<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine {

	use pocketmine\utils\Git;
	use pocketmine\utils\MainLogger;
	use pocketmine\utils\ServerKiller;
	use pocketmine\utils\Terminal;
	use pocketmine\utils\Timezone;
	use pocketmine\utils\Utils;
	use pocketmine\utils\VersionString;
	use pocketmine\wizard\SetupWizard;

	require_once __DIR__ . '/VersionInfo.php';

	const MIN_PHP_VERSION = "7.2.0";

	/**
	 * @param string $message
	 * @return void
	 */
	function critical_error($message){
		echo "[ERROR] $message" . PHP_EOL;
	}

	/*
	 * Startup code. Do not look at it, it may harm you.
	 * This is the only non-class based file on this project.
	 * Enjoy it as much as I did writing it. I don't want to do it again.
	 */

	/**
	 * @return string[]
	 */
	function check_platform_dependencies(){
		if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
			//If PHP version isn't high enough, anything below might break, so don't bother checking it.
			return [
				"PHP >= " . MIN_PHP_VERSION . " is required, but you have PHP " . PHP_VERSION . "."
			];
		}

		$messages = [];

		if(PHP_INT_SIZE < 8){
			$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.";
		}

		if(php_sapi_name() !== "cli"){
			$messages[] = "Only PHP CLI is supported.";
		}

		$extensions = [
			"bcmath" => "BC Math",
			"curl" => "cURL",
			"ctype" => "ctype",
			"date" => "Date",
			"hash" => "Hash",
			"json" => "JSON",
			"mbstring" => "Multibyte String",
			"openssl" => "OpenSSL",
			"pcre" => "PCRE",
			"phar" => "Phar",
			"pthreads" => "pthreads",
			"reflection" => "Reflection",
			"sockets" => "Sockets",
			"spl" => "SPL",
			"yaml" => "YAML",
			"zip" => "Zip",
			"zlib" => "Zlib"
		];

		foreach($extensions as $ext => $name){
			if(!extension_loaded($ext)){
				$messages[] = "Unable to find the $name ($ext) extension.";
			}
		}

		if(extension_loaded("pthreads")){
			$pthreads_version = phpversion("pthreads");
			if(substr_count($pthreads_version, ".") < 2){
				$pthreads_version = "0.$pthreads_version";
			}
			if(version_compare($pthreads_version, "3.2.0") < 0){
				$messages[] = "pthreads >= 3.2.0 is required, while you have $pthreads_version.";
			}
		}

		if(extension_loaded("leveldb")){
			$leveldb_version = phpversion("leveldb");
			if(version_compare($leveldb_version, "0.2.1") < 0){
				$messages[] = "php-leveldb >= 0.2.1 is required, while you have $leveldb_version.";
			}
		}

		if(extension_loaded("pocketmine")){
			$messages[] = "The native PocketMine extension is no longer supported.";
		}

		return $messages;
	}

	/**
	 * @param \Logger $logger
	 * @return void
	 */
	function emit_performance_warnings(\Logger $logger){
		if(extension_loaded("xdebug")){
			$logger->warning("Xdebug extension is enabled. This has a major impact on performance.");
		}
		if(!extension_loaded("pocketmine_chunkutils")){
			$logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance.");
		}
		if(((int) ini_get('zend.assertions')) !== -1){
			$logger->warning("Debugging assertions are enabled. This may degrade performance. To disable them, set `zend.assertions = -1` in php.ini.");
		}
		if(\Phar::running(true) === ""){
			$logger->warning("Non-packaged installation detected. This will degrade autoloading speed and make startup times longer.");
		}
	}

	/**
	 * @return void
	 */
	function set_ini_entries(){
		ini_set("allow_url_fopen", '1');
		ini_set("display_errors", '1');
		ini_set("display_startup_errors", '1');
		ini_set("default_charset", "utf-8");
		ini_set('assert.exception', '1');
	}

	/**
	 * @return void
	 */
	function server(){
		if(count($messages = check_platform_dependencies()) > 0){
			echo PHP_EOL;
			$binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
			critical_error("Selected PHP binary ($binary) does not satisfy some requirements.");
			foreach($messages as $m){
				echo " - $m" . PHP_EOL;
			}
			critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
			echo PHP_EOL;
			exit(1);
		}
		unset($messages);

		error_reporting(-1);
		set_ini_entries();

		$opts = getopt("", ["bootstrap:"]);
		if(isset($opts["bootstrap"])){
			$bootstrap = ($real = realpath($opts["bootstrap"])) !== false ? $real : $opts["bootstrap"];
		}else{
			$bootstrap = dirname(__FILE__, 3) . '/vendor/autoload.php';
		}
		define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);

		if(\pocketmine\COMPOSER_AUTOLOADER_PATH !== false and is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
			require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
		}else{
			critical_error("Composer autoloader not found at " . $bootstrap);
			critical_error("Please install/update Composer dependencies or use provided builds.");
			exit(1);
		}

		set_error_handler([Utils::class, 'errorExceptionHandler']);

		$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
		define('pocketmine\VERSION', $version->getFullVersion(true));

		$gitHash = str_repeat("00", 20);

		if(\Phar::running(true) === ""){
			$gitHash = Git::getRepositoryStatePretty(\pocketmine\PATH);
		}else{
			$phar = new \Phar(\Phar::running(false));
			$meta = $phar->getMetadata();
			if(isset($meta["git"])){
				$gitHash = $meta["git"];
			}
		}

		define('pocketmine\GIT_COMMIT', $gitHash);

		$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);

		define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR);
		define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);

		if(!file_exists(\pocketmine\DATA)){
			mkdir(\pocketmine\DATA, 0777, true);
		}

		define('pocketmine\LOCK_FILE', fopen(\pocketmine\DATA . 'server.lock', "a+b"));
		if(!flock(\pocketmine\LOCK_FILE, LOCK_EX | LOCK_NB)){
			//wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the
			//other server wrote its PID and released exclusive lock before we get our lock
			flock(\pocketmine\LOCK_FILE, LOCK_SH);
			$pid = stream_get_contents(\pocketmine\LOCK_FILE);
			critical_error("Another " . \pocketmine\NAME . " instance (PID $pid) is already using this folder (" . realpath(\pocketmine\DATA) . ").");
			critical_error("Please stop the other server first before running a new one.");
			exit(1);
		}
		ftruncate(\pocketmine\LOCK_FILE, 0);
		fwrite(\pocketmine\LOCK_FILE, (string) getmypid());
		fflush(\pocketmine\LOCK_FILE);
		flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading

		//Logger has a dependency on timezone
		$tzError = Timezone::init();

		if(isset($opts["enable-ansi"])){
			Terminal::init(true);
		}elseif(isset($opts["disable-ansi"])){
			Terminal::init(false);
		}else{
			Terminal::init();
		}

		$logger = new MainLogger(\pocketmine\DATA . "server.log");
		$logger->registerStatic();

		foreach($tzError as $e){
			$logger->warning($e);
		}
		unset($tzError);

		emit_performance_warnings($logger);

		$exitCode = 0;
		do{
			if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){
				$installer = new SetupWizard();
				if(!$installer->run()){
					$exitCode = -1;
					break;
				}
			}

			//TODO: move this to a Server field
			define('pocketmine\START_TIME', microtime(true));

			/*
			 * We now use the Composer autoloader, but this autoloader is still for loading plugins.
			 */
			$autoloader = new \BaseClassLoader();
			$autoloader->register(false);

			new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);

			$logger->info("Stopping other threads");

			$killer = new ServerKiller(8);
			$killer->start(PTHREADS_INHERIT_NONE);
			usleep(10000); //Fixes ServerKiller not being able to start on single-core machines

			if(ThreadManager::getInstance()->stopAll() > 0){
				$logger->debug("Some threads could not be stopped, performing a force-kill");
				Utils::kill(getmypid());
			}
		}while(false);

		$logger->shutdown();
		$logger->join();

		echo Terminal::$FORMAT_RESET . PHP_EOL;

		exit($exitCode);
	}

	if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
		\pocketmine\server();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine;

// composer autoload doesn't use require_once and also pthreads can inherit things
// TODO: drop this file and use a final class with constants
if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
	return;
}
const _VERSION_INFO_INCLUDED = true;

const NAME = "PocketMine-MP";
const BASE_VERSION = "3.11.6";
const IS_DEVELOPMENT_BUILD = false;
const BUILD_NUMBER = 1791;
<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInit2465bc1320a965a378e5f39bc0181113::getLoader();
<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInit2465bc1320a965a378e5f39bc0181113
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInit2465bc1320a965a378e5f39bc0181113', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInit2465bc1320a965a378e5f39bc0181113', 'loadClassLoader'));

        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
        if ($useStaticLoader) {
            require_once __DIR__ . '/autoload_static.php';

            call_user_func(\Composer\Autoload\ComposerStaticInit2465bc1320a965a378e5f39bc0181113::getInitializer($loader));
        } else {
            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }

        $loader->setClassMapAuthoritative(true);
        $loader->register(true);

        if ($useStaticLoader) {
            $includeFiles = Composer\Autoload\ComposerStaticInit2465bc1320a965a378e5f39bc0181113::$files;
        } else {
            $includeFiles = require __DIR__ . '/autoload_files.php';
        }
        foreach ($includeFiles as $fileIdentifier => $file) {
            composerRequire2465bc1320a965a378e5f39bc0181113($fileIdentifier, $file);
        }

        return $loader;
    }
}

function composerRequire2465bc1320a965a378e5f39bc0181113($fileIdentifier, $file)
{
    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
        require $file;

        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
    }
}
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @see    http://www.php-fig.org/psr/psr-0/
 * @see    http://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    // PSR-4
    private $prefixLengthsPsr4 = array();
    private $prefixDirsPsr4 = array();
    private $fallbackDirsPsr4 = array();

    // PSR-0
    private $prefixesPsr0 = array();
    private $fallbackDirsPsr0 = array();

    private $useIncludePath = false;
    private $classMap = array();
    private $classMapAuthoritative = false;
    private $missingClasses = array();
    private $apcuPrefix;

    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', $this->prefixesPsr0);
        }

        return array();
    }

    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param array $classMap Class to filename map
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string       $prefix  The prefix
     * @param array|string $paths   The PSR-0 root directories
     * @param bool         $prepend Whether to prepend the directories
     */
    public function add($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            if ($prepend) {
                $this->fallbackDirsPsr0 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr0
                );
            } else {
                $this->fallbackDirsPsr0 = array_merge(
                    $this->fallbackDirsPsr0,
                    (array) $paths
                );
            }

            return;
        }

        $first = $prefix[0];
        if (!isset($this->prefixesPsr0[$first][$prefix])) {
            $this->prefixesPsr0[$first][$prefix] = (array) $paths;

            return;
        }
        if ($prepend) {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                (array) $paths,
                $this->prefixesPsr0[$first][$prefix]
            );
        } else {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $this->prefixesPsr0[$first][$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string       $prefix  The prefix/namespace, with trailing '\\'
     * @param array|string $paths   The PSR-4 base directories
     * @param bool         $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    (array) $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        } elseif ($prepend) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                (array) $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string       $prefix The prefix
     * @param array|string $paths  The PSR-0 base directories
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string       $prefix The prefix/namespace, with trailing '\\'
     * @param array|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     */
    public function setPsr4($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr4 = (array) $paths;
        } else {
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
    }

    /**
     * Unregisters this instance as an autoloader.
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return bool|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            includeFile($file);

            return true;
        }
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            $subPath = $class;
            while (false !== $lastPos = strrpos($subPath, '\\')) {
                $subPath = substr($subPath, 0, $lastPos);
                $search = $subPath . '\\';
                if (isset($this->prefixDirsPsr4[$search])) {
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
                        if (file_exists($file = $dir . $pathEnd)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
        }

        if (isset($this->prefixesPsr0[$first])) {
            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }
}

/**
 * Scope isolated include.
 *
 * Prevents access to $this/self from included files.
 */
function includeFile($file)
{
    include $file;
}
<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInit2465bc1320a965a378e5f39bc0181113
{
    public static $files = array (
        '44f761fde233c98b53686bd6223104dd' => __DIR__ . '/../..' . '/src/pocketmine/CoreConstants.php',
        '9c3c6f7f4a17396c3ff535f7d7c38ad4' => __DIR__ . '/../..' . '/src/pocketmine/GlobalConstants.php',
        '89d5de50ff2daa656af29fba38fbd9af' => __DIR__ . '/../..' . '/src/pocketmine/VersionInfo.php',
    );

    public static $prefixLengthsPsr4 = array (
        'r' => 
        array (
            'raklib\\' => 7,
        ),
        'p' => 
        array (
            'pocketmine\\utils\\' => 17,
            'pocketmine\\snooze\\' => 18,
            'pocketmine\\nbt\\' => 15,
            'pocketmine\\math\\' => 16,
        ),
        'D' => 
        array (
            'DaveRandom\\CallbackValidator\\' => 29,
        ),
        'A' => 
        array (
            'Ahc\\Json\\' => 9,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'raklib\\' => 
        array (
            0 => __DIR__ . '/..' . '/pocketmine/raklib/src',
        ),
        'pocketmine\\utils\\' => 
        array (
            0 => __DIR__ . '/..' . '/pocketmine/binaryutils/src',
        ),
        'pocketmine\\snooze\\' => 
        array (
            0 => __DIR__ . '/..' . '/pocketmine/snooze/src',
        ),
        'pocketmine\\nbt\\' => 
        array (
            0 => __DIR__ . '/..' . '/pocketmine/nbt/src',
        ),
        'pocketmine\\math\\' => 
        array (
            0 => __DIR__ . '/..' . '/pocketmine/math/src',
        ),
        'DaveRandom\\CallbackValidator\\' => 
        array (
            0 => __DIR__ . '/..' . '/daverandom/callback-validator/src',
        ),
        'Ahc\\Json\\' => 
        array (
            0 => __DIR__ . '/..' . '/adhocore/json-comment/src',
        ),
    );

    public static $fallbackDirsPsr4 = array (
        0 => __DIR__ . '/../..' . '/src',
    );

    public static $classMap = array (
        'Ahc\\Json\\Comment' => __DIR__ . '/..' . '/adhocore/json-comment/src/Comment.php',
        'ArrayOutOfBoundsException' => __DIR__ . '/..' . '/pocketmine/spl/src/ArrayOutOfBoundsException.php',
        'AttachableLogger' => __DIR__ . '/..' . '/pocketmine/log/src/AttachableLogger.php',
        'AttachableThreadedLogger' => __DIR__ . '/..' . '/pocketmine/log/src/AttachableThreadedLogger.php',
        'BaseClassLoader' => __DIR__ . '/..' . '/pocketmine/classloader/src/BaseClassLoader.php',
        'ClassCastException' => __DIR__ . '/..' . '/pocketmine/spl/src/ClassCastException.php',
        'ClassLoader' => __DIR__ . '/..' . '/pocketmine/classloader/src/ClassLoader.php',
        'ClassNotFoundException' => __DIR__ . '/..' . '/pocketmine/spl/src/ClassNotFoundException.php',
        'DaveRandom\\CallbackValidator\\BuiltInTypes' => __DIR__ . '/..' . '/daverandom/callback-validator/src/BuiltInTypes.php',
        'DaveRandom\\CallbackValidator\\CallbackType' => __DIR__ . '/..' . '/daverandom/callback-validator/src/CallbackType.php',
        'DaveRandom\\CallbackValidator\\InvalidCallbackException' => __DIR__ . '/..' . '/daverandom/callback-validator/src/InvalidCallbackException.php',
        'DaveRandom\\CallbackValidator\\MatchTester' => __DIR__ . '/..' . '/daverandom/callback-validator/src/MatchTester.php',
        'DaveRandom\\CallbackValidator\\ParameterType' => __DIR__ . '/..' . '/daverandom/callback-validator/src/ParameterType.php',
        'DaveRandom\\CallbackValidator\\ReturnType' => __DIR__ . '/..' . '/daverandom/callback-validator/src/ReturnType.php',
        'DaveRandom\\CallbackValidator\\Type' => __DIR__ . '/..' . '/daverandom/callback-validator/src/Type.php',
        'InvalidArgumentCountException' => __DIR__ . '/..' . '/pocketmine/spl/src/InvalidArgumentCountException.php',
        'InvalidKeyException' => __DIR__ . '/..' . '/pocketmine/spl/src/InvalidKeyException.php',
        'InvalidStateException' => __DIR__ . '/..' . '/pocketmine/spl/src/InvalidStateException.php',
        'LogLevel' => __DIR__ . '/..' . '/pocketmine/log/src/LogLevel.php',
        'Logger' => __DIR__ . '/..' . '/pocketmine/log/src/Logger.php',
        'LoggerAttachment' => __DIR__ . '/..' . '/pocketmine/log/src/LoggerAttachment.php',
        'SplFixedByteArray' => __DIR__ . '/..' . '/pocketmine/spl/src/SplFixedByteArray.php',
        'StringOutOfBoundsException' => __DIR__ . '/..' . '/pocketmine/spl/src/StringOutOfBoundsException.php',
        'ThreadException' => __DIR__ . '/..' . '/pocketmine/spl/src/ThreadException.php',
        'ThreadedLogger' => __DIR__ . '/..' . '/pocketmine/log/src/ThreadedLogger.php',
        'ThreadedLoggerAttachment' => __DIR__ . '/..' . '/pocketmine/log/src/ThreadedLoggerAttachment.php',
        'UndefinedConstantException' => __DIR__ . '/..' . '/pocketmine/spl/src/UndefinedConstantException.php',
        'UndefinedPropertyException' => __DIR__ . '/..' . '/pocketmine/spl/src/UndefinedPropertyException.php',
        'UndefinedVariableException' => __DIR__ . '/..' . '/pocketmine/spl/src/UndefinedVariableException.php',
        'pocketmine\\Achievement' => __DIR__ . '/../..' . '/src/pocketmine/Achievement.php',
        'pocketmine\\Collectable' => __DIR__ . '/../..' . '/src/pocketmine/Collectable.php',
        'pocketmine\\CrashDump' => __DIR__ . '/../..' . '/src/pocketmine/CrashDump.php',
        'pocketmine\\IPlayer' => __DIR__ . '/../..' . '/src/pocketmine/IPlayer.php',
        'pocketmine\\MemoryManager' => __DIR__ . '/../..' . '/src/pocketmine/MemoryManager.php',
        'pocketmine\\OfflinePlayer' => __DIR__ . '/../..' . '/src/pocketmine/OfflinePlayer.php',
        'pocketmine\\Player' => __DIR__ . '/../..' . '/src/pocketmine/Player.php',
        'pocketmine\\Server' => __DIR__ . '/../..' . '/src/pocketmine/Server.php',
        'pocketmine\\Thread' => __DIR__ . '/../..' . '/src/pocketmine/Thread.php',
        'pocketmine\\ThreadManager' => __DIR__ . '/../..' . '/src/pocketmine/ThreadManager.php',
        'pocketmine\\Worker' => __DIR__ . '/../..' . '/src/pocketmine/Worker.php',
        'pocketmine\\block\\ActivatorRail' => __DIR__ . '/../..' . '/src/pocketmine/block/ActivatorRail.php',
        'pocketmine\\block\\Air' => __DIR__ . '/../..' . '/src/pocketmine/block/Air.php',
        'pocketmine\\block\\Anvil' => __DIR__ . '/../..' . '/src/pocketmine/block/Anvil.php',
        'pocketmine\\block\\BaseRail' => __DIR__ . '/../..' . '/src/pocketmine/block/BaseRail.php',
        'pocketmine\\block\\Bed' => __DIR__ . '/../..' . '/src/pocketmine/block/Bed.php',
        'pocketmine\\block\\Bedrock' => __DIR__ . '/../..' . '/src/pocketmine/block/Bedrock.php',
        'pocketmine\\block\\Beetroot' => __DIR__ . '/../..' . '/src/pocketmine/block/Beetroot.php',
        'pocketmine\\block\\Block' => __DIR__ . '/../..' . '/src/pocketmine/block/Block.php',
        'pocketmine\\block\\BlockFactory' => __DIR__ . '/../..' . '/src/pocketmine/block/BlockFactory.php',
        'pocketmine\\block\\BlockIds' => __DIR__ . '/../..' . '/src/pocketmine/block/BlockIds.php',
        'pocketmine\\block\\BlockToolType' => __DIR__ . '/../..' . '/src/pocketmine/block/BlockToolType.php',
        'pocketmine\\block\\BoneBlock' => __DIR__ . '/../..' . '/src/pocketmine/block/BoneBlock.php',
        'pocketmine\\block\\Bookshelf' => __DIR__ . '/../..' . '/src/pocketmine/block/Bookshelf.php',
        'pocketmine\\block\\BrewingStand' => __DIR__ . '/../..' . '/src/pocketmine/block/BrewingStand.php',
        'pocketmine\\block\\BrickStairs' => __DIR__ . '/../..' . '/src/pocketmine/block/BrickStairs.php',
        'pocketmine\\block\\Bricks' => __DIR__ . '/../..' . '/src/pocketmine/block/Bricks.php',
        'pocketmine\\block\\BrownMushroom' => __DIR__ . '/../..' . '/src/pocketmine/block/BrownMushroom.php',
        'pocketmine\\block\\BrownMushroomBlock' => __DIR__ . '/../..' . '/src/pocketmine/block/BrownMushroomBlock.php',
        'pocketmine\\block\\BurningFurnace' => __DIR__ . '/../..' . '/src/pocketmine/block/BurningFurnace.php',
        'pocketmine\\block\\Button' => __DIR__ . '/../..' . '/src/pocketmine/block/Button.php',
        'pocketmine\\block\\Cactus' => __DIR__ . '/../..' . '/src/pocketmine/block/Cactus.php',
        'pocketmine\\block\\Cake' => __DIR__ . '/../..' . '/src/pocketmine/block/Cake.php',
        'pocketmine\\block\\Carpet' => __DIR__ . '/../..' . '/src/pocketmine/block/Carpet.php',
        'pocketmine\\block\\Carrot' => __DIR__ . '/../..' . '/src/pocketmine/block/Carrot.php',
        'pocketmine\\block\\Chest' => __DIR__ . '/../..' . '/src/pocketmine/block/Chest.php',
        'pocketmine\\block\\Clay' => __DIR__ . '/../..' . '/src/pocketmine/block/Clay.php',
        'pocketmine\\block\\Coal' => __DIR__ . '/../..' . '/src/pocketmine/block/Coal.php',
        'pocketmine\\block\\CoalOre' => __DIR__ . '/../..' . '/src/pocketmine/block/CoalOre.php',
        'pocketmine\\block\\Cobblestone' => __DIR__ . '/../..' . '/src/pocketmine/block/Cobblestone.php',
        'pocketmine\\block\\CobblestoneStairs' => __DIR__ . '/../..' . '/src/pocketmine/block/CobblestoneStairs.php',
        'pocketmine\\block\\CobblestoneWall' => __DIR__ . '/../..' . '/src/pocketmine/block/CobblestoneWall.php',
        'pocketmine\\block\\Cobweb' => __DIR__ . '/../..' . '/src/pocketmine/block/Cobweb.php',
        'pocketmine\\block\\CocoaBlock' => __DIR__ . '/../..' . '/src/pocketmine/block/CocoaBlock.php',
        'pocketmine\\block\\Concrete' => __DIR__ . '/../..' . '/src/pocketmine/block/Concrete.php',
        'pocketmine\\block\\ConcretePowder' => __DIR__ . '/../..' . '/src/pocketmine/block/ConcretePowder.php',
        'pocketmine\\block\\CraftingTable' => __DIR__ . '/../..' . '/src/pocketmine/block/CraftingTable.php',
        'pocketmine\\block\\Crops' => __DIR__ . '/../..' . '/src/pocketmine/block/Crops.php',
        'pocketmine\\block\\Dandelion' => __DIR__ . '/../..' . '/src/pocketmine/block/Dandelion.php',
        'pocketmine\\block\\DaylightSensor' => __DIR__ . '/../..' . '/src/pocketmine/block/DaylightSensor.php',
        'pocketmine\\block\\DeadBush' => __DIR__ . '/../..' . '/src/pocketmine/block/DeadBush.php',
        'pocketmine\\block\\DetectorRail' => __DIR__ . '/../..' . '/src/pocketmine/block/DetectorRail.php',
        'pocketmine\\block\\Diamond' => __DIR__ . '/../..' . '/src/pocketmine/block/Diamond.php',
        'pocketmine\\block\\DiamondOre' => __DIR__ . '/../..' . '/src/pocketmine/block/DiamondOre.php',
        'pocketmine\\block\\Dirt' => __DIR__ . '/../..' . '/src/pocketmine/block/Dirt.php',
        'pocketmine\\block\\Door' => __DIR__ . '/../..' . '/src/pocketmine/block/Door.php',
        'pocketmine\\block\\DoublePlant' => __DIR__ . '/../..' . '/src/pocketmine/block/DoublePlant.php',
        'pocketmine\\block\\DoubleSlab' => __DIR__ . '/../..' . '/src/pocketmine/block/DoubleSlab.php',
        'pocketmine\\block\\DoubleStoneSlab' => __DIR__ . '/../..' . '/src/pocketmine/block/DoubleStoneSlab.php',
        'pocketmine\\block\\DoubleStoneSlab2' => __DIR__ . '/../..' . '/src/pocketmine/block/DoubleStoneSlab2.php',
        'pocketmine\\block\\DoubleWoodenSlab' => __DIR__ . '/../..' . '/src/pocketmine/block/DoubleWoodenSlab.php',
        'pocketmine\\block\\Emerald' => __DIR__ . '/../..' . '/src/pocketmine/block/Emerald.php',
        'pocketmine\\block\\EmeraldOre' => __DIR__ . '/../..' . '/src/pocketmine/block/EmeraldOre.php',
        'pocketmine\\block\\EnchantingTable' => __DIR__ . '/../..' . '/src/pocketmine/block/EnchantingTable.php',
        'pocketmine\\block\\EndPortalFrame' => __DIR__ . '/../..' . '/src/pocketmine/block/EndPortalFrame.php',
        'pocketmine\\block\\EndRod' => __DIR__ . '/../..' . '/src/pocketmine/block/EndRod.php',
        'pocketmine\\block\\EndStone' => __DIR__ . '/../..' . '/src/pocketmine/block/EndStone.php',
        'pocketmine\\block\\EndStoneBricks' => __DIR__ . '/../..' . '/src/pocketmine/block/EndStoneBricks.php',
        'pocketmine\\block\\EnderChest' => __DIR__ . '/../..' . '/src/pocketmine/block/EnderChest.php',
        'pocketmine\\block\\Fallable' => __DIR__ . '/../..' . '/src/pocketmine/block/Fallable.php',
        'pocketmine\\block\\Farmland' => __DIR__ . '/../..' . '/src/pocketmine/block/Farmland.php',
        'pocketmine\\block\\Fence' => __DIR__ . '/../..' . '/src/pocketmine/block/Fence.php',
        'pocketmine\\block\\FenceGate' => __DIR__ . '/../..' . '/src/pocketmine/block/FenceGate.php',
        'pocketmine\\block\\Fire' => __DIR__ . '/../..' . '/src/pocketmine/block/Fire.php',
        'pocketmine\\block\\Flowable' => __DIR__ . '/../..' . '/src/pocketmine/block/Flowable.php',
        'pocketmine\\block\\Flower' => __DIR__ . '/../..' . '/src/pocketmine/block/Flower.php',
        'pocketmine\\block\\FlowerPot' => __DIR__ . '/../..' . '/src/pocketmine/block/FlowerPot.php',
        'pocketmine\\block\\Furnace' => __DIR__ . '/../..' . '/src/pocketmine/block/Furnace.php',
        'pocketmine\\block\\Glass' => __DIR__ . '/../..' . '/src/pocketmine/block/Glass.php',
        'pocketmine\\block\\GlassPane' => __DIR__ . '/../..' . '/src/pocketmine/block/GlassPane.php',
        'pocketmine\\block\\GlazedTerracotta' => __DIR__ . '/../..' . '/src/pocketmine/block/GlazedTerracotta.php',
        'pocketmine\\block\\GlowingObsidian' => __DIR__ . '/../..' . '/src/pocketmine/block/GlowingObsidian.php',
        'pocketmine\\block\\GlowingRedstoneOre' => __DIR__ . '/../..' . '/src/pocketmine/block/GlowingRedstoneOre.php',
        'pocketmine\\block\\Glowstone' => __DIR__ . '/../..' . '/src/pocketmine/block/Glowstone.php',
        'pocketmine\\block\\Gold' => __DIR__ . '/../..' . '/src/pocketmine/block/Gold.php',
        'pocketmine\\block\\GoldOre' => __DIR__ . '/../..' . '/src/pocketmine/block/GoldOre.php',
        'pocketmine\\block\\Grass' => __DIR__ . '/../..' . '/src/pocketmine/block/Grass.php',
        'pocketmine\\block\\GrassPath' => __DIR__ . '/../..' . '/src/pocketmine/block/GrassPath.php',
        'pocketmine\\block\\Gravel' => __DIR__ . '/../..' . '/src/pocketmine/block/Gravel.php',
        'pocketmine\\block\\HardenedClay' => __DIR__ . '/../..' . '/src/pocketmine/block/HardenedClay.php',
        'pocketmine\\block\\HayBale' => __DIR__ . '/../..' . '/src/pocketmine/block/HayBale.php',
        'pocketmine\\block\\Ice' => __DIR__ . '/../..' . '/src/pocketmine/block/Ice.php',
        'pocketmine\\block\\InfoUpdate' => __DIR__ . '/../..' . '/src/pocketmine/block/InfoUpdate.php',
        'pocketmine\\block\\InvisibleBedrock' => __DIR__ . '/../..' . '/src/pocketmine/block/InvisibleBedrock.php',
        'pocketmine\\block\\Iron' => __DIR__ . '/../..' . '/src/pocketmine/block/Iron.php',
        'pocketmine\\block\\IronBars' => __DIR__ . '/../..' . '/src/pocketmine/block/IronBars.php',
        'pocketmine\\block\\IronDoor' => __DIR__ . '/../..' . '/src/pocketmine/block/IronDoor.php',
        'pocketmine\\block\\IronOre' => __DIR__ . '/../..' . '/src/pocketmine/block/IronOre.php',
        'pocketmine\\block\\IronTrapdoor' => __DIR__ . '/../..' . '/src/pocketmine/block/IronTrapdoor.php',
        'pocketmine\\block\\ItemFrame' => __DIR__ . '/../..' . '/src/pocketmine/block/ItemFrame.php',
        'pocketmine\\block\\Ladder' => __DIR__ . '/../..' . '/src/pocketmine/block/Ladder.php',
        'pocketmine\\block\\Lapis' => __DIR__ . '/../..' . '/src/pocketmine/block/Lapis.php',
        'pocketmine\\block\\LapisOre' => __DIR__ . '/../..' . '/src/pocketmine/block/LapisOre.php',
        'pocketmine\\block\\Lava' => __DIR__ . '/../..' . '/src/pocketmine/block/Lava.php',
        'pocketmine\\block\\Leaves' => __DIR__ . '/../..' . '/src/pocketmine/block/Leaves.php',
        'pocketmine\\block\\Leaves2' => __DIR__ . '/../..' . '/src/pocketmine/block/Leaves2.php',
        'pocketmine\\block\\Lever' => __DIR__ . '/../..' . '/src/pocketmine/block/Lever.php',
        'pocketmine\\block\\Liquid' => __DIR__ . '/../..' . '/src/pocketmine/block/Liquid.php',
        'pocketmine\\block\\LitPumpkin' => __DIR__ . '/../..' . '/src/pocketmine/block/LitPumpkin.php',
        'pocketmine\\block\\LitRedstoneLamp' => __DIR__ . '/../..' . '/src/pocketmine/block/LitRedstoneLamp.php',
        'pocketmine\\block\\Magma' => __DIR__ . '/../..' . '/src/pocketmine/block/Magma.php',
        'pocketmine\\block\\Melon' => __DIR__ . '/../..' . '/src/pocketmine/block/Melon.php',
        'pocketmine\\block\\MelonStem' => __DIR__ . '/../..' . '/src/pocketmine/block/MelonStem.php',
        'pocketmine\\block\\MonsterSpawner' => __DIR__ . '/../..' . '/src/pocketmine/block/MonsterSpawner.php',
        'pocketmine\\block\\MossyCobblestone' => __DIR__ . '/../..' . '/src/pocketmine/block/MossyCobblestone.php',
        'pocketmine\\block\\Mycelium' => __DIR__ . '/../..' . '/src/pocketmine/block/Mycelium.php',
        'pocketmine\\block\\NetherBrick' => __DIR__ . '/../..' . '/src/pocketmine/block/NetherBrick.php',
        'pocketmine\\block\\NetherBrickFence' => __DIR__ . '/../..' . '/src/pocketmine/block/NetherBrickFence.php',
        'pocketmine\\block\\NetherBrickStairs' => __DIR__ . '/../..' . '/src/pocketmine/block/NetherBrickStairs.php',
        'pocketmine\\block\\NetherQuartzOre' => __DIR__ . '/../..' . '/src/pocketmine/block/NetherQuartzOre.php',
        'pocketmine\\block\\NetherReactor' => __DIR__ . '/../..' . '/src/pocketmine/block/NetherReactor.php',
        'pocketmine\\block\\NetherWartBlock' => __DIR__ . '/../..' . '/src/pocketmine/block/NetherWartBlock.php',
        'pocketmine\\block\\NetherWartPlant' => __DIR__ . '/../..' . '/src/pocketmine/block/NetherWartPlant.php',
        'pocketmine\\block\\Netherrack' => __DIR__ . '/../..' . '/src/pocketmine/block/Netherrack.php',
        'pocketmine\\block\\NoteBlock' => __DIR__ . '/../..' . '/src/pocketmine/block/NoteBlock.php',
        'pocketmine\\block\\Obsidian' => __DIR__ . '/../..' . '/src/pocketmine/block/Obsidian.php',
        'pocketmine\\block\\PackedIce' => __DIR__ . '/../..' . '/src/pocketmine/block/PackedIce.php',
        'pocketmine\\block\\Planks' => __DIR__ . '/../..' . '/src/pocketmine/block/Planks.php',
        'pocketmine\\block\\Podzol' => __DIR__ . '/../..' . '/src/pocketmine/block/Podzol.php',
        'pocketmine\\block\\Potato' => __DIR__ . '/../..' . '/src/pocketmine/block/Potato.php',
        'pocketmine\\block\\PoweredRail' => __DIR__ . '/../..' . '/src/pocketmine/block/PoweredRail.php',
        'pocketmine\\block\\Prismarine' => __DIR__ . '/../..' . '/src/pocketmine/block/Prismarine.php',
        'pocketmine\\block\\Pumpkin' => __DIR__ . '/../..' . '/src/pocketmine/block/Pumpkin.php',
        'pocketmine\\block\\PumpkinStem' => __DIR__ . '/../..' . '/src/pocketmine/block/PumpkinStem.php',
        'pocketmine\\block\\Purpur' => __DIR__ . '/../..' . '/src/pocketmine/block/Purpur.php',
        'pocketmine\\block\\PurpurStairs' => __DIR__ . '/../..' . '/src/pocketmine/block/PurpurStairs.php',
        'pocketmine\\block\\Quartz' => __DIR__ . '/../..' . '/src/pocketmine/block/Quartz.php',
        'pocketmine\\block\\QuartzStairs' => __DIR__ . '/../..' . '/src/pocketmine/block/QuartzStairs.php',
        'pocketmine\\block\\Rail' => __DIR__ . '/../..' . '/src/pocketmine/block/Rail.php',
        'pocketmine\\block\\RedMushroom' => __DIR__ . '/../..' . '/src/pocketmine/block/RedMushroom.php',
        'pocketmine\\block\\RedMushroomBlock' => __DIR__ . '/../..' . '/src/pocketmine/block/RedMushroomBlock.php',
        'pocketmine\\block\\RedSandstone' => __DIR__ . '/../..' . '/src/pocketmine/block/RedSandstone.php',
        'pocketmine\\block\\RedSandstoneStairs' => __DIR__ . '/../..' . '/src/pocketmine/block/RedSandstoneStairs.php',
        'pocketmine\\block\\Redstone' => __DIR__ . '/../..' . '/src/pocketmine/block/Redstone.php',
        'pocketmine\\block\\RedstoneLamp' => __DIR__ . '/../..' . '/src/pocketmine/block/RedstoneLamp.php',
        'pocketmine\\block\\RedstoneOre' => __DIR__ . '/../..' . '/src/pocketmine/block/RedstoneOre.php',
        'pocketmine\\block\\RedstoneRail' => __DIR__ . '/../..' . '/src/pocketmine/block/RedstoneRail.php',
        'pocketmine\\block\\RedstoneTorch' => __DIR__ . '/../..' . '/src/pocketmine/block/RedstoneTorch.php',
        'pocketmine\\block\\RedstoneTorchUnlit' => __DIR__ . '/../..' . '/src/pocketmine/block/RedstoneTorchUnlit.php',
        'pocketmine\\block\\Reserved6' => __DIR__ . '/../..' . '/src/pocketmine/block/Reserved6.php',
        'pocketmine\\block\\Sand' => __DIR__ . '/../..' . '/src/pocketmine/block/Sand.php',
        'pocketmine\\block\\Sandstone' => __DIR__ . '/../..' . '/src/pocketmine/block/Sandstone.php',
        'pocketmine\\block\\SandstoneStairs' => __DIR__ . '/../..' . '/src/pocketmine/block/SandstoneStairs.php',
        'pocketmine\\block\\Sapling' => __DIR__ . '/../..' . '/src/pocketmine/block/Sapling.php',
        'pocketmine\\block\\SeaLantern' => __DIR__ . '/../..' . '/src/pocketmine/block/SeaLantern.php',
        'pocketmine\\block\\SignPost' => __DIR__ . '/../..' . '/src/pocketmine/block/SignPost.php',
        'pocketmine\\block\\Skull' => __DIR__ . '/../..' . '/src/pocketmine/block/Skull.php',
        'pocketmine\\block\\Slab' => __DIR__ . '/../..' . '/src/pocketmine/block/Slab.php',
        'pocketmine\\block\\Snow' => __DIR__ . '/../..' . '/src/pocketmine/block/Snow.php',
        'pocketmine\\block\\SnowLayer' => __DIR__ . '/../..' . '/src/pocketmine/block/SnowLayer.php',
        'pocketmine\\block\\Solid' => __DIR__ . '/../..' . '/src/pocketmine/block/Solid.php',
        'pocketmine\\block\\SoulSand' => __DIR__ . '/../..' . '/src/pocketmine/block/SoulSand.php',
        'pocketmine\\block\\Sponge' => __DIR__ . '/../..' . '/src/pocketmine/block/Sponge.php',
        'pocketmine\\block\\StainedClay' => __DIR__ . '/../..' . '/src/pocketmine/block/StainedClay.php',
        'pocketmine\\block\\StainedGlass' => __DIR__ . '/../..' . '/src/pocketmine/block/StainedGlass.php',
        'pocketmine\\block\\StainedGlassPane' => __DIR__ . '/../..' . '/src/pocketmine/block/StainedGlassPane.php',
        'pocketmine\\block\\Stair' => __DIR__ . '/../..' . '/src/pocketmine/block/Stair.php',
        'pocketmine\\block\\StandingBanner' => __DIR__ . '/../..' . '/src/pocketmine/block/StandingBanner.php',
        'pocketmine\\block\\StillLava' => __DIR__ . '/../..' . '/src/pocketmine/block/StillLava.php',
        'pocketmine\\block\\StillWater' => __DIR__ . '/../..' . '/src/pocketmine/block/StillWater.php',
        'pocketmine\\block\\Stone' => __DIR__ . '/../..' . '/src/pocketmine/block/Stone.php',
        'pocketmine\\block\\StoneBrickStairs' => __DIR__ . '/../..' . '/src/pocketmine/block/StoneBrickStairs.php',
        'pocketmine\\block\\StoneBricks' => __DIR__ . '/../..' . '/src/pocketmine/block/StoneBricks.php',
        'pocketmine\\block\\StoneButton' => __DIR__ . '/../..' . '/src/pocketmine/block/StoneButton.php',
        'pocketmine\\block\\StonePressurePlate' => __DIR__ . '/../..' . '/src/pocketmine/block/StonePressurePlate.php',
        'pocketmine\\block\\StoneSlab' => __DIR__ . '/../..' . '/src/pocketmine/block/StoneSlab.php',
        'pocketmine\\block\\StoneSlab2' => __DIR__ . '/../..' . '/src/pocketmine/block/StoneSlab2.php',
        'pocketmine\\block\\Stonecutter' => __DIR__ . '/../..' . '/src/pocketmine/block/Stonecutter.php',
        'pocketmine\\block\\Sugarcane' => __DIR__ . '/../..' . '/src/pocketmine/block/Sugarcane.php',
        'pocketmine\\block\\TNT' => __DIR__ . '/../..' . '/src/pocketmine/block/TNT.php',
        'pocketmine\\block\\TallGrass' => __DIR__ . '/../..' . '/src/pocketmine/block/TallGrass.php',
        'pocketmine\\block\\Thin' => __DIR__ . '/../..' . '/src/pocketmine/block/Thin.php',
        'pocketmine\\block\\Torch' => __DIR__ . '/../..' . '/src/pocketmine/block/Torch.php',
        'pocketmine\\block\\Transparent' => __DIR__ . '/../..' . '/src/pocketmine/block/Transparent.php',
        'pocketmine\\block\\Trapdoor' => __DIR__ . '/../..' . '/src/pocketmine/block/Trapdoor.php',
        'pocketmine\\block\\TrappedChest' => __DIR__ . '/../..' . '/src/pocketmine/block/TrappedChest.php',
        'pocketmine\\block\\Tripwire' => __DIR__ . '/../..' . '/src/pocketmine/block/Tripwire.php',
        'pocketmine\\block\\TripwireHook' => __DIR__ . '/../..' . '/src/pocketmine/block/TripwireHook.php',
        'pocketmine\\block\\UnknownBlock' => __DIR__ . '/../..' . '/src/pocketmine/block/UnknownBlock.php',
        'pocketmine\\block\\Vine' => __DIR__ . '/../..' . '/src/pocketmine/block/Vine.php',
        'pocketmine\\block\\WallBanner' => __DIR__ . '/../..' . '/src/pocketmine/block/WallBanner.php',
        'pocketmine\\block\\WallSign' => __DIR__ . '/../..' . '/src/pocketmine/block/WallSign.php',
        'pocketmine\\block\\Water' => __DIR__ . '/../..' . '/src/pocketmine/block/Water.php',
        'pocketmine\\block\\WaterLily' => __DIR__ . '/../..' . '/src/pocketmine/block/WaterLily.php',
        'pocketmine\\block\\WeightedPressurePlateHeavy' => __DIR__ . '/../..' . '/src/pocketmine/block/WeightedPressurePlateHeavy.php',
        'pocketmine\\block\\WeightedPressurePlateLight' => __DIR__ . '/../..' . '/src/pocketmine/block/WeightedPressurePlateLight.php',
        'pocketmine\\block\\Wheat' => __DIR__ . '/../..' . '/src/pocketmine/block/Wheat.php',
        'pocketmine\\block\\Wood' => __DIR__ . '/../..' . '/src/pocketmine/block/Wood.php',
        'pocketmine\\block\\Wood2' => __DIR__ . '/../..' . '/src/pocketmine/block/Wood2.php',
        'pocketmine\\block\\WoodenButton' => __DIR__ . '/../..' . '/src/pocketmine/block/WoodenButton.php',
        'pocketmine\\block\\WoodenDoor' => __DIR__ . '/../..' . '/src/pocketmine/block/WoodenDoor.php',
        'pocketmine\\block\\WoodenFence' => __DIR__ . '/../..' . '/src/pocketmine/block/WoodenFence.php',
        'pocketmine\\block\\WoodenPressurePlate' => __DIR__ . '/../..' . '/src/pocketmine/block/WoodenPressurePlate.php',
        'pocketmine\\block\\WoodenSlab' => __DIR__ . '/../..' . '/src/pocketmine/block/WoodenSlab.php',
        'pocketmine\\block\\WoodenStairs' => __DIR__ . '/../..' . '/src/pocketmine/block/WoodenStairs.php',
        'pocketmine\\block\\Wool' => __DIR__ . '/../..' . '/src/pocketmine/block/Wool.php',
        'pocketmine\\block\\utils\\ColorBlockMetaHelper' => __DIR__ . '/../..' . '/src/pocketmine/block/utils/ColorBlockMetaHelper.php',
        'pocketmine\\block\\utils\\PillarRotationHelper' => __DIR__ . '/../..' . '/src/pocketmine/block/utils/PillarRotationHelper.php',
        'pocketmine\\command\\Command' => __DIR__ . '/../..' . '/src/pocketmine/command/Command.php',
        'pocketmine\\command\\CommandExecutor' => __DIR__ . '/../..' . '/src/pocketmine/command/CommandExecutor.php',
        'pocketmine\\command\\CommandMap' => __DIR__ . '/../..' . '/src/pocketmine/command/CommandMap.php',
        'pocketmine\\command\\CommandReader' => __DIR__ . '/../..' . '/src/pocketmine/command/CommandReader.php',
        'pocketmine\\command\\CommandSender' => __DIR__ . '/../..' . '/src/pocketmine/command/CommandSender.php',
        'pocketmine\\command\\ConsoleCommandSender' => __DIR__ . '/../..' . '/src/pocketmine/command/ConsoleCommandSender.php',
        'pocketmine\\command\\FormattedCommandAlias' => __DIR__ . '/../..' . '/src/pocketmine/command/FormattedCommandAlias.php',
        'pocketmine\\command\\PluginCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/PluginCommand.php',
        'pocketmine\\command\\PluginIdentifiableCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/PluginIdentifiableCommand.php',
        'pocketmine\\command\\RemoteConsoleCommandSender' => __DIR__ . '/../..' . '/src/pocketmine/command/RemoteConsoleCommandSender.php',
        'pocketmine\\command\\SimpleCommandMap' => __DIR__ . '/../..' . '/src/pocketmine/command/SimpleCommandMap.php',
        'pocketmine\\command\\defaults\\BanCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/BanCommand.php',
        'pocketmine\\command\\defaults\\BanIpCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/BanIpCommand.php',
        'pocketmine\\command\\defaults\\BanListCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/BanListCommand.php',
        'pocketmine\\command\\defaults\\DefaultGamemodeCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/DefaultGamemodeCommand.php',
        'pocketmine\\command\\defaults\\DeopCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/DeopCommand.php',
        'pocketmine\\command\\defaults\\DifficultyCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/DifficultyCommand.php',
        'pocketmine\\command\\defaults\\DumpMemoryCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/DumpMemoryCommand.php',
        'pocketmine\\command\\defaults\\EffectCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/EffectCommand.php',
        'pocketmine\\command\\defaults\\EnchantCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/EnchantCommand.php',
        'pocketmine\\command\\defaults\\GamemodeCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/GamemodeCommand.php',
        'pocketmine\\command\\defaults\\GarbageCollectorCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/GarbageCollectorCommand.php',
        'pocketmine\\command\\defaults\\GiveCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/GiveCommand.php',
        'pocketmine\\command\\defaults\\HelpCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/HelpCommand.php',
        'pocketmine\\command\\defaults\\KickCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/KickCommand.php',
        'pocketmine\\command\\defaults\\KillCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/KillCommand.php',
        'pocketmine\\command\\defaults\\ListCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/ListCommand.php',
        'pocketmine\\command\\defaults\\MeCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/MeCommand.php',
        'pocketmine\\command\\defaults\\OpCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/OpCommand.php',
        'pocketmine\\command\\defaults\\PardonCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/PardonCommand.php',
        'pocketmine\\command\\defaults\\PardonIpCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/PardonIpCommand.php',
        'pocketmine\\command\\defaults\\ParticleCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/ParticleCommand.php',
        'pocketmine\\command\\defaults\\PluginsCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/PluginsCommand.php',
        'pocketmine\\command\\defaults\\ReloadCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/ReloadCommand.php',
        'pocketmine\\command\\defaults\\SaveCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/SaveCommand.php',
        'pocketmine\\command\\defaults\\SaveOffCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/SaveOffCommand.php',
        'pocketmine\\command\\defaults\\SaveOnCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/SaveOnCommand.php',
        'pocketmine\\command\\defaults\\SayCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/SayCommand.php',
        'pocketmine\\command\\defaults\\SeedCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/SeedCommand.php',
        'pocketmine\\command\\defaults\\SetWorldSpawnCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/SetWorldSpawnCommand.php',
        'pocketmine\\command\\defaults\\SpawnpointCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/SpawnpointCommand.php',
        'pocketmine\\command\\defaults\\StatusCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/StatusCommand.php',
        'pocketmine\\command\\defaults\\StopCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/StopCommand.php',
        'pocketmine\\command\\defaults\\TeleportCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/TeleportCommand.php',
        'pocketmine\\command\\defaults\\TellCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/TellCommand.php',
        'pocketmine\\command\\defaults\\TimeCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/TimeCommand.php',
        'pocketmine\\command\\defaults\\TimingsCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/TimingsCommand.php',
        'pocketmine\\command\\defaults\\TitleCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/TitleCommand.php',
        'pocketmine\\command\\defaults\\TransferServerCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/TransferServerCommand.php',
        'pocketmine\\command\\defaults\\VanillaCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/VanillaCommand.php',
        'pocketmine\\command\\defaults\\VersionCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/VersionCommand.php',
        'pocketmine\\command\\defaults\\WhitelistCommand' => __DIR__ . '/../..' . '/src/pocketmine/command/defaults/WhitelistCommand.php',
        'pocketmine\\command\\utils\\CommandException' => __DIR__ . '/../..' . '/src/pocketmine/command/utils/CommandException.php',
        'pocketmine\\command\\utils\\InvalidCommandSyntaxException' => __DIR__ . '/../..' . '/src/pocketmine/command/utils/InvalidCommandSyntaxException.php',
        'pocketmine\\entity\\Ageable' => __DIR__ . '/../..' . '/src/pocketmine/entity/Ageable.php',
        'pocketmine\\entity\\Animal' => __DIR__ . '/../..' . '/src/pocketmine/entity/Animal.php',
        'pocketmine\\entity\\Attribute' => __DIR__ . '/../..' . '/src/pocketmine/entity/Attribute.php',
        'pocketmine\\entity\\AttributeMap' => __DIR__ . '/../..' . '/src/pocketmine/entity/AttributeMap.php',
        'pocketmine\\entity\\Creature' => __DIR__ . '/../..' . '/src/pocketmine/entity/Creature.php',
        'pocketmine\\entity\\Damageable' => __DIR__ . '/../..' . '/src/pocketmine/entity/Damageable.php',
        'pocketmine\\entity\\DataPropertyManager' => __DIR__ . '/../..' . '/src/pocketmine/entity/DataPropertyManager.php',
        'pocketmine\\entity\\Effect' => __DIR__ . '/../..' . '/src/pocketmine/entity/Effect.php',
        'pocketmine\\entity\\EffectInstance' => __DIR__ . '/../..' . '/src/pocketmine/entity/EffectInstance.php',
        'pocketmine\\entity\\Entity' => __DIR__ . '/../..' . '/src/pocketmine/entity/Entity.php',
        'pocketmine\\entity\\EntityIds' => __DIR__ . '/../..' . '/src/pocketmine/entity/EntityIds.php',
        'pocketmine\\entity\\Explosive' => __DIR__ . '/../..' . '/src/pocketmine/entity/Explosive.php',
        'pocketmine\\entity\\Human' => __DIR__ . '/../..' . '/src/pocketmine/entity/Human.php',
        'pocketmine\\entity\\Living' => __DIR__ . '/../..' . '/src/pocketmine/entity/Living.php',
        'pocketmine\\entity\\Monster' => __DIR__ . '/../..' . '/src/pocketmine/entity/Monster.php',
        'pocketmine\\entity\\NPC' => __DIR__ . '/../..' . '/src/pocketmine/entity/NPC.php',
        'pocketmine\\entity\\Rideable' => __DIR__ . '/../..' . '/src/pocketmine/entity/Rideable.php',
        'pocketmine\\entity\\Skin' => __DIR__ . '/../..' . '/src/pocketmine/entity/Skin.php',
        'pocketmine\\entity\\Squid' => __DIR__ . '/../..' . '/src/pocketmine/entity/Squid.php',
        'pocketmine\\entity\\Vehicle' => __DIR__ . '/../..' . '/src/pocketmine/entity/Vehicle.php',
        'pocketmine\\entity\\Villager' => __DIR__ . '/../..' . '/src/pocketmine/entity/Villager.php',
        'pocketmine\\entity\\WaterAnimal' => __DIR__ . '/../..' . '/src/pocketmine/entity/WaterAnimal.php',
        'pocketmine\\entity\\Zombie' => __DIR__ . '/../..' . '/src/pocketmine/entity/Zombie.php',
        'pocketmine\\entity\\object\\ExperienceOrb' => __DIR__ . '/../..' . '/src/pocketmine/entity/object/ExperienceOrb.php',
        'pocketmine\\entity\\object\\FallingBlock' => __DIR__ . '/../..' . '/src/pocketmine/entity/object/FallingBlock.php',
        'pocketmine\\entity\\object\\ItemEntity' => __DIR__ . '/../..' . '/src/pocketmine/entity/object/ItemEntity.php',
        'pocketmine\\entity\\object\\Painting' => __DIR__ . '/../..' . '/src/pocketmine/entity/object/Painting.php',
        'pocketmine\\entity\\object\\PaintingMotive' => __DIR__ . '/../..' . '/src/pocketmine/entity/object/PaintingMotive.php',
        'pocketmine\\entity\\object\\PrimedTNT' => __DIR__ . '/../..' . '/src/pocketmine/entity/object/PrimedTNT.php',
        'pocketmine\\entity\\projectile\\Arrow' => __DIR__ . '/../..' . '/src/pocketmine/entity/projectile/Arrow.php',
        'pocketmine\\entity\\projectile\\Egg' => __DIR__ . '/../..' . '/src/pocketmine/entity/projectile/Egg.php',
        'pocketmine\\entity\\projectile\\EnderPearl' => __DIR__ . '/../..' . '/src/pocketmine/entity/projectile/EnderPearl.php',
        'pocketmine\\entity\\projectile\\ExperienceBottle' => __DIR__ . '/../..' . '/src/pocketmine/entity/projectile/ExperienceBottle.php',
        'pocketmine\\entity\\projectile\\Projectile' => __DIR__ . '/../..' . '/src/pocketmine/entity/projectile/Projectile.php',
        'pocketmine\\entity\\projectile\\ProjectileSource' => __DIR__ . '/../..' . '/src/pocketmine/entity/projectile/ProjectileSource.php',
        'pocketmine\\entity\\projectile\\Snowball' => __DIR__ . '/../..' . '/src/pocketmine/entity/projectile/Snowball.php',
        'pocketmine\\entity\\projectile\\SplashPotion' => __DIR__ . '/../..' . '/src/pocketmine/entity/projectile/SplashPotion.php',
        'pocketmine\\entity\\projectile\\Throwable' => __DIR__ . '/../..' . '/src/pocketmine/entity/projectile/Throwable.php',
        'pocketmine\\entity\\utils\\ExperienceUtils' => __DIR__ . '/../..' . '/src/pocketmine/entity/utils/ExperienceUtils.php',
        'pocketmine\\event\\Cancellable' => __DIR__ . '/../..' . '/src/pocketmine/event/Cancellable.php',
        'pocketmine\\event\\Event' => __DIR__ . '/../..' . '/src/pocketmine/event/Event.php',
        'pocketmine\\event\\EventPriority' => __DIR__ . '/../..' . '/src/pocketmine/event/EventPriority.php',
        'pocketmine\\event\\HandlerList' => __DIR__ . '/../..' . '/src/pocketmine/event/HandlerList.php',
        'pocketmine\\event\\Listener' => __DIR__ . '/../..' . '/src/pocketmine/event/Listener.php',
        'pocketmine\\event\\block\\BlockBreakEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/BlockBreakEvent.php',
        'pocketmine\\event\\block\\BlockBurnEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/BlockBurnEvent.php',
        'pocketmine\\event\\block\\BlockEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/BlockEvent.php',
        'pocketmine\\event\\block\\BlockFormEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/BlockFormEvent.php',
        'pocketmine\\event\\block\\BlockGrowEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/BlockGrowEvent.php',
        'pocketmine\\event\\block\\BlockPlaceEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/BlockPlaceEvent.php',
        'pocketmine\\event\\block\\BlockSpreadEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/BlockSpreadEvent.php',
        'pocketmine\\event\\block\\BlockUpdateEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/BlockUpdateEvent.php',
        'pocketmine\\event\\block\\LeavesDecayEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/LeavesDecayEvent.php',
        'pocketmine\\event\\block\\SignChangeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/block/SignChangeEvent.php',
        'pocketmine\\event\\entity\\EntityArmorChangeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityArmorChangeEvent.php',
        'pocketmine\\event\\entity\\EntityBlockChangeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityBlockChangeEvent.php',
        'pocketmine\\event\\entity\\EntityCombustByBlockEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityCombustByBlockEvent.php',
        'pocketmine\\event\\entity\\EntityCombustByEntityEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityCombustByEntityEvent.php',
        'pocketmine\\event\\entity\\EntityCombustEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityCombustEvent.php',
        'pocketmine\\event\\entity\\EntityDamageByBlockEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityDamageByBlockEvent.php',
        'pocketmine\\event\\entity\\EntityDamageByChildEntityEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityDamageByChildEntityEvent.php',
        'pocketmine\\event\\entity\\EntityDamageByEntityEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityDamageByEntityEvent.php',
        'pocketmine\\event\\entity\\EntityDamageEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityDamageEvent.php',
        'pocketmine\\event\\entity\\EntityDeathEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityDeathEvent.php',
        'pocketmine\\event\\entity\\EntityDespawnEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityDespawnEvent.php',
        'pocketmine\\event\\entity\\EntityEffectAddEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityEffectAddEvent.php',
        'pocketmine\\event\\entity\\EntityEffectEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityEffectEvent.php',
        'pocketmine\\event\\entity\\EntityEffectRemoveEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityEffectRemoveEvent.php',
        'pocketmine\\event\\entity\\EntityEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityEvent.php',
        'pocketmine\\event\\entity\\EntityExplodeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityExplodeEvent.php',
        'pocketmine\\event\\entity\\EntityInventoryChangeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityInventoryChangeEvent.php',
        'pocketmine\\event\\entity\\EntityLevelChangeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityLevelChangeEvent.php',
        'pocketmine\\event\\entity\\EntityMotionEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityMotionEvent.php',
        'pocketmine\\event\\entity\\EntityRegainHealthEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityRegainHealthEvent.php',
        'pocketmine\\event\\entity\\EntityShootBowEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityShootBowEvent.php',
        'pocketmine\\event\\entity\\EntitySpawnEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntitySpawnEvent.php',
        'pocketmine\\event\\entity\\EntityTeleportEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/EntityTeleportEvent.php',
        'pocketmine\\event\\entity\\ExplosionPrimeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/ExplosionPrimeEvent.php',
        'pocketmine\\event\\entity\\ItemDespawnEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/ItemDespawnEvent.php',
        'pocketmine\\event\\entity\\ItemSpawnEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/ItemSpawnEvent.php',
        'pocketmine\\event\\entity\\ProjectileHitBlockEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/ProjectileHitBlockEvent.php',
        'pocketmine\\event\\entity\\ProjectileHitEntityEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/ProjectileHitEntityEvent.php',
        'pocketmine\\event\\entity\\ProjectileHitEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/ProjectileHitEvent.php',
        'pocketmine\\event\\entity\\ProjectileLaunchEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/entity/ProjectileLaunchEvent.php',
        'pocketmine\\event\\inventory\\CraftItemEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/inventory/CraftItemEvent.php',
        'pocketmine\\event\\inventory\\FurnaceBurnEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/inventory/FurnaceBurnEvent.php',
        'pocketmine\\event\\inventory\\FurnaceSmeltEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/inventory/FurnaceSmeltEvent.php',
        'pocketmine\\event\\inventory\\InventoryCloseEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/inventory/InventoryCloseEvent.php',
        'pocketmine\\event\\inventory\\InventoryEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/inventory/InventoryEvent.php',
        'pocketmine\\event\\inventory\\InventoryOpenEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/inventory/InventoryOpenEvent.php',
        'pocketmine\\event\\inventory\\InventoryPickupArrowEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/inventory/InventoryPickupArrowEvent.php',
        'pocketmine\\event\\inventory\\InventoryPickupItemEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/inventory/InventoryPickupItemEvent.php',
        'pocketmine\\event\\inventory\\InventoryTransactionEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/inventory/InventoryTransactionEvent.php',
        'pocketmine\\event\\level\\ChunkEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/ChunkEvent.php',
        'pocketmine\\event\\level\\ChunkLoadEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/ChunkLoadEvent.php',
        'pocketmine\\event\\level\\ChunkPopulateEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/ChunkPopulateEvent.php',
        'pocketmine\\event\\level\\ChunkUnloadEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/ChunkUnloadEvent.php',
        'pocketmine\\event\\level\\LevelEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/LevelEvent.php',
        'pocketmine\\event\\level\\LevelInitEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/LevelInitEvent.php',
        'pocketmine\\event\\level\\LevelLoadEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/LevelLoadEvent.php',
        'pocketmine\\event\\level\\LevelSaveEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/LevelSaveEvent.php',
        'pocketmine\\event\\level\\LevelUnloadEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/LevelUnloadEvent.php',
        'pocketmine\\event\\level\\SpawnChangeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/level/SpawnChangeEvent.php',
        'pocketmine\\event\\player\\PlayerAchievementAwardedEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerAchievementAwardedEvent.php',
        'pocketmine\\event\\player\\PlayerAnimationEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerAnimationEvent.php',
        'pocketmine\\event\\player\\PlayerBedEnterEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerBedEnterEvent.php',
        'pocketmine\\event\\player\\PlayerBedLeaveEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerBedLeaveEvent.php',
        'pocketmine\\event\\player\\PlayerBlockPickEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerBlockPickEvent.php',
        'pocketmine\\event\\player\\PlayerBucketEmptyEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerBucketEmptyEvent.php',
        'pocketmine\\event\\player\\PlayerBucketEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerBucketEvent.php',
        'pocketmine\\event\\player\\PlayerBucketFillEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerBucketFillEvent.php',
        'pocketmine\\event\\player\\PlayerChangeSkinEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerChangeSkinEvent.php',
        'pocketmine\\event\\player\\PlayerChatEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerChatEvent.php',
        'pocketmine\\event\\player\\PlayerCommandPreprocessEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerCommandPreprocessEvent.php',
        'pocketmine\\event\\player\\PlayerCreationEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerCreationEvent.php',
        'pocketmine\\event\\player\\PlayerDataSaveEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerDataSaveEvent.php',
        'pocketmine\\event\\player\\PlayerDeathEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerDeathEvent.php',
        'pocketmine\\event\\player\\PlayerDropItemEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerDropItemEvent.php',
        'pocketmine\\event\\player\\PlayerEditBookEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerEditBookEvent.php',
        'pocketmine\\event\\player\\PlayerEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerEvent.php',
        'pocketmine\\event\\player\\PlayerExhaustEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerExhaustEvent.php',
        'pocketmine\\event\\player\\PlayerExperienceChangeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerExperienceChangeEvent.php',
        'pocketmine\\event\\player\\PlayerGameModeChangeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerGameModeChangeEvent.php',
        'pocketmine\\event\\player\\PlayerInteractEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerInteractEvent.php',
        'pocketmine\\event\\player\\PlayerItemConsumeEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerItemConsumeEvent.php',
        'pocketmine\\event\\player\\PlayerItemHeldEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerItemHeldEvent.php',
        'pocketmine\\event\\player\\PlayerJoinEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerJoinEvent.php',
        'pocketmine\\event\\player\\PlayerJumpEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerJumpEvent.php',
        'pocketmine\\event\\player\\PlayerKickEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerKickEvent.php',
        'pocketmine\\event\\player\\PlayerLoginEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerLoginEvent.php',
        'pocketmine\\event\\player\\PlayerMoveEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerMoveEvent.php',
        'pocketmine\\event\\player\\PlayerPreLoginEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerPreLoginEvent.php',
        'pocketmine\\event\\player\\PlayerQuitEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerQuitEvent.php',
        'pocketmine\\event\\player\\PlayerRespawnEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerRespawnEvent.php',
        'pocketmine\\event\\player\\PlayerToggleFlightEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerToggleFlightEvent.php',
        'pocketmine\\event\\player\\PlayerToggleSneakEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerToggleSneakEvent.php',
        'pocketmine\\event\\player\\PlayerToggleSprintEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerToggleSprintEvent.php',
        'pocketmine\\event\\player\\PlayerTransferEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/PlayerTransferEvent.php',
        'pocketmine\\event\\player\\cheat\\PlayerCheatEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/cheat/PlayerCheatEvent.php',
        'pocketmine\\event\\player\\cheat\\PlayerIllegalMoveEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/player/cheat/PlayerIllegalMoveEvent.php',
        'pocketmine\\event\\plugin\\PluginDisableEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/plugin/PluginDisableEvent.php',
        'pocketmine\\event\\plugin\\PluginEnableEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/plugin/PluginEnableEvent.php',
        'pocketmine\\event\\plugin\\PluginEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/plugin/PluginEvent.php',
        'pocketmine\\event\\server\\CommandEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/CommandEvent.php',
        'pocketmine\\event\\server\\DataPacketReceiveEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/DataPacketReceiveEvent.php',
        'pocketmine\\event\\server\\DataPacketSendEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/DataPacketSendEvent.php',
        'pocketmine\\event\\server\\LowMemoryEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/LowMemoryEvent.php',
        'pocketmine\\event\\server\\NetworkInterfaceCrashEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/NetworkInterfaceCrashEvent.php',
        'pocketmine\\event\\server\\NetworkInterfaceEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/NetworkInterfaceEvent.php',
        'pocketmine\\event\\server\\NetworkInterfaceRegisterEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/NetworkInterfaceRegisterEvent.php',
        'pocketmine\\event\\server\\NetworkInterfaceUnregisterEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/NetworkInterfaceUnregisterEvent.php',
        'pocketmine\\event\\server\\QueryRegenerateEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/QueryRegenerateEvent.php',
        'pocketmine\\event\\server\\RemoteServerCommandEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/RemoteServerCommandEvent.php',
        'pocketmine\\event\\server\\ServerCommandEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/ServerCommandEvent.php',
        'pocketmine\\event\\server\\ServerEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/ServerEvent.php',
        'pocketmine\\event\\server\\UpdateNotifyEvent' => __DIR__ . '/../..' . '/src/pocketmine/event/server/UpdateNotifyEvent.php',
        'pocketmine\\form\\Form' => __DIR__ . '/../..' . '/src/pocketmine/form/Form.php',
        'pocketmine\\form\\FormValidationException' => __DIR__ . '/../..' . '/src/pocketmine/form/FormValidationException.php',
        'pocketmine\\inventory\\AnvilInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/AnvilInventory.php',
        'pocketmine\\inventory\\ArmorInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/ArmorInventory.php',
        'pocketmine\\inventory\\ArmorInventoryEventProcessor' => __DIR__ . '/../..' . '/src/pocketmine/inventory/ArmorInventoryEventProcessor.php',
        'pocketmine\\inventory\\BaseInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/BaseInventory.php',
        'pocketmine\\inventory\\ChestInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/ChestInventory.php',
        'pocketmine\\inventory\\ContainerInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/ContainerInventory.php',
        'pocketmine\\inventory\\CraftingGrid' => __DIR__ . '/../..' . '/src/pocketmine/inventory/CraftingGrid.php',
        'pocketmine\\inventory\\CraftingManager' => __DIR__ . '/../..' . '/src/pocketmine/inventory/CraftingManager.php',
        'pocketmine\\inventory\\CraftingRecipe' => __DIR__ . '/../..' . '/src/pocketmine/inventory/CraftingRecipe.php',
        'pocketmine\\inventory\\CustomInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/CustomInventory.php',
        'pocketmine\\inventory\\DoubleChestInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/DoubleChestInventory.php',
        'pocketmine\\inventory\\EnchantInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/EnchantInventory.php',
        'pocketmine\\inventory\\EnderChestInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/EnderChestInventory.php',
        'pocketmine\\inventory\\EntityInventoryEventProcessor' => __DIR__ . '/../..' . '/src/pocketmine/inventory/EntityInventoryEventProcessor.php',
        'pocketmine\\inventory\\FurnaceInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/FurnaceInventory.php',
        'pocketmine\\inventory\\FurnaceRecipe' => __DIR__ . '/../..' . '/src/pocketmine/inventory/FurnaceRecipe.php',
        'pocketmine\\inventory\\Inventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/Inventory.php',
        'pocketmine\\inventory\\InventoryEventProcessor' => __DIR__ . '/../..' . '/src/pocketmine/inventory/InventoryEventProcessor.php',
        'pocketmine\\inventory\\InventoryHolder' => __DIR__ . '/../..' . '/src/pocketmine/inventory/InventoryHolder.php',
        'pocketmine\\inventory\\MultiRecipe' => __DIR__ . '/../..' . '/src/pocketmine/inventory/MultiRecipe.php',
        'pocketmine\\inventory\\PlayerCursorInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/PlayerCursorInventory.php',
        'pocketmine\\inventory\\PlayerInventory' => __DIR__ . '/../..' . '/src/pocketmine/inventory/PlayerInventory.php',
        'pocketmine\\inventory\\Recipe' => __DIR__ . '/../..' . '/src/pocketmine/inventory/Recipe.php',
        'pocketmine\\inventory\\ShapedRecipe' => __DIR__ . '/../..' . '/src/pocketmine/inventory/ShapedRecipe.php',
        'pocketmine\\inventory\\ShapelessRecipe' => __DIR__ . '/../..' . '/src/pocketmine/inventory/ShapelessRecipe.php',
        'pocketmine\\inventory\\transaction\\CraftingTransaction' => __DIR__ . '/../..' . '/src/pocketmine/inventory/transaction/CraftingTransaction.php',
        'pocketmine\\inventory\\transaction\\InventoryTransaction' => __DIR__ . '/../..' . '/src/pocketmine/inventory/transaction/InventoryTransaction.php',
        'pocketmine\\inventory\\transaction\\TransactionValidationException' => __DIR__ . '/../..' . '/src/pocketmine/inventory/transaction/TransactionValidationException.php',
        'pocketmine\\inventory\\transaction\\action\\CreativeInventoryAction' => __DIR__ . '/../..' . '/src/pocketmine/inventory/transaction/action/CreativeInventoryAction.php',
        'pocketmine\\inventory\\transaction\\action\\DropItemAction' => __DIR__ . '/../..' . '/src/pocketmine/inventory/transaction/action/DropItemAction.php',
        'pocketmine\\inventory\\transaction\\action\\InventoryAction' => __DIR__ . '/../..' . '/src/pocketmine/inventory/transaction/action/InventoryAction.php',
        'pocketmine\\inventory\\transaction\\action\\SlotChangeAction' => __DIR__ . '/../..' . '/src/pocketmine/inventory/transaction/action/SlotChangeAction.php',
        'pocketmine\\item\\Apple' => __DIR__ . '/../..' . '/src/pocketmine/item/Apple.php',
        'pocketmine\\item\\Armor' => __DIR__ . '/../..' . '/src/pocketmine/item/Armor.php',
        'pocketmine\\item\\Arrow' => __DIR__ . '/../..' . '/src/pocketmine/item/Arrow.php',
        'pocketmine\\item\\Axe' => __DIR__ . '/../..' . '/src/pocketmine/item/Axe.php',
        'pocketmine\\item\\BakedPotato' => __DIR__ . '/../..' . '/src/pocketmine/item/BakedPotato.php',
        'pocketmine\\item\\Banner' => __DIR__ . '/../..' . '/src/pocketmine/item/Banner.php',
        'pocketmine\\item\\Bed' => __DIR__ . '/../..' . '/src/pocketmine/item/Bed.php',
        'pocketmine\\item\\Beetroot' => __DIR__ . '/../..' . '/src/pocketmine/item/Beetroot.php',
        'pocketmine\\item\\BeetrootSeeds' => __DIR__ . '/../..' . '/src/pocketmine/item/BeetrootSeeds.php',
        'pocketmine\\item\\BeetrootSoup' => __DIR__ . '/../..' . '/src/pocketmine/item/BeetrootSoup.php',
        'pocketmine\\item\\BlazeRod' => __DIR__ . '/../..' . '/src/pocketmine/item/BlazeRod.php',
        'pocketmine\\item\\Boat' => __DIR__ . '/../..' . '/src/pocketmine/item/Boat.php',
        'pocketmine\\item\\Book' => __DIR__ . '/../..' . '/src/pocketmine/item/Book.php',
        'pocketmine\\item\\Bow' => __DIR__ . '/../..' . '/src/pocketmine/item/Bow.php',
        'pocketmine\\item\\Bowl' => __DIR__ . '/../..' . '/src/pocketmine/item/Bowl.php',
        'pocketmine\\item\\Bread' => __DIR__ . '/../..' . '/src/pocketmine/item/Bread.php',
        'pocketmine\\item\\Bucket' => __DIR__ . '/../..' . '/src/pocketmine/item/Bucket.php',
        'pocketmine\\item\\Carrot' => __DIR__ . '/../..' . '/src/pocketmine/item/Carrot.php',
        'pocketmine\\item\\ChainBoots' => __DIR__ . '/../..' . '/src/pocketmine/item/ChainBoots.php',
        'pocketmine\\item\\ChainChestplate' => __DIR__ . '/../..' . '/src/pocketmine/item/ChainChestplate.php',
        'pocketmine\\item\\ChainHelmet' => __DIR__ . '/../..' . '/src/pocketmine/item/ChainHelmet.php',
        'pocketmine\\item\\ChainLeggings' => __DIR__ . '/../..' . '/src/pocketmine/item/ChainLeggings.php',
        'pocketmine\\item\\ChorusFruit' => __DIR__ . '/../..' . '/src/pocketmine/item/ChorusFruit.php',
        'pocketmine\\item\\Clock' => __DIR__ . '/../..' . '/src/pocketmine/item/Clock.php',
        'pocketmine\\item\\Clownfish' => __DIR__ . '/../..' . '/src/pocketmine/item/Clownfish.php',
        'pocketmine\\item\\Coal' => __DIR__ . '/../..' . '/src/pocketmine/item/Coal.php',
        'pocketmine\\item\\Compass' => __DIR__ . '/../..' . '/src/pocketmine/item/Compass.php',
        'pocketmine\\item\\Consumable' => __DIR__ . '/../..' . '/src/pocketmine/item/Consumable.php',
        'pocketmine\\item\\CookedChicken' => __DIR__ . '/../..' . '/src/pocketmine/item/CookedChicken.php',
        'pocketmine\\item\\CookedFish' => __DIR__ . '/../..' . '/src/pocketmine/item/CookedFish.php',
        'pocketmine\\item\\CookedMutton' => __DIR__ . '/../..' . '/src/pocketmine/item/CookedMutton.php',
        'pocketmine\\item\\CookedPorkchop' => __DIR__ . '/../..' . '/src/pocketmine/item/CookedPorkchop.php',
        'pocketmine\\item\\CookedRabbit' => __DIR__ . '/../..' . '/src/pocketmine/item/CookedRabbit.php',
        'pocketmine\\item\\CookedSalmon' => __DIR__ . '/../..' . '/src/pocketmine/item/CookedSalmon.php',
        'pocketmine\\item\\Cookie' => __DIR__ . '/../..' . '/src/pocketmine/item/Cookie.php',
        'pocketmine\\item\\DiamondBoots' => __DIR__ . '/../..' . '/src/pocketmine/item/DiamondBoots.php',
        'pocketmine\\item\\DiamondChestplate' => __DIR__ . '/../..' . '/src/pocketmine/item/DiamondChestplate.php',
        'pocketmine\\item\\DiamondHelmet' => __DIR__ . '/../..' . '/src/pocketmine/item/DiamondHelmet.php',
        'pocketmine\\item\\DiamondLeggings' => __DIR__ . '/../..' . '/src/pocketmine/item/DiamondLeggings.php',
        'pocketmine\\item\\DriedKelp' => __DIR__ . '/../..' . '/src/pocketmine/item/DriedKelp.php',
        'pocketmine\\item\\Durable' => __DIR__ . '/../..' . '/src/pocketmine/item/Durable.php',
        'pocketmine\\item\\Dye' => __DIR__ . '/../..' . '/src/pocketmine/item/Dye.php',
        'pocketmine\\item\\Egg' => __DIR__ . '/../..' . '/src/pocketmine/item/Egg.php',
        'pocketmine\\item\\EnderPearl' => __DIR__ . '/../..' . '/src/pocketmine/item/EnderPearl.php',
        'pocketmine\\item\\ExperienceBottle' => __DIR__ . '/../..' . '/src/pocketmine/item/ExperienceBottle.php',
        'pocketmine\\item\\FishingRod' => __DIR__ . '/../..' . '/src/pocketmine/item/FishingRod.php',
        'pocketmine\\item\\FlintSteel' => __DIR__ . '/../..' . '/src/pocketmine/item/FlintSteel.php',
        'pocketmine\\item\\Food' => __DIR__ . '/../..' . '/src/pocketmine/item/Food.php',
        'pocketmine\\item\\FoodSource' => __DIR__ . '/../..' . '/src/pocketmine/item/FoodSource.php',
        'pocketmine\\item\\GlassBottle' => __DIR__ . '/../..' . '/src/pocketmine/item/GlassBottle.php',
        'pocketmine\\item\\GoldBoots' => __DIR__ . '/../..' . '/src/pocketmine/item/GoldBoots.php',
        'pocketmine\\item\\GoldChestplate' => __DIR__ . '/../..' . '/src/pocketmine/item/GoldChestplate.php',
        'pocketmine\\item\\GoldHelmet' => __DIR__ . '/../..' . '/src/pocketmine/item/GoldHelmet.php',
        'pocketmine\\item\\GoldLeggings' => __DIR__ . '/../..' . '/src/pocketmine/item/GoldLeggings.php',
        'pocketmine\\item\\GoldenApple' => __DIR__ . '/../..' . '/src/pocketmine/item/GoldenApple.php',
        'pocketmine\\item\\GoldenAppleEnchanted' => __DIR__ . '/../..' . '/src/pocketmine/item/GoldenAppleEnchanted.php',
        'pocketmine\\item\\GoldenCarrot' => __DIR__ . '/../..' . '/src/pocketmine/item/GoldenCarrot.php',
        'pocketmine\\item\\Hoe' => __DIR__ . '/../..' . '/src/pocketmine/item/Hoe.php',
        'pocketmine\\item\\IronBoots' => __DIR__ . '/../..' . '/src/pocketmine/item/IronBoots.php',
        'pocketmine\\item\\IronChestplate' => __DIR__ . '/../..' . '/src/pocketmine/item/IronChestplate.php',
        'pocketmine\\item\\IronHelmet' => __DIR__ . '/../..' . '/src/pocketmine/item/IronHelmet.php',
        'pocketmine\\item\\IronLeggings' => __DIR__ . '/../..' . '/src/pocketmine/item/IronLeggings.php',
        'pocketmine\\item\\Item' => __DIR__ . '/../..' . '/src/pocketmine/item/Item.php',
        'pocketmine\\item\\ItemBlock' => __DIR__ . '/../..' . '/src/pocketmine/item/ItemBlock.php',
        'pocketmine\\item\\ItemFactory' => __DIR__ . '/../..' . '/src/pocketmine/item/ItemFactory.php',
        'pocketmine\\item\\ItemIds' => __DIR__ . '/../..' . '/src/pocketmine/item/ItemIds.php',
        'pocketmine\\item\\LeatherBoots' => __DIR__ . '/../..' . '/src/pocketmine/item/LeatherBoots.php',
        'pocketmine\\item\\LeatherCap' => __DIR__ . '/../..' . '/src/pocketmine/item/LeatherCap.php',
        'pocketmine\\item\\LeatherPants' => __DIR__ . '/../..' . '/src/pocketmine/item/LeatherPants.php',
        'pocketmine\\item\\LeatherTunic' => __DIR__ . '/../..' . '/src/pocketmine/item/LeatherTunic.php',
        'pocketmine\\item\\MaybeConsumable' => __DIR__ . '/../..' . '/src/pocketmine/item/MaybeConsumable.php',
        'pocketmine\\item\\Melon' => __DIR__ . '/../..' . '/src/pocketmine/item/Melon.php',
        'pocketmine\\item\\MelonSeeds' => __DIR__ . '/../..' . '/src/pocketmine/item/MelonSeeds.php',
        'pocketmine\\item\\Minecart' => __DIR__ . '/../..' . '/src/pocketmine/item/Minecart.php',
        'pocketmine\\item\\MushroomStew' => __DIR__ . '/../..' . '/src/pocketmine/item/MushroomStew.php',
        'pocketmine\\item\\PaintingItem' => __DIR__ . '/../..' . '/src/pocketmine/item/PaintingItem.php',
        'pocketmine\\item\\Pickaxe' => __DIR__ . '/../..' . '/src/pocketmine/item/Pickaxe.php',
        'pocketmine\\item\\PoisonousPotato' => __DIR__ . '/../..' . '/src/pocketmine/item/PoisonousPotato.php',
        'pocketmine\\item\\Potato' => __DIR__ . '/../..' . '/src/pocketmine/item/Potato.php',
        'pocketmine\\item\\Potion' => __DIR__ . '/../..' . '/src/pocketmine/item/Potion.php',
        'pocketmine\\item\\ProjectileItem' => __DIR__ . '/../..' . '/src/pocketmine/item/ProjectileItem.php',
        'pocketmine\\item\\Pufferfish' => __DIR__ . '/../..' . '/src/pocketmine/item/Pufferfish.php',
        'pocketmine\\item\\PumpkinPie' => __DIR__ . '/../..' . '/src/pocketmine/item/PumpkinPie.php',
        'pocketmine\\item\\PumpkinSeeds' => __DIR__ . '/../..' . '/src/pocketmine/item/PumpkinSeeds.php',
        'pocketmine\\item\\RabbitStew' => __DIR__ . '/../..' . '/src/pocketmine/item/RabbitStew.php',
        'pocketmine\\item\\RawBeef' => __DIR__ . '/../..' . '/src/pocketmine/item/RawBeef.php',
        'pocketmine\\item\\RawChicken' => __DIR__ . '/../..' . '/src/pocketmine/item/RawChicken.php',
        'pocketmine\\item\\RawFish' => __DIR__ . '/../..' . '/src/pocketmine/item/RawFish.php',
        'pocketmine\\item\\RawMutton' => __DIR__ . '/../..' . '/src/pocketmine/item/RawMutton.php',
        'pocketmine\\item\\RawPorkchop' => __DIR__ . '/../..' . '/src/pocketmine/item/RawPorkchop.php',
        'pocketmine\\item\\RawRabbit' => __DIR__ . '/../..' . '/src/pocketmine/item/RawRabbit.php',
        'pocketmine\\item\\RawSalmon' => __DIR__ . '/../..' . '/src/pocketmine/item/RawSalmon.php',
        'pocketmine\\item\\Redstone' => __DIR__ . '/../..' . '/src/pocketmine/item/Redstone.php',
        'pocketmine\\item\\RottenFlesh' => __DIR__ . '/../..' . '/src/pocketmine/item/RottenFlesh.php',
        'pocketmine\\item\\Shears' => __DIR__ . '/../..' . '/src/pocketmine/item/Shears.php',
        'pocketmine\\item\\Shovel' => __DIR__ . '/../..' . '/src/pocketmine/item/Shovel.php',
        'pocketmine\\item\\Sign' => __DIR__ . '/../..' . '/src/pocketmine/item/Sign.php',
        'pocketmine\\item\\Snowball' => __DIR__ . '/../..' . '/src/pocketmine/item/Snowball.php',
        'pocketmine\\item\\SpawnEgg' => __DIR__ . '/../..' . '/src/pocketmine/item/SpawnEgg.php',
        'pocketmine\\item\\SpiderEye' => __DIR__ . '/../..' . '/src/pocketmine/item/SpiderEye.php',
        'pocketmine\\item\\SplashPotion' => __DIR__ . '/../..' . '/src/pocketmine/item/SplashPotion.php',
        'pocketmine\\item\\Steak' => __DIR__ . '/../..' . '/src/pocketmine/item/Steak.php',
        'pocketmine\\item\\Stick' => __DIR__ . '/../..' . '/src/pocketmine/item/Stick.php',
        'pocketmine\\item\\StringItem' => __DIR__ . '/../..' . '/src/pocketmine/item/StringItem.php',
        'pocketmine\\item\\Sword' => __DIR__ . '/../..' . '/src/pocketmine/item/Sword.php',
        'pocketmine\\item\\TieredTool' => __DIR__ . '/../..' . '/src/pocketmine/item/TieredTool.php',
        'pocketmine\\item\\Tool' => __DIR__ . '/../..' . '/src/pocketmine/item/Tool.php',
        'pocketmine\\item\\Totem' => __DIR__ . '/../..' . '/src/pocketmine/item/Totem.php',
        'pocketmine\\item\\WheatSeeds' => __DIR__ . '/../..' . '/src/pocketmine/item/WheatSeeds.php',
        'pocketmine\\item\\WritableBook' => __DIR__ . '/../..' . '/src/pocketmine/item/WritableBook.php',
        'pocketmine\\item\\WrittenBook' => __DIR__ . '/../..' . '/src/pocketmine/item/WrittenBook.php',
        'pocketmine\\item\\enchantment\\Enchantment' => __DIR__ . '/../..' . '/src/pocketmine/item/enchantment/Enchantment.php',
        'pocketmine\\item\\enchantment\\EnchantmentEntry' => __DIR__ . '/../..' . '/src/pocketmine/item/enchantment/EnchantmentEntry.php',
        'pocketmine\\item\\enchantment\\EnchantmentInstance' => __DIR__ . '/../..' . '/src/pocketmine/item/enchantment/EnchantmentInstance.php',
        'pocketmine\\item\\enchantment\\EnchantmentList' => __DIR__ . '/../..' . '/src/pocketmine/item/enchantment/EnchantmentList.php',
        'pocketmine\\item\\enchantment\\FireAspectEnchantment' => __DIR__ . '/../..' . '/src/pocketmine/item/enchantment/FireAspectEnchantment.php',
        'pocketmine\\item\\enchantment\\KnockbackEnchantment' => __DIR__ . '/../..' . '/src/pocketmine/item/enchantment/KnockbackEnchantment.php',
        'pocketmine\\item\\enchantment\\MeleeWeaponEnchantment' => __DIR__ . '/../..' . '/src/pocketmine/item/enchantment/MeleeWeaponEnchantment.php',
        'pocketmine\\item\\enchantment\\ProtectionEnchantment' => __DIR__ . '/../..' . '/src/pocketmine/item/enchantment/ProtectionEnchantment.php',
        'pocketmine\\item\\enchantment\\SharpnessEnchantment' => __DIR__ . '/../..' . '/src/pocketmine/item/enchantment/SharpnessEnchantment.php',
        'pocketmine\\lang\\BaseLang' => __DIR__ . '/../..' . '/src/pocketmine/lang/BaseLang.php',
        'pocketmine\\lang\\TextContainer' => __DIR__ . '/../..' . '/src/pocketmine/lang/TextContainer.php',
        'pocketmine\\lang\\TranslationContainer' => __DIR__ . '/../..' . '/src/pocketmine/lang/TranslationContainer.php',
        'pocketmine\\level\\ChunkLoader' => __DIR__ . '/../..' . '/src/pocketmine/level/ChunkLoader.php',
        'pocketmine\\level\\ChunkManager' => __DIR__ . '/../..' . '/src/pocketmine/level/ChunkManager.php',
        'pocketmine\\level\\Explosion' => __DIR__ . '/../..' . '/src/pocketmine/level/Explosion.php',
        'pocketmine\\level\\Level' => __DIR__ . '/../..' . '/src/pocketmine/level/Level.php',
        'pocketmine\\level\\LevelException' => __DIR__ . '/../..' . '/src/pocketmine/level/LevelException.php',
        'pocketmine\\level\\LevelTimings' => __DIR__ . '/../..' . '/src/pocketmine/level/LevelTimings.php',
        'pocketmine\\level\\Location' => __DIR__ . '/../..' . '/src/pocketmine/level/Location.php',
        'pocketmine\\level\\Position' => __DIR__ . '/../..' . '/src/pocketmine/level/Position.php',
        'pocketmine\\level\\SimpleChunkManager' => __DIR__ . '/../..' . '/src/pocketmine/level/SimpleChunkManager.php',
        'pocketmine\\level\\biome\\Biome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/Biome.php',
        'pocketmine\\level\\biome\\DesertBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/DesertBiome.php',
        'pocketmine\\level\\biome\\ForestBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/ForestBiome.php',
        'pocketmine\\level\\biome\\GrassyBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/GrassyBiome.php',
        'pocketmine\\level\\biome\\HellBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/HellBiome.php',
        'pocketmine\\level\\biome\\IcePlainsBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/IcePlainsBiome.php',
        'pocketmine\\level\\biome\\MountainsBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/MountainsBiome.php',
        'pocketmine\\level\\biome\\OceanBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/OceanBiome.php',
        'pocketmine\\level\\biome\\PlainBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/PlainBiome.php',
        'pocketmine\\level\\biome\\RiverBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/RiverBiome.php',
        'pocketmine\\level\\biome\\SandyBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/SandyBiome.php',
        'pocketmine\\level\\biome\\SmallMountainsBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/SmallMountainsBiome.php',
        'pocketmine\\level\\biome\\SnowyBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/SnowyBiome.php',
        'pocketmine\\level\\biome\\SwampBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/SwampBiome.php',
        'pocketmine\\level\\biome\\TaigaBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/TaigaBiome.php',
        'pocketmine\\level\\biome\\UnknownBiome' => __DIR__ . '/../..' . '/src/pocketmine/level/biome/UnknownBiome.php',
        'pocketmine\\level\\format\\Chunk' => __DIR__ . '/../..' . '/src/pocketmine/level/format/Chunk.php',
        'pocketmine\\level\\format\\ChunkException' => __DIR__ . '/../..' . '/src/pocketmine/level/format/ChunkException.php',
        'pocketmine\\level\\format\\EmptySubChunk' => __DIR__ . '/../..' . '/src/pocketmine/level/format/EmptySubChunk.php',
        'pocketmine\\level\\format\\SubChunk' => __DIR__ . '/../..' . '/src/pocketmine/level/format/SubChunk.php',
        'pocketmine\\level\\format\\SubChunkInterface' => __DIR__ . '/../..' . '/src/pocketmine/level/format/SubChunkInterface.php',
        'pocketmine\\level\\format\\io\\BaseLevelProvider' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/BaseLevelProvider.php',
        'pocketmine\\level\\format\\io\\ChunkRequestTask' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/ChunkRequestTask.php',
        'pocketmine\\level\\format\\io\\ChunkUtils' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/ChunkUtils.php',
        'pocketmine\\level\\format\\io\\LevelProvider' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/LevelProvider.php',
        'pocketmine\\level\\format\\io\\LevelProviderManager' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/LevelProviderManager.php',
        'pocketmine\\level\\format\\io\\exception\\CorruptedChunkException' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/exception/CorruptedChunkException.php',
        'pocketmine\\level\\format\\io\\exception\\UnsupportedChunkFormatException' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/exception/UnsupportedChunkFormatException.php',
        'pocketmine\\level\\format\\io\\leveldb\\LevelDB' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/leveldb/LevelDB.php',
        'pocketmine\\level\\format\\io\\region\\Anvil' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/region/Anvil.php',
        'pocketmine\\level\\format\\io\\region\\CorruptedRegionException' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/region/CorruptedRegionException.php',
        'pocketmine\\level\\format\\io\\region\\McRegion' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/region/McRegion.php',
        'pocketmine\\level\\format\\io\\region\\PMAnvil' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/region/PMAnvil.php',
        'pocketmine\\level\\format\\io\\region\\RegionException' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/region/RegionException.php',
        'pocketmine\\level\\format\\io\\region\\RegionLoader' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/region/RegionLoader.php',
        'pocketmine\\level\\format\\io\\region\\RegionLocationTableEntry' => __DIR__ . '/../..' . '/src/pocketmine/level/format/io/region/RegionLocationTableEntry.php',
        'pocketmine\\level\\generator\\Flat' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/Flat.php',
        'pocketmine\\level\\generator\\Generator' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/Generator.php',
        'pocketmine\\level\\generator\\GeneratorManager' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/GeneratorManager.php',
        'pocketmine\\level\\generator\\GeneratorRegisterTask' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/GeneratorRegisterTask.php',
        'pocketmine\\level\\generator\\GeneratorUnregisterTask' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/GeneratorUnregisterTask.php',
        'pocketmine\\level\\generator\\InvalidGeneratorOptionsException' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/InvalidGeneratorOptionsException.php',
        'pocketmine\\level\\generator\\PopulationTask' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/PopulationTask.php',
        'pocketmine\\level\\generator\\biome\\BiomeSelector' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/biome/BiomeSelector.php',
        'pocketmine\\level\\generator\\hell\\Nether' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/hell/Nether.php',
        'pocketmine\\level\\generator\\noise\\Noise' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/noise/Noise.php',
        'pocketmine\\level\\generator\\noise\\Perlin' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/noise/Perlin.php',
        'pocketmine\\level\\generator\\noise\\Simplex' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/noise/Simplex.php',
        'pocketmine\\level\\generator\\normal\\Normal' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/normal/Normal.php',
        'pocketmine\\level\\generator\\object\\BigTree' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/BigTree.php',
        'pocketmine\\level\\generator\\object\\BirchTree' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/BirchTree.php',
        'pocketmine\\level\\generator\\object\\JungleTree' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/JungleTree.php',
        'pocketmine\\level\\generator\\object\\OakTree' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/OakTree.php',
        'pocketmine\\level\\generator\\object\\Ore' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/Ore.php',
        'pocketmine\\level\\generator\\object\\OreType' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/OreType.php',
        'pocketmine\\level\\generator\\object\\Pond' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/Pond.php',
        'pocketmine\\level\\generator\\object\\PopulatorObject' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/PopulatorObject.php',
        'pocketmine\\level\\generator\\object\\SpruceTree' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/SpruceTree.php',
        'pocketmine\\level\\generator\\object\\TallGrass' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/TallGrass.php',
        'pocketmine\\level\\generator\\object\\Tree' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/object/Tree.php',
        'pocketmine\\level\\generator\\populator\\GroundCover' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/populator/GroundCover.php',
        'pocketmine\\level\\generator\\populator\\Ore' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/populator/Ore.php',
        'pocketmine\\level\\generator\\populator\\Pond' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/populator/Pond.php',
        'pocketmine\\level\\generator\\populator\\Populator' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/populator/Populator.php',
        'pocketmine\\level\\generator\\populator\\TallGrass' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/populator/TallGrass.php',
        'pocketmine\\level\\generator\\populator\\Tree' => __DIR__ . '/../..' . '/src/pocketmine/level/generator/populator/Tree.php',
        'pocketmine\\level\\light\\BlockLightUpdate' => __DIR__ . '/../..' . '/src/pocketmine/level/light/BlockLightUpdate.php',
        'pocketmine\\level\\light\\LightPopulationTask' => __DIR__ . '/../..' . '/src/pocketmine/level/light/LightPopulationTask.php',
        'pocketmine\\level\\light\\LightUpdate' => __DIR__ . '/../..' . '/src/pocketmine/level/light/LightUpdate.php',
        'pocketmine\\level\\light\\SkyLightUpdate' => __DIR__ . '/../..' . '/src/pocketmine/level/light/SkyLightUpdate.php',
        'pocketmine\\level\\particle\\AngryVillagerParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/AngryVillagerParticle.php',
        'pocketmine\\level\\particle\\BlockForceFieldParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/BlockForceFieldParticle.php',
        'pocketmine\\level\\particle\\BubbleParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/BubbleParticle.php',
        'pocketmine\\level\\particle\\CriticalParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/CriticalParticle.php',
        'pocketmine\\level\\particle\\DestroyBlockParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/DestroyBlockParticle.php',
        'pocketmine\\level\\particle\\DustParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/DustParticle.php',
        'pocketmine\\level\\particle\\EnchantParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/EnchantParticle.php',
        'pocketmine\\level\\particle\\EnchantmentTableParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/EnchantmentTableParticle.php',
        'pocketmine\\level\\particle\\EntityFlameParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/EntityFlameParticle.php',
        'pocketmine\\level\\particle\\ExplodeParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/ExplodeParticle.php',
        'pocketmine\\level\\particle\\FlameParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/FlameParticle.php',
        'pocketmine\\level\\particle\\FloatingTextParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/FloatingTextParticle.php',
        'pocketmine\\level\\particle\\GenericParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/GenericParticle.php',
        'pocketmine\\level\\particle\\HappyVillagerParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/HappyVillagerParticle.php',
        'pocketmine\\level\\particle\\HeartParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/HeartParticle.php',
        'pocketmine\\level\\particle\\HugeExplodeParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/HugeExplodeParticle.php',
        'pocketmine\\level\\particle\\HugeExplodeSeedParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/HugeExplodeSeedParticle.php',
        'pocketmine\\level\\particle\\InkParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/InkParticle.php',
        'pocketmine\\level\\particle\\InstantEnchantParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/InstantEnchantParticle.php',
        'pocketmine\\level\\particle\\ItemBreakParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/ItemBreakParticle.php',
        'pocketmine\\level\\particle\\LavaDripParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/LavaDripParticle.php',
        'pocketmine\\level\\particle\\LavaParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/LavaParticle.php',
        'pocketmine\\level\\particle\\MobSpawnParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/MobSpawnParticle.php',
        'pocketmine\\level\\particle\\Particle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/Particle.php',
        'pocketmine\\level\\particle\\PortalParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/PortalParticle.php',
        'pocketmine\\level\\particle\\RainSplashParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/RainSplashParticle.php',
        'pocketmine\\level\\particle\\RedstoneParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/RedstoneParticle.php',
        'pocketmine\\level\\particle\\SmokeParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/SmokeParticle.php',
        'pocketmine\\level\\particle\\SnowballPoofParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/SnowballPoofParticle.php',
        'pocketmine\\level\\particle\\SplashParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/SplashParticle.php',
        'pocketmine\\level\\particle\\SporeParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/SporeParticle.php',
        'pocketmine\\level\\particle\\TerrainParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/TerrainParticle.php',
        'pocketmine\\level\\particle\\WaterDripParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/WaterDripParticle.php',
        'pocketmine\\level\\particle\\WaterParticle' => __DIR__ . '/../..' . '/src/pocketmine/level/particle/WaterParticle.php',
        'pocketmine\\level\\sound\\AnvilBreakSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/AnvilBreakSound.php',
        'pocketmine\\level\\sound\\AnvilFallSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/AnvilFallSound.php',
        'pocketmine\\level\\sound\\AnvilUseSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/AnvilUseSound.php',
        'pocketmine\\level\\sound\\BlazeShootSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/BlazeShootSound.php',
        'pocketmine\\level\\sound\\ClickSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/ClickSound.php',
        'pocketmine\\level\\sound\\DoorBumpSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/DoorBumpSound.php',
        'pocketmine\\level\\sound\\DoorCrashSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/DoorCrashSound.php',
        'pocketmine\\level\\sound\\DoorSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/DoorSound.php',
        'pocketmine\\level\\sound\\EndermanTeleportSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/EndermanTeleportSound.php',
        'pocketmine\\level\\sound\\FizzSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/FizzSound.php',
        'pocketmine\\level\\sound\\GenericSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/GenericSound.php',
        'pocketmine\\level\\sound\\GhastShootSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/GhastShootSound.php',
        'pocketmine\\level\\sound\\GhastSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/GhastSound.php',
        'pocketmine\\level\\sound\\LaunchSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/LaunchSound.php',
        'pocketmine\\level\\sound\\PopSound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/PopSound.php',
        'pocketmine\\level\\sound\\Sound' => __DIR__ . '/../..' . '/src/pocketmine/level/sound/Sound.php',
        'pocketmine\\level\\utils\\SubChunkIteratorManager' => __DIR__ . '/../..' . '/src/pocketmine/level/utils/SubChunkIteratorManager.php',
        'pocketmine\\math\\AxisAlignedBB' => __DIR__ . '/..' . '/pocketmine/math/src/AxisAlignedBB.php',
        'pocketmine\\math\\Math' => __DIR__ . '/..' . '/pocketmine/math/src/Math.php',
        'pocketmine\\math\\Matrix' => __DIR__ . '/..' . '/pocketmine/math/src/Matrix.php',
        'pocketmine\\math\\RayTraceResult' => __DIR__ . '/..' . '/pocketmine/math/src/RayTraceResult.php',
        'pocketmine\\math\\Vector2' => __DIR__ . '/..' . '/pocketmine/math/src/Vector2.php',
        'pocketmine\\math\\Vector3' => __DIR__ . '/..' . '/pocketmine/math/src/Vector3.php',
        'pocketmine\\math\\VectorMath' => __DIR__ . '/..' . '/pocketmine/math/src/VectorMath.php',
        'pocketmine\\math\\VoxelRayTrace' => __DIR__ . '/..' . '/pocketmine/math/src/VoxelRayTrace.php',
        'pocketmine\\metadata\\BlockMetadataStore' => __DIR__ . '/../..' . '/src/pocketmine/metadata/BlockMetadataStore.php',
        'pocketmine\\metadata\\EntityMetadataStore' => __DIR__ . '/../..' . '/src/pocketmine/metadata/EntityMetadataStore.php',
        'pocketmine\\metadata\\LevelMetadataStore' => __DIR__ . '/../..' . '/src/pocketmine/metadata/LevelMetadataStore.php',
        'pocketmine\\metadata\\MetadataStore' => __DIR__ . '/../..' . '/src/pocketmine/metadata/MetadataStore.php',
        'pocketmine\\metadata\\MetadataValue' => __DIR__ . '/../..' . '/src/pocketmine/metadata/MetadataValue.php',
        'pocketmine\\metadata\\Metadatable' => __DIR__ . '/../..' . '/src/pocketmine/metadata/Metadatable.php',
        'pocketmine\\metadata\\PlayerMetadataStore' => __DIR__ . '/../..' . '/src/pocketmine/metadata/PlayerMetadataStore.php',
        'pocketmine\\nbt\\BigEndianNBTStream' => __DIR__ . '/..' . '/pocketmine/nbt/src/BigEndianNBTStream.php',
        'pocketmine\\nbt\\JsonNbtParser' => __DIR__ . '/..' . '/pocketmine/nbt/src/JsonNbtParser.php',
        'pocketmine\\nbt\\LittleEndianNBTStream' => __DIR__ . '/..' . '/pocketmine/nbt/src/LittleEndianNBTStream.php',
        'pocketmine\\nbt\\NBT' => __DIR__ . '/..' . '/pocketmine/nbt/src/NBT.php',
        'pocketmine\\nbt\\NBTStream' => __DIR__ . '/..' . '/pocketmine/nbt/src/NBTStream.php',
        'pocketmine\\nbt\\NetworkLittleEndianNBTStream' => __DIR__ . '/..' . '/pocketmine/nbt/src/NetworkLittleEndianNBTStream.php',
        'pocketmine\\nbt\\ReaderTracker' => __DIR__ . '/..' . '/pocketmine/nbt/src/ReaderTracker.php',
        'pocketmine\\nbt\\tag\\ByteArrayTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/ByteArrayTag.php',
        'pocketmine\\nbt\\tag\\ByteTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/ByteTag.php',
        'pocketmine\\nbt\\tag\\CompoundTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/CompoundTag.php',
        'pocketmine\\nbt\\tag\\DoubleTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/DoubleTag.php',
        'pocketmine\\nbt\\tag\\FloatTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/FloatTag.php',
        'pocketmine\\nbt\\tag\\IntArrayTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/IntArrayTag.php',
        'pocketmine\\nbt\\tag\\IntTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/IntTag.php',
        'pocketmine\\nbt\\tag\\ListTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/ListTag.php',
        'pocketmine\\nbt\\tag\\LongTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/LongTag.php',
        'pocketmine\\nbt\\tag\\NamedTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/NamedTag.php',
        'pocketmine\\nbt\\tag\\NoDynamicFieldsTrait' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/NoDynamicFieldsTrait.php',
        'pocketmine\\nbt\\tag\\ShortTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/ShortTag.php',
        'pocketmine\\nbt\\tag\\StringTag' => __DIR__ . '/..' . '/pocketmine/nbt/src/tag/StringTag.php',
        'pocketmine\\network\\AdvancedSourceInterface' => __DIR__ . '/../..' . '/src/pocketmine/network/AdvancedSourceInterface.php',
        'pocketmine\\network\\CompressBatchedTask' => __DIR__ . '/../..' . '/src/pocketmine/network/CompressBatchedTask.php',
        'pocketmine\\network\\Network' => __DIR__ . '/../..' . '/src/pocketmine/network/Network.php',
        'pocketmine\\network\\SourceInterface' => __DIR__ . '/../..' . '/src/pocketmine/network/SourceInterface.php',
        'pocketmine\\network\\mcpe\\CachedEncapsulatedPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/CachedEncapsulatedPacket.php',
        'pocketmine\\network\\mcpe\\NetworkBinaryStream' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/NetworkBinaryStream.php',
        'pocketmine\\network\\mcpe\\NetworkSession' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/NetworkSession.php',
        'pocketmine\\network\\mcpe\\PlayerNetworkSessionAdapter' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php',
        'pocketmine\\network\\mcpe\\RakLibInterface' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/RakLibInterface.php',
        'pocketmine\\network\\mcpe\\VerifyLoginException' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/VerifyLoginException.php',
        'pocketmine\\network\\mcpe\\VerifyLoginTask' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/VerifyLoginTask.php',
        'pocketmine\\network\\mcpe\\protocol\\ActorEventPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ActorEventPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ActorFallPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ActorFallPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ActorPickRequestPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ActorPickRequestPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AddActorPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AddActorPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AddBehaviorTreePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AddBehaviorTreePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AddEntityPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AddEntityPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AddItemActorPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AddItemActorPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AddPaintingPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AddPaintingPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AddPlayerPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AddPlayerPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AdventureSettingsPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AdventureSettingsPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AnimatePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AnimatePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AnvilDamagePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AnvilDamagePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AutomationClientConnectPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AutomationClientConnectPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AvailableActorIdentifiersPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AvailableActorIdentifiersPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\AvailableCommandsPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\BatchPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/BatchPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\BiomeDefinitionListPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/BiomeDefinitionListPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\BlockActorDataPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/BlockActorDataPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\BlockEventPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/BlockEventPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\BlockPickRequestPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/BlockPickRequestPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\BookEditPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/BookEditPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\BossEventPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/BossEventPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\CameraPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/CameraPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ChangeDimensionPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ChangeDimensionPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ChunkRadiusUpdatedPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ChunkRadiusUpdatedPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ClientCacheBlobStatusPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ClientCacheBlobStatusPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ClientCacheMissResponsePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ClientCacheMissResponsePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ClientCacheStatusPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ClientCacheStatusPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ClientToServerHandshakePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ClientToServerHandshakePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ClientboundMapItemDataPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ClientboundMapItemDataPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\CommandBlockUpdatePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/CommandBlockUpdatePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\CommandOutputPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/CommandOutputPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\CommandRequestPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/CommandRequestPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\CompletedUsingItemPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/CompletedUsingItemPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ContainerClosePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ContainerClosePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ContainerOpenPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ContainerOpenPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ContainerSetDataPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ContainerSetDataPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\CraftingDataPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\CraftingEventPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/CraftingEventPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\DataPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/DataPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\DisconnectPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/DisconnectPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\EducationSettingsPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/EducationSettingsPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\EmotePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/EmotePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\EventPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/EventPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\GameRulesChangedPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/GameRulesChangedPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\GuiDataPickItemPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/GuiDataPickItemPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\HurtArmorPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/HurtArmorPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\InteractPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/InteractPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\InventoryContentPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/InventoryContentPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\InventorySlotPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/InventorySlotPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\InventoryTransactionPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/InventoryTransactionPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ItemFrameDropItemPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ItemFrameDropItemPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\LabTablePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/LabTablePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\LecternUpdatePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/LecternUpdatePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\LevelChunkPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\LevelEventGenericPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/LevelEventGenericPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\LevelEventPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/LevelEventPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\LevelSoundEventPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/LevelSoundEventPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\LevelSoundEventPacketV1' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/LevelSoundEventPacketV1.php',
        'pocketmine\\network\\mcpe\\protocol\\LevelSoundEventPacketV2' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/LevelSoundEventPacketV2.php',
        'pocketmine\\network\\mcpe\\protocol\\LoginPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/LoginPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\MapCreateLockedCopyPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/MapCreateLockedCopyPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\MapInfoRequestPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/MapInfoRequestPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\MobArmorEquipmentPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/MobArmorEquipmentPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\MobEffectPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/MobEffectPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\MobEquipmentPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/MobEquipmentPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ModalFormRequestPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ModalFormRequestPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ModalFormResponsePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ModalFormResponsePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\MoveActorAbsolutePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/MoveActorAbsolutePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\MoveActorDeltaPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/MoveActorDeltaPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\MovePlayerPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/MovePlayerPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\MultiplayerSettingsPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/MultiplayerSettingsPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\NetworkChunkPublisherUpdatePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/NetworkChunkPublisherUpdatePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\NetworkSettingsPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/NetworkSettingsPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\NetworkStackLatencyPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/NetworkStackLatencyPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\NpcRequestPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/NpcRequestPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\OnScreenTextureAnimationPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/OnScreenTextureAnimationPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\PacketPool' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PacketPool.php',
        'pocketmine\\network\\mcpe\\protocol\\PhotoTransferPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PhotoTransferPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\PlaySoundPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PlaySoundPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\PlayStatusPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PlayStatusPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\PlayerActionPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PlayerActionPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\PlayerAuthInputPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PlayerAuthInputPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\PlayerHotbarPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PlayerHotbarPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\PlayerInputPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PlayerInputPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\PlayerListPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PlayerListPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\PlayerSkinPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PlayerSkinPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ProtocolInfo' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php',
        'pocketmine\\network\\mcpe\\protocol\\PurchaseReceiptPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/PurchaseReceiptPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\RemoveActorPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/RemoveActorPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\RemoveEntityPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/RemoveEntityPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\RemoveObjectivePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/RemoveObjectivePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\RequestChunkRadiusPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/RequestChunkRadiusPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ResourcePackChunkDataPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ResourcePackChunkDataPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ResourcePackChunkRequestPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ResourcePackChunkRequestPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ResourcePackClientResponsePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ResourcePackClientResponsePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ResourcePackDataInfoPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ResourcePackDataInfoPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ResourcePackStackPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ResourcePackStackPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ResourcePacksInfoPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ResourcePacksInfoPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\RespawnPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/RespawnPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\RiderJumpPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/RiderJumpPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ScriptCustomEventPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ScriptCustomEventPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ServerSettingsRequestPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ServerSettingsRequestPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ServerSettingsResponsePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ServerSettingsResponsePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ServerToClientHandshakePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ServerToClientHandshakePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetActorDataPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetActorDataPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetActorLinkPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetActorLinkPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetActorMotionPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetActorMotionPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetCommandsEnabledPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetCommandsEnabledPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetDefaultGameTypePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetDefaultGameTypePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetDifficultyPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetDifficultyPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetDisplayObjectivePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetDisplayObjectivePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetHealthPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetHealthPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetLastHurtByPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetLastHurtByPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetLocalPlayerAsInitializedPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetLocalPlayerAsInitializedPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetPlayerGameTypePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetPlayerGameTypePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetScorePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetScorePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetScoreboardIdentityPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetScoreboardIdentityPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetSpawnPositionPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetSpawnPositionPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetTimePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetTimePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SetTitlePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SetTitlePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SettingsCommandPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SettingsCommandPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ShowCreditsPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ShowCreditsPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ShowProfilePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ShowProfilePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\ShowStoreOfferPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/ShowStoreOfferPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SimpleEventPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SimpleEventPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SpawnExperienceOrbPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SpawnExperienceOrbPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SpawnParticleEffectPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SpawnParticleEffectPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\StartGamePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/StartGamePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\StopSoundPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/StopSoundPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\StructureBlockUpdatePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/StructureBlockUpdatePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\StructureTemplateDataRequestPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/StructureTemplateDataRequestPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\StructureTemplateDataResponsePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/StructureTemplateDataResponsePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\SubClientLoginPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/SubClientLoginPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\TakeItemActorPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/TakeItemActorPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\TextPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/TextPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\TickSyncPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/TickSyncPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\TransferPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/TransferPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\UnknownPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/UnknownPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\UpdateAttributesPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/UpdateAttributesPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\UpdateBlockPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/UpdateBlockPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\UpdateBlockPropertiesPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/UpdateBlockPropertiesPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\UpdateBlockSyncedPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/UpdateBlockSyncedPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\UpdateEquipPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/UpdateEquipPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\UpdateSoftEnumPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/UpdateSoftEnumPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\UpdateTradePacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/UpdateTradePacket.php',
        'pocketmine\\network\\mcpe\\protocol\\VideoStreamConnectPacket' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/VideoStreamConnectPacket.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\ChunkCacheBlob' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/ChunkCacheBlob.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\CommandData' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/CommandData.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\CommandEnum' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/CommandEnum.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\CommandEnumConstraint' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/CommandEnumConstraint.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\CommandOriginData' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/CommandOriginData.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\CommandOutputMessage' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/CommandOutputMessage.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\CommandParameter' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\ContainerIds' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/ContainerIds.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\DimensionIds' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/DimensionIds.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\EntityLink' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/EntityLink.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\InputMode' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/InputMode.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\LegacySkinAdapter' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/LegacySkinAdapter.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\MapDecoration' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/MapDecoration.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\MapTrackedObject' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/MapTrackedObject.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\NetworkInventoryAction' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/NetworkInventoryAction.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\PlayMode' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/PlayMode.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\PlayerListEntry' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/PlayerListEntry.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\PlayerPermissions' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/PlayerPermissions.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\PotionContainerChangeRecipe' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/PotionContainerChangeRecipe.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\PotionTypeRecipe' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/PotionTypeRecipe.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\ResourcePackType' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/ResourcePackType.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\RuntimeBlockMapping' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\ScorePacketEntry' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/ScorePacketEntry.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\ScoreboardIdentityPacketEntry' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/ScoreboardIdentityPacketEntry.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\SkinAdapter' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/SkinAdapter.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\SkinAdapterSingleton' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/SkinAdapterSingleton.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\SkinAnimation' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/SkinAnimation.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\SkinData' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/SkinData.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\SkinImage' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/SkinImage.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\StructureSettings' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/StructureSettings.php',
        'pocketmine\\network\\mcpe\\protocol\\types\\WindowTypes' => __DIR__ . '/../..' . '/src/pocketmine/network/mcpe/protocol/types/WindowTypes.php',
        'pocketmine\\network\\query\\QueryHandler' => __DIR__ . '/../..' . '/src/pocketmine/network/query/QueryHandler.php',
        'pocketmine\\network\\rcon\\RCON' => __DIR__ . '/../..' . '/src/pocketmine/network/rcon/RCON.php',
        'pocketmine\\network\\rcon\\RCONInstance' => __DIR__ . '/../..' . '/src/pocketmine/network/rcon/RCONInstance.php',
        'pocketmine\\network\\upnp\\UPnP' => __DIR__ . '/../..' . '/src/pocketmine/network/upnp/UPnP.php',
        'pocketmine\\permission\\BanEntry' => __DIR__ . '/../..' . '/src/pocketmine/permission/BanEntry.php',
        'pocketmine\\permission\\BanList' => __DIR__ . '/../..' . '/src/pocketmine/permission/BanList.php',
        'pocketmine\\permission\\DefaultPermissions' => __DIR__ . '/../..' . '/src/pocketmine/permission/DefaultPermissions.php',
        'pocketmine\\permission\\Permissible' => __DIR__ . '/../..' . '/src/pocketmine/permission/Permissible.php',
        'pocketmine\\permission\\PermissibleBase' => __DIR__ . '/../..' . '/src/pocketmine/permission/PermissibleBase.php',
        'pocketmine\\permission\\Permission' => __DIR__ . '/../..' . '/src/pocketmine/permission/Permission.php',
        'pocketmine\\permission\\PermissionAttachment' => __DIR__ . '/../..' . '/src/pocketmine/permission/PermissionAttachment.php',
        'pocketmine\\permission\\PermissionAttachmentInfo' => __DIR__ . '/../..' . '/src/pocketmine/permission/PermissionAttachmentInfo.php',
        'pocketmine\\permission\\PermissionManager' => __DIR__ . '/../..' . '/src/pocketmine/permission/PermissionManager.php',
        'pocketmine\\permission\\PermissionRemovedExecutor' => __DIR__ . '/../..' . '/src/pocketmine/permission/PermissionRemovedExecutor.php',
        'pocketmine\\permission\\ServerOperator' => __DIR__ . '/../..' . '/src/pocketmine/permission/ServerOperator.php',
        'pocketmine\\plugin\\EventExecutor' => __DIR__ . '/../..' . '/src/pocketmine/plugin/EventExecutor.php',
        'pocketmine\\plugin\\MethodEventExecutor' => __DIR__ . '/../..' . '/src/pocketmine/plugin/MethodEventExecutor.php',
        'pocketmine\\plugin\\PharPluginLoader' => __DIR__ . '/../..' . '/src/pocketmine/plugin/PharPluginLoader.php',
        'pocketmine\\plugin\\Plugin' => __DIR__ . '/../..' . '/src/pocketmine/plugin/Plugin.php',
        'pocketmine\\plugin\\PluginBase' => __DIR__ . '/../..' . '/src/pocketmine/plugin/PluginBase.php',
        'pocketmine\\plugin\\PluginDescription' => __DIR__ . '/../..' . '/src/pocketmine/plugin/PluginDescription.php',
        'pocketmine\\plugin\\PluginException' => __DIR__ . '/../..' . '/src/pocketmine/plugin/PluginException.php',
        'pocketmine\\plugin\\PluginLoadOrder' => __DIR__ . '/../..' . '/src/pocketmine/plugin/PluginLoadOrder.php',
        'pocketmine\\plugin\\PluginLoader' => __DIR__ . '/../..' . '/src/pocketmine/plugin/PluginLoader.php',
        'pocketmine\\plugin\\PluginLogger' => __DIR__ . '/../..' . '/src/pocketmine/plugin/PluginLogger.php',
        'pocketmine\\plugin\\PluginManager' => __DIR__ . '/../..' . '/src/pocketmine/plugin/PluginManager.php',
        'pocketmine\\plugin\\RegisteredListener' => __DIR__ . '/../..' . '/src/pocketmine/plugin/RegisteredListener.php',
        'pocketmine\\plugin\\ScriptPluginLoader' => __DIR__ . '/../..' . '/src/pocketmine/plugin/ScriptPluginLoader.php',
        'pocketmine\\resourcepacks\\ResourcePack' => __DIR__ . '/../..' . '/src/pocketmine/resourcepacks/ResourcePack.php',
        'pocketmine\\resourcepacks\\ResourcePackException' => __DIR__ . '/../..' . '/src/pocketmine/resourcepacks/ResourcePackException.php',
        'pocketmine\\resourcepacks\\ResourcePackInfoEntry' => __DIR__ . '/../..' . '/src/pocketmine/resourcepacks/ResourcePackInfoEntry.php',
        'pocketmine\\resourcepacks\\ResourcePackManager' => __DIR__ . '/../..' . '/src/pocketmine/resourcepacks/ResourcePackManager.php',
        'pocketmine\\resourcepacks\\ZippedResourcePack' => __DIR__ . '/../..' . '/src/pocketmine/resourcepacks/ZippedResourcePack.php',
        'pocketmine\\scheduler\\AsyncPool' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/AsyncPool.php',
        'pocketmine\\scheduler\\AsyncTask' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/AsyncTask.php',
        'pocketmine\\scheduler\\AsyncWorker' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/AsyncWorker.php',
        'pocketmine\\scheduler\\BulkCurlTask' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/BulkCurlTask.php',
        'pocketmine\\scheduler\\ClosureTask' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/ClosureTask.php',
        'pocketmine\\scheduler\\DumpWorkerMemoryTask' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/DumpWorkerMemoryTask.php',
        'pocketmine\\scheduler\\FileWriteTask' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/FileWriteTask.php',
        'pocketmine\\scheduler\\GarbageCollectionTask' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/GarbageCollectionTask.php',
        'pocketmine\\scheduler\\SendUsageTask' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/SendUsageTask.php',
        'pocketmine\\scheduler\\Task' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/Task.php',
        'pocketmine\\scheduler\\TaskHandler' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/TaskHandler.php',
        'pocketmine\\scheduler\\TaskScheduler' => __DIR__ . '/../..' . '/src/pocketmine/scheduler/TaskScheduler.php',
        'pocketmine\\snooze\\SleeperHandler' => __DIR__ . '/..' . '/pocketmine/snooze/src/SleeperHandler.php',
        'pocketmine\\snooze\\SleeperNotifier' => __DIR__ . '/..' . '/pocketmine/snooze/src/SleeperNotifier.php',
        'pocketmine\\snooze\\ThreadedSleeper' => __DIR__ . '/..' . '/pocketmine/snooze/src/ThreadedSleeper.php',
        'pocketmine\\tile\\Banner' => __DIR__ . '/../..' . '/src/pocketmine/tile/Banner.php',
        'pocketmine\\tile\\Bed' => __DIR__ . '/../..' . '/src/pocketmine/tile/Bed.php',
        'pocketmine\\tile\\Chest' => __DIR__ . '/../..' . '/src/pocketmine/tile/Chest.php',
        'pocketmine\\tile\\Container' => __DIR__ . '/../..' . '/src/pocketmine/tile/Container.php',
        'pocketmine\\tile\\ContainerTrait' => __DIR__ . '/../..' . '/src/pocketmine/tile/ContainerTrait.php',
        'pocketmine\\tile\\EnchantTable' => __DIR__ . '/../..' . '/src/pocketmine/tile/EnchantTable.php',
        'pocketmine\\tile\\EnderChest' => __DIR__ . '/../..' . '/src/pocketmine/tile/EnderChest.php',
        'pocketmine\\tile\\FlowerPot' => __DIR__ . '/../..' . '/src/pocketmine/tile/FlowerPot.php',
        'pocketmine\\tile\\Furnace' => __DIR__ . '/../..' . '/src/pocketmine/tile/Furnace.php',
        'pocketmine\\tile\\ItemFrame' => __DIR__ . '/../..' . '/src/pocketmine/tile/ItemFrame.php',
        'pocketmine\\tile\\Nameable' => __DIR__ . '/../..' . '/src/pocketmine/tile/Nameable.php',
        'pocketmine\\tile\\NameableTrait' => __DIR__ . '/../..' . '/src/pocketmine/tile/NameableTrait.php',
        'pocketmine\\tile\\Sign' => __DIR__ . '/../..' . '/src/pocketmine/tile/Sign.php',
        'pocketmine\\tile\\Skull' => __DIR__ . '/../..' . '/src/pocketmine/tile/Skull.php',
        'pocketmine\\tile\\Spawnable' => __DIR__ . '/../..' . '/src/pocketmine/tile/Spawnable.php',
        'pocketmine\\tile\\Tile' => __DIR__ . '/../..' . '/src/pocketmine/tile/Tile.php',
        'pocketmine\\timings\\Timings' => __DIR__ . '/../..' . '/src/pocketmine/timings/Timings.php',
        'pocketmine\\timings\\TimingsHandler' => __DIR__ . '/../..' . '/src/pocketmine/timings/TimingsHandler.php',
        'pocketmine\\updater\\AutoUpdater' => __DIR__ . '/../..' . '/src/pocketmine/updater/AutoUpdater.php',
        'pocketmine\\updater\\UpdateCheckTask' => __DIR__ . '/../..' . '/src/pocketmine/updater/UpdateCheckTask.php',
        'pocketmine\\utils\\Binary' => __DIR__ . '/..' . '/pocketmine/binaryutils/src/Binary.php',
        'pocketmine\\utils\\BinaryDataException' => __DIR__ . '/..' . '/pocketmine/binaryutils/src/BinaryDataException.php',
        'pocketmine\\utils\\BinaryStream' => __DIR__ . '/..' . '/pocketmine/binaryutils/src/BinaryStream.php',
        'pocketmine\\utils\\Color' => __DIR__ . '/../..' . '/src/pocketmine/utils/Color.php',
        'pocketmine\\utils\\Config' => __DIR__ . '/../..' . '/src/pocketmine/utils/Config.php',
        'pocketmine\\utils\\Git' => __DIR__ . '/../..' . '/src/pocketmine/utils/Git.php',
        'pocketmine\\utils\\Internet' => __DIR__ . '/../..' . '/src/pocketmine/utils/Internet.php',
        'pocketmine\\utils\\InternetException' => __DIR__ . '/../..' . '/src/pocketmine/utils/InternetException.php',
        'pocketmine\\utils\\MainLogger' => __DIR__ . '/../..' . '/src/pocketmine/utils/MainLogger.php',
        'pocketmine\\utils\\Random' => __DIR__ . '/../..' . '/src/pocketmine/utils/Random.php',
        'pocketmine\\utils\\ReversePriorityQueue' => __DIR__ . '/../..' . '/src/pocketmine/utils/ReversePriorityQueue.php',
        'pocketmine\\utils\\ServerException' => __DIR__ . '/../..' . '/src/pocketmine/utils/ServerException.php',
        'pocketmine\\utils\\ServerKiller' => __DIR__ . '/../..' . '/src/pocketmine/utils/ServerKiller.php',
        'pocketmine\\utils\\Terminal' => __DIR__ . '/../..' . '/src/pocketmine/utils/Terminal.php',
        'pocketmine\\utils\\TextFormat' => __DIR__ . '/../..' . '/src/pocketmine/utils/TextFormat.php',
        'pocketmine\\utils\\Timezone' => __DIR__ . '/../..' . '/src/pocketmine/utils/Timezone.php',
        'pocketmine\\utils\\UUID' => __DIR__ . '/../..' . '/src/pocketmine/utils/UUID.php',
        'pocketmine\\utils\\Utils' => __DIR__ . '/../..' . '/src/pocketmine/utils/Utils.php',
        'pocketmine\\utils\\VersionString' => __DIR__ . '/../..' . '/src/pocketmine/utils/VersionString.php',
        'pocketmine\\wizard\\SetupWizard' => __DIR__ . '/../..' . '/src/pocketmine/wizard/SetupWizard.php',
        'raklib\\RakLib' => __DIR__ . '/..' . '/pocketmine/raklib/src/RakLib.php',
        'raklib\\protocol\\ACK' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/ACK.php',
        'raklib\\protocol\\AcknowledgePacket' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/AcknowledgePacket.php',
        'raklib\\protocol\\AdvertiseSystem' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/AdvertiseSystem.php',
        'raklib\\protocol\\ConnectedPing' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/ConnectedPing.php',
        'raklib\\protocol\\ConnectedPong' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/ConnectedPong.php',
        'raklib\\protocol\\ConnectionRequest' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/ConnectionRequest.php',
        'raklib\\protocol\\ConnectionRequestAccepted' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/ConnectionRequestAccepted.php',
        'raklib\\protocol\\Datagram' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/Datagram.php',
        'raklib\\protocol\\DisconnectionNotification' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/DisconnectionNotification.php',
        'raklib\\protocol\\EncapsulatedPacket' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/EncapsulatedPacket.php',
        'raklib\\protocol\\IncompatibleProtocolVersion' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/IncompatibleProtocolVersion.php',
        'raklib\\protocol\\MessageIdentifiers' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/MessageIdentifiers.php',
        'raklib\\protocol\\NACK' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/NACK.php',
        'raklib\\protocol\\NewIncomingConnection' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/NewIncomingConnection.php',
        'raklib\\protocol\\OfflineMessage' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/OfflineMessage.php',
        'raklib\\protocol\\OpenConnectionReply1' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/OpenConnectionReply1.php',
        'raklib\\protocol\\OpenConnectionReply2' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/OpenConnectionReply2.php',
        'raklib\\protocol\\OpenConnectionRequest1' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/OpenConnectionRequest1.php',
        'raklib\\protocol\\OpenConnectionRequest2' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/OpenConnectionRequest2.php',
        'raklib\\protocol\\Packet' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/Packet.php',
        'raklib\\protocol\\PacketReliability' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/PacketReliability.php',
        'raklib\\protocol\\UnconnectedPing' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/UnconnectedPing.php',
        'raklib\\protocol\\UnconnectedPingOpenConnections' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/UnconnectedPingOpenConnections.php',
        'raklib\\protocol\\UnconnectedPong' => __DIR__ . '/..' . '/pocketmine/raklib/src/protocol/UnconnectedPong.php',
        'raklib\\server\\OfflineMessageHandler' => __DIR__ . '/..' . '/pocketmine/raklib/src/server/OfflineMessageHandler.php',
        'raklib\\server\\RakLibServer' => __DIR__ . '/..' . '/pocketmine/raklib/src/server/RakLibServer.php',
        'raklib\\server\\ServerHandler' => __DIR__ . '/..' . '/pocketmine/raklib/src/server/ServerHandler.php',
        'raklib\\server\\ServerInstance' => __DIR__ . '/..' . '/pocketmine/raklib/src/server/ServerInstance.php',
        'raklib\\server\\Session' => __DIR__ . '/..' . '/pocketmine/raklib/src/server/Session.php',
        'raklib\\server\\SessionManager' => __DIR__ . '/..' . '/pocketmine/raklib/src/server/SessionManager.php',
        'raklib\\server\\UDPServerSocket' => __DIR__ . '/..' . '/pocketmine/raklib/src/server/UDPServerSocket.php',
        'raklib\\utils\\InternetAddress' => __DIR__ . '/..' . '/pocketmine/raklib/src/utils/InternetAddress.php',
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInit2465bc1320a965a378e5f39bc0181113::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInit2465bc1320a965a378e5f39bc0181113::$prefixDirsPsr4;
            $loader->fallbackDirsPsr4 = ComposerStaticInit2465bc1320a965a378e5f39bc0181113::$fallbackDirsPsr4;
            $loader->classMap = ComposerStaticInit2465bc1320a965a378e5f39bc0181113::$classMap;

        }, null, ClassLoader::class);
    }
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine;

// composer autoload doesn't use require_once and also pthreads can inherit things
if(defined('pocketmine\_CORE_CONSTANTS_INCLUDED')){
	return;
}
define('pocketmine\_CORE_CONSTANTS_INCLUDED', true);

define('pocketmine\PATH', dirname(__DIR__, 2) . '/');
define('pocketmine\RESOURCE_PATH', __DIR__ . '/resources/');
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

// composer autoload doesn't use require_once and also pthreads can inherit things
if(defined('pocketmine\_GLOBAL_CONSTANTS_INCLUDED')){
	return;
}
define('pocketmine\_GLOBAL_CONSTANTS_INCLUDED', true);

const INT32_MIN = -0x80000000;
const INT32_MAX = 0x7fffffff;
const INT32_MASK = 0xffffffff;
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Various Utilities used around the code
 */

namespace pocketmine\utils;

use DaveRandom\CallbackValidator\CallbackType;
use pocketmine\ThreadManager;
use function array_combine;
use function array_map;
use function array_reverse;
use function array_values;
use function base64_decode;
use function bin2hex;
use function chunk_split;
use function count;
use function debug_zval_dump;
use function dechex;
use function error_reporting;
use function exec;
use function explode;
use function fclose;
use function file;
use function file_exists;
use function file_get_contents;
use function function_exists;
use function get_current_user;
use function get_loaded_extensions;
use function getenv;
use function gettype;
use function hexdec;
use function implode;
use function is_array;
use function is_object;
use function is_readable;
use function is_string;
use function json_decode;
use function ltrim;
use function memory_get_usage;
use function ob_end_clean;
use function ob_get_contents;
use function ob_start;
use function ord;
use function php_uname;
use function phpversion;
use function posix_kill;
use function preg_grep;
use function preg_match;
use function preg_match_all;
use function preg_replace;
use function proc_close;
use function proc_open;
use function rtrim;
use function sha1;
use function spl_object_hash;
use function str_pad;
use function str_replace;
use function str_split;
use function stream_get_contents;
use function stripos;
use function strlen;
use function strpos;
use function strtolower;
use function strtr;
use function substr;
use function sys_get_temp_dir;
use function trim;
use function xdebug_get_function_stack;
use const PHP_EOL;
use const PHP_INT_MAX;
use const PHP_INT_SIZE;
use const PHP_MAXPATHLEN;
use const STR_PAD_LEFT;
use const STR_PAD_RIGHT;

/**
 * Big collection of functions
 */
class Utils{
	/** @var string|null */
	public static $os;
	/** @var UUID|null */
	private static $serverUniqueId = null;

	/**
	 * Generates an unique identifier to a callable
	 *
	 * @return string
	 */
	public static function getCallableIdentifier(callable $variable){
		if(is_array($variable)){
			return sha1(strtolower(spl_object_hash($variable[0])) . "::" . strtolower($variable[1]));
		}else{
			return sha1(strtolower($variable));
		}
	}

	/**
	 * Returns a readable identifier for the given Closure, including file and line.
	 *
	 * @throws \ReflectionException
	 */
	public static function getNiceClosureName(\Closure $closure) : string{
		$func = new \ReflectionFunction($closure);
		if(substr($func->getName(), -strlen('{closure}')) !== '{closure}'){
			//closure wraps a named function, can be done with reflection or fromCallable()
			//isClosure() is useless here because it just tells us if $func is reflecting a Closure object

			$scope = $func->getClosureScopeClass();
			if($scope !== null){ //class method
				return
					$scope->getName() .
					($func->getClosureThis() !== null ? "->" : "::") .
					$func->getName(); //name doesn't include class in this case
			}

			//non-class function
			return $func->getName();
		}
		return "closure@" . self::cleanPath($func->getFileName()) . "#L" . $func->getStartLine();
	}

	/**
	 * Returns a readable identifier for the class of the given object. Sanitizes class names for anonymous classes.
	 *
	 * @throws \ReflectionException
	 */
	public static function getNiceClassName(object $obj) : string{
		$reflect = new \ReflectionClass($obj);
		if($reflect->isAnonymous()){
			return "anonymous@" . self::cleanPath($reflect->getFileName()) . "#L" . $reflect->getStartLine();
		}

		return $reflect->getName();
	}

	/**
	 * Gets this machine / server instance unique ID
	 * Returns a hash, the first 32 characters (or 16 if raw)
	 * will be an identifier that won't change frequently.
	 * The rest of the hash will change depending on other factors.
	 *
	 * @param string $extra optional, additional data to identify the machine
	 */
	public static function getMachineUniqueId(string $extra = "") : UUID{
		if(self::$serverUniqueId !== null and $extra === ""){
			return self::$serverUniqueId;
		}

		$machine = php_uname("a");
		$machine .= file_exists("/proc/cpuinfo") ? implode(preg_grep("/(model name|Processor|Serial)/", file("/proc/cpuinfo"))) : "";
		$machine .= sys_get_temp_dir();
		$machine .= $extra;
		$os = Utils::getOS();
		if($os === "win"){
			@exec("ipconfig /ALL", $mac);
			$mac = implode("\n", $mac);
			if(preg_match_all("#Physical Address[. ]{1,}: ([0-9A-F\\-]{17})#", $mac, $matches)){
				foreach($matches[1] as $i => $v){
					if($v == "00-00-00-00-00-00"){
						unset($matches[1][$i]);
					}
				}
				$machine .= implode(" ", $matches[1]); //Mac Addresses
			}
		}elseif($os === "linux"){
			if(file_exists("/etc/machine-id")){
				$machine .= file_get_contents("/etc/machine-id");
			}else{
				@exec("ifconfig 2>/dev/null", $mac);
				$mac = implode("\n", $mac);
				if(preg_match_all("#HWaddr[ \t]{1,}([0-9a-f:]{17})#", $mac, $matches)){
					foreach($matches[1] as $i => $v){
						if($v == "00:00:00:00:00:00"){
							unset($matches[1][$i]);
						}
					}
					$machine .= implode(" ", $matches[1]); //Mac Addresses
				}
			}
		}elseif($os === "android"){
			$machine .= @file_get_contents("/system/build.prop");
		}elseif($os === "mac"){
			$machine .= `system_profiler SPHardwareDataType | grep UUID`;
		}
		$data = $machine . PHP_MAXPATHLEN;
		$data .= PHP_INT_MAX;
		$data .= PHP_INT_SIZE;
		$data .= get_current_user();
		foreach(get_loaded_extensions() as $ext){
			$data .= $ext . ":" . phpversion($ext);
		}

		$uuid = UUID::fromData($machine, $data);

		if($extra === ""){
			self::$serverUniqueId = $uuid;
		}

		return $uuid;
	}

	/**
	 * @deprecated
	 * @see Internet::getIP()
	 *
	 * @param bool $force default false, force IP check even when cached
	 *
	 * @return string|bool
	 */
	public static function getIP(bool $force = false){
		return Internet::getIP($force);
	}

	/**
	 * Returns the current Operating System
	 * Windows => win
	 * MacOS => mac
	 * iOS => ios
	 * Android => android
	 * Linux => Linux
	 * BSD => bsd
	 * Other => other
	 */
	public static function getOS(bool $recalculate = false) : string{
		if(self::$os === null or $recalculate){
			$uname = php_uname("s");
			if(stripos($uname, "Darwin") !== false){
				if(strpos(php_uname("m"), "iP") === 0){
					self::$os = "ios";
				}else{
					self::$os = "mac";
				}
			}elseif(stripos($uname, "Win") !== false or $uname === "Msys"){
				self::$os = "win";
			}elseif(stripos($uname, "Linux") !== false){
				if(@file_exists("/system/build.prop")){
					self::$os = "android";
				}else{
					self::$os = "linux";
				}
			}elseif(stripos($uname, "BSD") !== false or $uname === "DragonFly"){
				self::$os = "bsd";
			}else{
				self::$os = "other";
			}
		}

		return self::$os;
	}

	/**
	 * @return int[]
	 */
	public static function getRealMemoryUsage() : array{
		$stack = 0;
		$heap = 0;

		if(Utils::getOS() === "linux" or Utils::getOS() === "android"){
			$mappings = file("/proc/self/maps");
			foreach($mappings as $line){
				if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){
					if(strpos($matches[3], "heap") === 0){
						$heap += hexdec($matches[2]) - hexdec($matches[1]);
					}elseif(strpos($matches[3], "stack") === 0){
						$stack += hexdec($matches[2]) - hexdec($matches[1]);
					}
				}
			}
		}

		return [$heap, $stack];
	}

	/**
	 * @return int[]|int
	 */
	public static function getMemoryUsage(bool $advanced = false){
		$reserved = memory_get_usage();
		$VmSize = null;
		$VmRSS = null;
		if(Utils::getOS() === "linux" or Utils::getOS() === "android"){
			$status = file_get_contents("/proc/self/status");
			if(preg_match("/VmRSS:[ \t]+([0-9]+) kB/", $status, $matches) > 0){
				$VmRSS = $matches[1] * 1024;
			}

			if(preg_match("/VmSize:[ \t]+([0-9]+) kB/", $status, $matches) > 0){
				$VmSize = $matches[1] * 1024;
			}
		}

		//TODO: more OS

		if($VmRSS === null){
			$VmRSS = memory_get_usage();
		}

		if(!$advanced){
			return $VmRSS;
		}

		if($VmSize === null){
			$VmSize = memory_get_usage(true);
		}

		return [$reserved, $VmRSS, $VmSize];
	}

	public static function getThreadCount() : int{
		if(Utils::getOS() === "linux" or Utils::getOS() === "android"){
			if(preg_match("/Threads:[ \t]+([0-9]+)/", file_get_contents("/proc/self/status"), $matches) > 0){
				return (int) $matches[1];
			}
		}
		//TODO: more OS

		return count(ThreadManager::getInstance()->getAll()) + 3; //RakLib + MainLogger + Main Thread
	}

	public static function getCoreCount(bool $recalculate = false) : int{
		static $processors = 0;

		if($processors > 0 and !$recalculate){
			return $processors;
		}else{
			$processors = 0;
		}

		switch(Utils::getOS()){
			case "linux":
			case "android":
				if(file_exists("/proc/cpuinfo")){
					foreach(file("/proc/cpuinfo") as $l){
						if(preg_match('/^processor[ \t]*:[ \t]*[0-9]+$/m', $l) > 0){
							++$processors;
						}
					}
				}elseif(is_readable("/sys/devices/system/cpu/present")){
					if(preg_match("/^([0-9]+)\\-([0-9]+)$/", trim(file_get_contents("/sys/devices/system/cpu/present")), $matches) > 0){
						$processors = (int) ($matches[2] - $matches[1]);
					}
				}
				break;
			case "bsd":
			case "mac":
				$processors = (int) `sysctl -n hw.ncpu`;
				break;
			case "win":
				$processors = (int) getenv("NUMBER_OF_PROCESSORS");
				break;
		}
		return $processors;
	}

	/**
	 * Returns a prettified hexdump
	 */
	public static function hexdump(string $bin) : string{
		$output = "";
		$bin = str_split($bin, 16);
		foreach($bin as $counter => $line){
			$hex = chunk_split(chunk_split(str_pad(bin2hex($line), 32, " ", STR_PAD_RIGHT), 2, " "), 24, " ");
			$ascii = preg_replace('#([^\x20-\x7E])#', ".", $line);
			$output .= str_pad(dechex($counter << 4), 4, "0", STR_PAD_LEFT) . "  " . $hex . " " . $ascii . PHP_EOL;
		}

		return $output;
	}

	/**
	 * Returns a string that can be printed, replaces non-printable characters
	 *
	 * @param mixed $str
	 */
	public static function printable($str) : string{
		if(!is_string($str)){
			return gettype($str);
		}

		return preg_replace('#([^\x20-\x7E])#', '.', $str);
	}

	/*
	public static function angle3D($pos1, $pos2){
		$X = $pos1["x"] - $pos2["x"];
		$Z = $pos1["z"] - $pos2["z"];
		$dXZ = sqrt(pow($X, 2) + pow($Z, 2));
		$Y = $pos1["y"] - $pos2["y"];
		$hAngle = rad2deg(atan2($Z, $X) - M_PI_2);
		$vAngle = rad2deg(-atan2($Y, $dXZ));

		return array("yaw" => $hAngle, "pitch" => $vAngle);
	}*/

	/**
	 * @deprecated
	 * @see Internet::getURL()
	 *
	 * @param int      $timeout default 10
	 * @param string[] $extraHeaders
	 * @param string   $err reference parameter, will be set to the output of curl_error(). Use this to retrieve errors that occured during the operation.
	 * @param string[] $headers reference parameter
	 * @param int      $httpCode reference parameter
	 * @phpstan-param list<string>          $extraHeaders
	 * @phpstan-param array<string, string> $headers
	 *
	 * @return string|false
	 */
	public static function getURL(string $page, int $timeout = 10, array $extraHeaders = [], &$err = null, &$headers = null, &$httpCode = null){
		return Internet::getURL($page, $timeout, $extraHeaders, $err, $headers, $httpCode);
	}

	/**
	 * @deprecated
	 * @see Internet::postURL()
	 *
	 * @param string[]|string $args
	 * @param string[]        $extraHeaders
	 * @param string          $err reference parameter, will be set to the output of curl_error(). Use this to retrieve errors that occured during the operation.
	 * @param string[]        $headers reference parameter
	 * @param int             $httpCode reference parameter
	 * @phpstan-param string|array<string, string> $args
	 * @phpstan-param list<string>                 $extraHeaders
	 * @phpstan-param array<string, string>        $headers
	 *
	 * @return string|false
	 */
	public static function postURL(string $page, $args, int $timeout = 10, array $extraHeaders = [], &$err = null, &$headers = null, &$httpCode = null){
		return Internet::postURL($page, $args, $timeout, $extraHeaders, $err, $headers, $httpCode);
	}

	/**
	 * @deprecated
	 * @see Internet::simpleCurl()
	 *
	 * @param float|int     $timeout      The maximum connect timeout and timeout in seconds, correct to ms.
	 * @param string[]      $extraHeaders extra headers to send as a plain string array
	 * @param array         $extraOpts    extra CURLOPT_* to set as an [opt => value] map
	 * @param callable|null $onSuccess    function to be called if there is no error. Accepts a resource argument as the cURL handle.
	 * @phpstan-param array<int, mixed>                $extraOpts
	 * @phpstan-param list<string>                     $extraHeaders
	 * @phpstan-param (callable(resource) : void)|null $onSuccess
	 *
	 * @return array a plain array of three [result body : string, headers : string[][], HTTP response code : int]. Headers are grouped by requests with strtolower(header name) as keys and header value as values
	 * @phpstan-return array{string, list<array<string, string>>, int}
	 *
	 * @throws \RuntimeException if a cURL error occurs
	 */
	public static function simpleCurl(string $page, $timeout = 10, array $extraHeaders = [], array $extraOpts = [], callable $onSuccess = null){
		return Internet::simpleCurl($page, $timeout, $extraHeaders, $extraOpts, $onSuccess);
	}

	public static function javaStringHash(string $string) : int{
		$hash = 0;
		for($i = 0, $len = strlen($string); $i < $len; $i++){
			$ord = ord($string[$i]);
			if(($ord & 0x80) !== 0){
				$ord -= 0x100;
			}
			$hash = 31 * $hash + $ord;
			while($hash > 0x7FFFFFFF){
				$hash -= 0x100000000;
			}
			while($hash < -0x80000000){
				$hash += 0x100000000;
			}
			$hash &= 0xFFFFFFFF;
		}
		return $hash;
	}

	/**
	 * @param string      $command Command to execute
	 * @param string|null $stdout Reference parameter to write stdout to
	 * @param string|null $stderr Reference parameter to write stderr to
	 *
	 * @return int process exit code
	 */
	public static function execute(string $command, string &$stdout = null, string &$stderr = null) : int{
		$process = proc_open($command, [
			["pipe", "r"],
			["pipe", "w"],
			["pipe", "w"]
		], $pipes);

		if($process === false){
			$stderr = "Failed to open process";
			$stdout = "";

			return -1;
		}

		$stdout = stream_get_contents($pipes[1]);
		$stderr = stream_get_contents($pipes[2]);

		foreach($pipes as $p){
			fclose($p);
		}

		return proc_close($process);
	}

	/**
	 * @return mixed[]
	 * @phpstan-return array<string, mixed>
	 */
	public static function decodeJWT(string $token) : array{
		list($headB64, $payloadB64, $sigB64) = explode(".", $token);

		return json_decode(base64_decode(strtr($payloadB64, '-_', '+/'), true), true);
	}

	/**
	 * @param int $pid
	 */
	public static function kill($pid) : void{
		if(MainLogger::isRegisteredStatic()){
			MainLogger::getLogger()->syncFlushBuffer();
		}
		switch(Utils::getOS()){
			case "win":
				exec("taskkill.exe /F /PID $pid > NUL");
				break;
			case "mac":
			case "linux":
			default:
				if(function_exists("posix_kill")){
					posix_kill($pid, 9); //SIGKILL
				}else{
					exec("kill -9 $pid > /dev/null 2>&1");
				}
		}
	}

	/**
	 * @param object $value
	 *
	 * @return int
	 */
	public static function getReferenceCount($value, bool $includeCurrent = true){
		ob_start();
		debug_zval_dump($value);
		$ret = explode("\n", ob_get_contents());
		ob_end_clean();

		if(count($ret) >= 1 and preg_match('/^.* refcount\\(([0-9]+)\\)\\{$/', trim($ret[0]), $m) > 0){
			return ((int) $m[1]) - ($includeCurrent ? 3 : 4); //$value + zval call + extra call
		}
		return -1;
	}

	/**
	 * @param mixed[][] $trace
	 * @phpstan-param list<array<string, mixed>> $trace
	 *
	 * @return string[]
	 */
	public static function printableTrace(array $trace, int $maxStringLength = 80) : array{
		$messages = [];
		for($i = 0; isset($trace[$i]); ++$i){
			$params = "";
			if(isset($trace[$i]["args"]) or isset($trace[$i]["params"])){
				if(isset($trace[$i]["args"])){
					$args = $trace[$i]["args"];
				}else{
					$args = $trace[$i]["params"];
				}

				$params = implode(", ", array_map(function($value) use($maxStringLength) : string{
					if(is_object($value)){
						return "object " . self::getNiceClassName($value);
					}
					if(is_array($value)){
						return "array[" . count($value) . "]";
					}
					if(is_string($value)){
						return "string[" . strlen($value) . "] " . substr(Utils::printable($value), 0, $maxStringLength);
					}
					return gettype($value) . " " . Utils::printable((string) $value);
				}, $args));
			}
			$messages[] = "#$i " . (isset($trace[$i]["file"]) ? self::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($params) . ")";
		}
		return $messages;
	}

	/**
	 * @return mixed[][]
	 * @phpstan-return list<array<string, mixed>>
	 */
	public static function currentTrace(int $skipFrames = 0) : array{
		++$skipFrames; //omit this frame from trace, in addition to other skipped frames
		if(function_exists("xdebug_get_function_stack")){
			$trace = array_reverse(xdebug_get_function_stack());
		}else{
			$e = new \Exception();
			$trace = $e->getTrace();
		}
		for($i = 0; $i < $skipFrames; ++$i){
			unset($trace[$i]);
		}
		return array_values($trace);
	}

	/**
	 * @return string[]
	 */
	public static function printableCurrentTrace(int $skipFrames = 0) : array{
		return self::printableTrace(self::currentTrace(++$skipFrames));
	}

	/**
	 * @param string $path
	 *
	 * @return string
	 */
	public static function cleanPath($path){
		$result = str_replace(["\\", ".php", "phar://"], ["/", "", ""], $path);

		//remove relative paths
		//TODO: make these paths dynamic so they can be unit-tested against
		static $cleanPaths = [
			\pocketmine\PLUGIN_PATH => "plugins", //this has to come BEFORE \pocketmine\PATH because it's inside that by default on src installations
			\pocketmine\PATH => ""
		];
		foreach($cleanPaths as $cleanPath => $replacement){
			$cleanPath = rtrim(str_replace(["\\", "phar://"], ["/", ""], $cleanPath), "/");
			if(strpos($result, $cleanPath) === 0){
				$result = ltrim(str_replace($cleanPath, $replacement, $result), "/");
			}
		}
		return $result;
	}

	/**
	 * Extracts one-line tags from the doc-comment
	 *
	 * @return string[] an array of tagName => tag value. If the tag has no value, an empty string is used as the value.
	 */
	public static function parseDocComment(string $docComment) : array{
		preg_match_all('/(*ANYCRLF)^[\t ]*\* @([a-zA-Z]+)(?:[\t ]+(.+))?[\t ]*$/m', $docComment, $matches);

		return array_combine($matches[1], $matches[2]);
	}

	/**
	 * @throws \ErrorException
	 */
	public static function errorExceptionHandler(int $severity, string $message, string $file, int $line) : bool{
		if((error_reporting() & $severity) !== 0){
			throw new \ErrorException($message, 0, $severity, $file, $line);
		}

		return true; //stfu operator
	}

	public static function testValidInstance(string $className, string $baseName) : void{
		try{
			$base = new \ReflectionClass($baseName);
		}catch(\ReflectionException $e){
			throw new \InvalidArgumentException("Base class $baseName does not exist");
		}

		try{
			$class = new \ReflectionClass($className);
		}catch(\ReflectionException $e){
			throw new \InvalidArgumentException("Class $className does not exist");
		}

		if(!$class->isSubclassOf($baseName)){
			throw new \InvalidArgumentException("Class $className does not " . ($base->isInterface() ? "implement" : "extend") . " " . $baseName);
		}
		if(!$class->isInstantiable()){
			throw new \InvalidArgumentException("Class $className cannot be constructed");
		}
	}

	/**
	 * Verifies that the given callable is compatible with the desired signature. Throws a TypeError if they are
	 * incompatible.
	 *
	 * @param callable $signature Dummy callable with the required parameters and return type
	 * @param callable $subject Callable to check the signature of
	 *
	 * @throws \DaveRandom\CallbackValidator\InvalidCallbackException
	 * @throws \TypeError
	 */
	public static function validateCallableSignature(callable $signature, callable $subject) : void{
		if(!($sigType = CallbackType::createFromCallable($signature))->isSatisfiedBy($subject)){
			throw new \TypeError("Declaration of callable `" . CallbackType::createFromCallable($subject) . "` must be compatible with `" . $sigType . "`");
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;

use function count;
use function preg_match;

/**
 * Manages PocketMine-MP version strings, and compares them
 */
class VersionString{
	/** @var string */
	private $baseVersion;
	/** @var string */
	private $suffix;

	/** @var int */
	private $major;
	/** @var int */
	private $minor;
	/** @var int */
	private $patch;

	/** @var int */
	private $build;
	/** @var bool */
	private $development = false;

	public function __construct(string $baseVersion, bool $isDevBuild = false, int $buildNumber = 0){
		$this->baseVersion = $baseVersion;
		$this->development = $isDevBuild;
		$this->build = $buildNumber;

		preg_match('/(\d+)\.(\d+)\.(\d+)(?:-(.*))?$/', $this->baseVersion, $matches);
		if(count($matches) < 4){
			throw new \InvalidArgumentException("Invalid base version \"$baseVersion\", should contain at least 3 version digits");
		}

		$this->major = (int) $matches[1];
		$this->minor = (int) $matches[2];
		$this->patch = (int) $matches[3];
		$this->suffix = $matches[4] ?? "";
	}

	public function getNumber() : int{
		return (($this->major << 9) | ($this->minor << 5) | $this->patch);
	}

	public function getBaseVersion() : string{
		return $this->baseVersion;
	}

	public function getFullVersion(bool $build = false) : string{
		$retval = $this->baseVersion;
		if($this->development){
			$retval .= "+dev";
			if($build and $this->build > 0){
				$retval .= "." . $this->build;
			}
		}

		return $retval;
	}

	public function getMajor() : int{
		return $this->major;
	}

	public function getMinor() : int{
		return $this->minor;
	}

	public function getPatch() : int{
		return $this->patch;
	}

	public function getSuffix() : string{
		return $this->suffix;
	}

	public function getBuild() : int{
		return $this->build;
	}

	public function isDev() : bool{
		return $this->development;
	}

	public function __toString() : string{
		return $this->getFullVersion();
	}

	public function compare(VersionString $target, bool $diff = false) : int{
		$number = $this->getNumber();
		$tNumber = $target->getNumber();
		if($diff){
			return $tNumber - $number;
		}
		if($number > $tNumber){
			return -1; //Target is older
		}elseif($number < $tNumber){
			return 1; //Target is newer
		}elseif($target->isDev() and !$this->isDev()){
			return -1; //Dev builds of the same version are always considered older than a release
		}elseif($target->getBuild() > $this->getBuild()){
			return 1;
		}elseif($target->getBuild() < $this->getBuild()){
			return -1;
		}else{
			return 0; //Same version
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;

use function abs;
use function date_default_timezone_set;
use function date_parse;
use function exec;
use function file_exists;
use function file_get_contents;
use function implode;
use function ini_get;
use function ini_set;
use function is_link;
use function is_string;
use function json_decode;
use function parse_ini_file;
use function preg_match;
use function readlink;
use function str_replace;
use function strpos;
use function substr;
use function timezone_abbreviations_list;
use function timezone_name_from_abbr;
use function trim;

abstract class Timezone{

	public static function get() : string{
		return ini_get('date.timezone');
	}

	/**
	 * @return string[]
	 */
	public static function init() : array{
		$messages = [];
		do{
			$timezone = ini_get("date.timezone");
			if($timezone !== ""){
				/*
				 * This is here so that people don't come to us complaining and fill up the issue tracker when they put
				 * an incorrect timezone abbreviation in php.ini apparently.
				 */
				if(strpos($timezone, "/") === false){
					$default_timezone = timezone_name_from_abbr($timezone);
					if($default_timezone !== false){
						ini_set("date.timezone", $default_timezone);
						date_default_timezone_set($default_timezone);
						break;
					}else{
						//Bad php.ini value, try another method to detect timezone
						$messages[] = "Timezone \"$timezone\" could not be parsed as a valid timezone from php.ini, falling back to auto-detection";
					}
				}else{
					date_default_timezone_set($timezone);
					break;
				}
			}

			if(($timezone = self::detectSystemTimezone()) and date_default_timezone_set($timezone)){
				//Success! Timezone has already been set and validated in the if statement.
				//This here is just for redundancy just in case some program wants to read timezone data from the ini.
				ini_set("date.timezone", $timezone);
				break;
			}

			if($response = Internet::getURL("http://ip-api.com/json") //If system timezone detection fails or timezone is an invalid value.
				and $ip_geolocation_data = json_decode($response, true)
				and $ip_geolocation_data['status'] !== 'fail'
				and date_default_timezone_set($ip_geolocation_data['timezone'])
			){
				//Again, for redundancy.
				ini_set("date.timezone", $ip_geolocation_data['timezone']);
				break;
			}

			ini_set("date.timezone", "UTC");
			date_default_timezone_set("UTC");
			$messages[] = "Timezone could not be automatically determined or was set to an invalid value. 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.";
		}while(false);

		return $messages;
	}

	/**
	 * @return string|false
	 */
	public static function detectSystemTimezone(){
		switch(Utils::getOS()){
			case 'win':
				$regex = '/(UTC)(\+*\-*\d*\d*\:*\d*\d*)/';

				/*
				 * wmic timezone get Caption
				 * Get the timezone offset
				 *
				 * Sample Output var_dump
				 * array(3) {
				 *	  [0] =>
				 *	  string(7) "Caption"
				 *	  [1] =>
				 *	  string(20) "(UTC+09:30) Adelaide"
				 *	  [2] =>
				 *	  string(0) ""
				 *	}
				 */
				exec("wmic timezone get Caption", $output);

				$string = trim(implode("\n", $output));

				//Detect the Time Zone string
				preg_match($regex, $string, $matches);

				if(!isset($matches[2])){
					return false;
				}

				$offset = $matches[2];

				if($offset == ""){
					return "UTC";
				}

				return self::parseOffset($offset);
			case 'linux':
				// Ubuntu / Debian.
				if(file_exists('/etc/timezone')){
					$data = file_get_contents('/etc/timezone');
					if($data){
						return trim($data);
					}
				}

				// RHEL / CentOS
				if(file_exists('/etc/sysconfig/clock')){
					$data = parse_ini_file('/etc/sysconfig/clock');
					if(isset($data['ZONE']) and is_string($data['ZONE'])){
						return trim($data['ZONE']);
					}
				}

				//Portable method for incompatible 1 distributions.

				$offset = trim(exec('date +%:z'));

				if($offset == "+00:00"){
					return "UTC";
				}

				return self::parseOffset($offset);
			case 'mac':
				if(is_link('/etc/localtime')){
					$filename = readlink('/etc/localtime');
					if(strpos($filename, '/usr/share/zoneinfo/') === 0){
						$timezone = substr($filename, 20);
						return trim($timezone);
					}
				}

				return false;
			default:
				return false;
		}
	}

	/**
	 * @param string $offset In the format of +09:00, +02:00, -04:00 etc.
	 *
	 * @return string|bool
	 */
	private static function parseOffset($offset){
		//Make signed offsets unsigned for date_parse
		if(strpos($offset, '-') !== false){
			$negative_offset = true;
			$offset = str_replace('-', '', $offset);
		}else{
			if(strpos($offset, '+') !== false){
				$negative_offset = false;
				$offset = str_replace('+', '', $offset);
			}else{
				return false;
			}
		}

		$parsed = date_parse($offset);
		$offset = $parsed['hour'] * 3600 + $parsed['minute'] * 60 + $parsed['second'];

		//After date_parse is done, put the sign back
		if($negative_offset == true){
			$offset = -abs($offset);
		}

		//And then, look the offset up.
		//timezone_name_from_abbr is not used because it returns false on some(most) offsets because it's mapping function is weird.
		//That's been a bug in PHP since 2008!
		foreach(timezone_abbreviations_list() as $zones){
			foreach($zones as $timezone){
				if($timezone['offset'] == $offset){
					return $timezone['timezone_id'];
				}
			}
		}

		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;

use function fclose;
use function fopen;
use function function_exists;
use function getenv;
use function is_array;
use function stream_isatty;

abstract class Terminal{
	/** @var string */
	public static $FORMAT_BOLD = "";
	/** @var string */
	public static $FORMAT_OBFUSCATED = "";
	/** @var string */
	public static $FORMAT_ITALIC = "";
	/** @var string */
	public static $FORMAT_UNDERLINE = "";
	/** @var string */
	public static $FORMAT_STRIKETHROUGH = "";

	/** @var string */
	public static $FORMAT_RESET = "";

	/** @var string */
	public static $COLOR_BLACK = "";
	/** @var string */
	public static $COLOR_DARK_BLUE = "";
	/** @var string */
	public static $COLOR_DARK_GREEN = "";
	/** @var string */
	public static $COLOR_DARK_AQUA = "";
	/** @var string */
	public static $COLOR_DARK_RED = "";
	/** @var string */
	public static $COLOR_PURPLE = "";
	/** @var string */
	public static $COLOR_GOLD = "";
	/** @var string */
	public static $COLOR_GRAY = "";
	/** @var string */
	public static $COLOR_DARK_GRAY = "";
	/** @var string */
	public static $COLOR_BLUE = "";
	/** @var string */
	public static $COLOR_GREEN = "";
	/** @var string */
	public static $COLOR_AQUA = "";
	/** @var string */
	public static $COLOR_RED = "";
	/** @var string */
	public static $COLOR_LIGHT_PURPLE = "";
	/** @var string */
	public static $COLOR_YELLOW = "";
	/** @var string */
	public static $COLOR_WHITE = "";

	/** @var bool|null */
	private static $formattingCodes = null;

	public static function hasFormattingCodes() : bool{
		if(self::$formattingCodes === null){
			throw new \InvalidStateException("Formatting codes have not been initialized");
		}
		return self::$formattingCodes;
	}

	private static function detectFormattingCodesSupport() : bool{
		$stdout = fopen("php://stdout", "w");
		$result = (
			stream_isatty($stdout) and //STDOUT isn't being piped
			(
				getenv('TERM') !== false or //Console says it supports colours
				(function_exists('sapi_windows_vt100_support') and sapi_windows_vt100_support($stdout)) //we're on windows and have vt100 support
			)
		);
		fclose($stdout);
		return $result;
	}

	/**
	 * @return void
	 */
	protected static function getFallbackEscapeCodes(){
		self::$FORMAT_BOLD = "\x1b[1m";
		self::$FORMAT_OBFUSCATED = "";
		self::$FORMAT_ITALIC = "\x1b[3m";
		self::$FORMAT_UNDERLINE = "\x1b[4m";
		self::$FORMAT_STRIKETHROUGH = "\x1b[9m";

		self::$FORMAT_RESET = "\x1b[m";

		self::$COLOR_BLACK = "\x1b[38;5;16m";
		self::$COLOR_DARK_BLUE = "\x1b[38;5;19m";
		self::$COLOR_DARK_GREEN = "\x1b[38;5;34m";
		self::$COLOR_DARK_AQUA = "\x1b[38;5;37m";
		self::$COLOR_DARK_RED = "\x1b[38;5;124m";
		self::$COLOR_PURPLE = "\x1b[38;5;127m";
		self::$COLOR_GOLD = "\x1b[38;5;214m";
		self::$COLOR_GRAY = "\x1b[38;5;145m";
		self::$COLOR_DARK_GRAY = "\x1b[38;5;59m";
		self::$COLOR_BLUE = "\x1b[38;5;63m";
		self::$COLOR_GREEN = "\x1b[38;5;83m";
		self::$COLOR_AQUA = "\x1b[38;5;87m";
		self::$COLOR_RED = "\x1b[38;5;203m";
		self::$COLOR_LIGHT_PURPLE = "\x1b[38;5;207m";
		self::$COLOR_YELLOW = "\x1b[38;5;227m";
		self::$COLOR_WHITE = "\x1b[38;5;231m";
	}

	/**
	 * @return void
	 */
	protected static function getEscapeCodes(){
		self::$FORMAT_BOLD = `tput bold`;
		self::$FORMAT_OBFUSCATED = `tput smacs`;
		self::$FORMAT_ITALIC = `tput sitm`;
		self::$FORMAT_UNDERLINE = `tput smul`;
		self::$FORMAT_STRIKETHROUGH = "\x1b[9m"; //`tput `;

		self::$FORMAT_RESET = `tput sgr0`;

		$colors = (int) `tput colors`;
		if($colors > 8){
			self::$COLOR_BLACK = $colors >= 256 ? `tput setaf 16` : `tput setaf 0`;
			self::$COLOR_DARK_BLUE = $colors >= 256 ? `tput setaf 19` : `tput setaf 4`;
			self::$COLOR_DARK_GREEN = $colors >= 256 ? `tput setaf 34` : `tput setaf 2`;
			self::$COLOR_DARK_AQUA = $colors >= 256 ? `tput setaf 37` : `tput setaf 6`;
			self::$COLOR_DARK_RED = $colors >= 256 ? `tput setaf 124` : `tput setaf 1`;
			self::$COLOR_PURPLE = $colors >= 256 ? `tput setaf 127` : `tput setaf 5`;
			self::$COLOR_GOLD = $colors >= 256 ? `tput setaf 214` : `tput setaf 3`;
			self::$COLOR_GRAY = $colors >= 256 ? `tput setaf 145` : `tput setaf 7`;
			self::$COLOR_DARK_GRAY = $colors >= 256 ? `tput setaf 59` : `tput setaf 8`;
			self::$COLOR_BLUE = $colors >= 256 ? `tput setaf 63` : `tput setaf 12`;
			self::$COLOR_GREEN = $colors >= 256 ? `tput setaf 83` : `tput setaf 10`;
			self::$COLOR_AQUA = $colors >= 256 ? `tput setaf 87` : `tput setaf 14`;
			self::$COLOR_RED = $colors >= 256 ? `tput setaf 203` : `tput setaf 9`;
			self::$COLOR_LIGHT_PURPLE = $colors >= 256 ? `tput setaf 207` : `tput setaf 13`;
			self::$COLOR_YELLOW = $colors >= 256 ? `tput setaf 227` : `tput setaf 11`;
			self::$COLOR_WHITE = $colors >= 256 ? `tput setaf 231` : `tput setaf 15`;
		}else{
			self::$COLOR_BLACK = self::$COLOR_DARK_GRAY = `tput setaf 0`;
			self::$COLOR_RED = self::$COLOR_DARK_RED = `tput setaf 1`;
			self::$COLOR_GREEN = self::$COLOR_DARK_GREEN = `tput setaf 2`;
			self::$COLOR_YELLOW = self::$COLOR_GOLD = `tput setaf 3`;
			self::$COLOR_BLUE = self::$COLOR_DARK_BLUE = `tput setaf 4`;
			self::$COLOR_LIGHT_PURPLE = self::$COLOR_PURPLE = `tput setaf 5`;
			self::$COLOR_AQUA = self::$COLOR_DARK_AQUA = `tput setaf 6`;
			self::$COLOR_GRAY = self::$COLOR_WHITE = `tput setaf 7`;
		}
	}

	public static function init(?bool $enableFormatting = null) : void{
		self::$formattingCodes = $enableFormatting ?? self::detectFormattingCodesSupport();
		if(!self::$formattingCodes){
			return;
		}

		switch(Utils::getOS()){
			case "linux":
			case "mac":
			case "bsd":
				self::getEscapeCodes();
				return;

			case "win":
			case "android":
				self::getFallbackEscapeCodes();
				return;
		}

		//TODO: iOS
	}

	public static function isInit() : bool{
		return self::$formattingCodes !== null;
	}

	/**
	 * Returns a string with colorized ANSI Escape codes for the current terminal
	 * Note that this is platform-dependent and might produce different results depending on the terminal type and/or OS.
	 *
	 * @param string|string[] $string
	 */
	public static function toANSI($string) : string{
		if(!is_array($string)){
			$string = TextFormat::tokenize($string);
		}

		$newString = "";
		foreach($string as $token){
			switch($token){
				case TextFormat::BOLD:
					$newString .= Terminal::$FORMAT_BOLD;
					break;
				case TextFormat::OBFUSCATED:
					$newString .= Terminal::$FORMAT_OBFUSCATED;
					break;
				case TextFormat::ITALIC:
					$newString .= Terminal::$FORMAT_ITALIC;
					break;
				case TextFormat::UNDERLINE:
					$newString .= Terminal::$FORMAT_UNDERLINE;
					break;
				case TextFormat::STRIKETHROUGH:
					$newString .= Terminal::$FORMAT_STRIKETHROUGH;
					break;
				case TextFormat::RESET:
					$newString .= Terminal::$FORMAT_RESET;
					break;

				//Colors
				case TextFormat::BLACK:
					$newString .= Terminal::$COLOR_BLACK;
					break;
				case TextFormat::DARK_BLUE:
					$newString .= Terminal::$COLOR_DARK_BLUE;
					break;
				case TextFormat::DARK_GREEN:
					$newString .= Terminal::$COLOR_DARK_GREEN;
					break;
				case TextFormat::DARK_AQUA:
					$newString .= Terminal::$COLOR_DARK_AQUA;
					break;
				case TextFormat::DARK_RED:
					$newString .= Terminal::$COLOR_DARK_RED;
					break;
				case TextFormat::DARK_PURPLE:
					$newString .= Terminal::$COLOR_PURPLE;
					break;
				case TextFormat::GOLD:
					$newString .= Terminal::$COLOR_GOLD;
					break;
				case TextFormat::GRAY:
					$newString .= Terminal::$COLOR_GRAY;
					break;
				case TextFormat::DARK_GRAY:
					$newString .= Terminal::$COLOR_DARK_GRAY;
					break;
				case TextFormat::BLUE:
					$newString .= Terminal::$COLOR_BLUE;
					break;
				case TextFormat::GREEN:
					$newString .= Terminal::$COLOR_GREEN;
					break;
				case TextFormat::AQUA:
					$newString .= Terminal::$COLOR_AQUA;
					break;
				case TextFormat::RED:
					$newString .= Terminal::$COLOR_RED;
					break;
				case TextFormat::LIGHT_PURPLE:
					$newString .= Terminal::$COLOR_LIGHT_PURPLE;
					break;
				case TextFormat::YELLOW:
					$newString .= Terminal::$COLOR_YELLOW;
					break;
				case TextFormat::WHITE:
					$newString .= Terminal::$COLOR_WHITE;
					break;
				default:
					$newString .= $token;
					break;
			}
		}

		return $newString;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;

use LogLevel;
use pocketmine\Thread;
use pocketmine\Worker;
use function fclose;
use function fopen;
use function fwrite;
use function get_class;
use function is_resource;
use function preg_replace;
use function sprintf;
use function time;
use function touch;
use function trim;
use const E_COMPILE_ERROR;
use const E_COMPILE_WARNING;
use const E_CORE_ERROR;
use const E_CORE_WARNING;
use const E_DEPRECATED;
use const E_ERROR;
use const E_NOTICE;
use const E_PARSE;
use const E_RECOVERABLE_ERROR;
use const E_STRICT;
use const E_USER_DEPRECATED;
use const E_USER_ERROR;
use const E_USER_NOTICE;
use const E_USER_WARNING;
use const E_WARNING;
use const PHP_EOL;
use const PTHREADS_INHERIT_NONE;

class MainLogger extends \AttachableThreadedLogger{

	/** @var string */
	protected $logFile;
	/** @var \Threaded */
	protected $logStream;
	/** @var bool */
	protected $shutdown = false;
	/** @var bool */
	protected $logDebug;
	/** @var MainLogger|null */
	public static $logger = null;
	/** @var bool */
	private $syncFlush = false;

	/** @var string */
	private $format = TextFormat::AQUA . "[%s] " . TextFormat::RESET . "%s[%s/%s]: %s" . TextFormat::RESET;

	/** @var bool */
	private $mainThreadHasFormattingCodes = false;

	/** @var string */
	private $timezone;

	/**
	 * @throws \RuntimeException
	 */
	public function __construct(string $logFile, bool $logDebug = false){
		parent::__construct();
		if(static::$logger instanceof MainLogger){
			throw new \RuntimeException("MainLogger has been already created");
		}
		touch($logFile);
		$this->logFile = $logFile;
		$this->logDebug = $logDebug;
		$this->logStream = new \Threaded;

		//Child threads may not inherit command line arguments, so if there's an override it needs to be recorded here
		$this->mainThreadHasFormattingCodes = Terminal::hasFormattingCodes();
		$this->timezone = Timezone::get();

		$this->start(PTHREADS_INHERIT_NONE);
	}

	public static function getLogger() : MainLogger{
		return static::$logger;
	}

	/**
	 * Returns whether a MainLogger instance is statically registered on this thread.
	 */
	public static function isRegisteredStatic() : bool{
		return static::$logger !== null;
	}

	/**
	 * Assigns the MainLogger instance to the {@link MainLogger#logger} static property.
	 *
	 * WARNING: Because static properties are thread-local, this MUST be called from the body of every Thread if you
	 * want the logger to be accessible via {@link MainLogger#getLogger}.
	 *
	 * @return void
	 */
	public function registerStatic(){
		if(static::$logger === null){
			static::$logger = $this;
		}
	}

	/**
	 * Returns the current logger format used for console output.
	 */
	public function getFormat() : string{
		return $this->format;
	}

	/**
	 * Sets the logger format to use for outputting text to the console.
	 * It should be an sprintf()able string accepting 5 string arguments:
	 * - time
	 * - color
	 * - thread name
	 * - prefix (debug, info etc)
	 * - message
	 *
	 * @see http://php.net/manual/en/function.sprintf.php
	 */
	public function setFormat(string $format) : void{
		$this->format = $format;
	}

	public function emergency($message){
		$this->send($message, \LogLevel::EMERGENCY, "EMERGENCY", TextFormat::RED);
	}

	public function alert($message){
		$this->send($message, \LogLevel::ALERT, "ALERT", TextFormat::RED);
	}

	public function critical($message){
		$this->send($message, \LogLevel::CRITICAL, "CRITICAL", TextFormat::RED);
	}

	public function error($message){
		$this->send($message, \LogLevel::ERROR, "ERROR", TextFormat::DARK_RED);
	}

	public function warning($message){
		$this->send($message, \LogLevel::WARNING, "WARNING", TextFormat::YELLOW);
	}

	public function notice($message){
		$this->send($message, \LogLevel::NOTICE, "NOTICE", TextFormat::AQUA);
	}

	public function info($message){
		$this->send($message, \LogLevel::INFO, "INFO", TextFormat::WHITE);
	}

	public function debug($message, bool $force = false){
		if(!$this->logDebug and !$force){
			return;
		}
		$this->send($message, \LogLevel::DEBUG, "DEBUG", TextFormat::GRAY);
	}

	/**
	 * @return void
	 */
	public function setLogDebug(bool $logDebug){
		$this->logDebug = $logDebug;
	}

	/**
	 * @param mixed[][]|null $trace
	 * @phpstan-param list<array<string, mixed>>|null $trace
	 *
	 * @return void
	 */
	public function logException(\Throwable $e, $trace = null){
		if($trace === null){
			$trace = $e->getTrace();
		}

		$this->synchronized(function() use ($e, $trace) : void{
			$this->critical(self::printExceptionMessage($e));
			foreach(Utils::printableTrace($trace) as $line){
				$this->debug($line, true);
			}
			for($prev = $e->getPrevious(); $prev !== null; $prev = $prev->getPrevious()){
				$this->debug("Previous: " . self::printExceptionMessage($prev), true);
				foreach(Utils::printableTrace($prev->getTrace()) as $line){
					$this->debug("  " . $line, true);
				}
			}
		});

		$this->syncFlushBuffer();
	}

	private static function printExceptionMessage(\Throwable $e) : string{
		static $errorConversion = [
			0 => "EXCEPTION",
			E_ERROR => "E_ERROR",
			E_WARNING => "E_WARNING",
			E_PARSE => "E_PARSE",
			E_NOTICE => "E_NOTICE",
			E_CORE_ERROR => "E_CORE_ERROR",
			E_CORE_WARNING => "E_CORE_WARNING",
			E_COMPILE_ERROR => "E_COMPILE_ERROR",
			E_COMPILE_WARNING => "E_COMPILE_WARNING",
			E_USER_ERROR => "E_USER_ERROR",
			E_USER_WARNING => "E_USER_WARNING",
			E_USER_NOTICE => "E_USER_NOTICE",
			E_STRICT => "E_STRICT",
			E_RECOVERABLE_ERROR => "E_RECOVERABLE_ERROR",
			E_DEPRECATED => "E_DEPRECATED",
			E_USER_DEPRECATED => "E_USER_DEPRECATED"
		];

		$errstr = preg_replace('/\s+/', ' ', trim($e->getMessage()));

		$errno = $e->getCode();
		$errno = $errorConversion[$errno] ?? $errno;

		$errfile = Utils::cleanPath($e->getFile());
		$errline = $e->getLine();

		return get_class($e) . ": \"$errstr\" ($errno) in \"$errfile\" at line $errline";
	}

	public function log($level, $message){
		switch($level){
			case LogLevel::EMERGENCY:
				$this->emergency($message);
				break;
			case LogLevel::ALERT:
				$this->alert($message);
				break;
			case LogLevel::CRITICAL:
				$this->critical($message);
				break;
			case LogLevel::ERROR:
				$this->error($message);
				break;
			case LogLevel::WARNING:
				$this->warning($message);
				break;
			case LogLevel::NOTICE:
				$this->notice($message);
				break;
			case LogLevel::INFO:
				$this->info($message);
				break;
			case LogLevel::DEBUG:
				$this->debug($message);
				break;
		}
	}

	/**
	 * @return void
	 */
	public function shutdown(){
		$this->shutdown = true;
		$this->notify();
	}

	/**
	 * @param string $message
	 * @param string $level
	 * @param string $prefix
	 * @param string $color
	 *
	 * @return void
	 */
	protected function send($message, $level, $prefix, $color){
		/** @var \DateTime|null $time */
		static $time = null;
		if($time === null){ //thread-local
			$time = new \DateTime('now', new \DateTimeZone($this->timezone));
		}
		$time->setTimestamp(time());

		$thread = \Thread::getCurrentThread();
		if($thread === null){
			$threadName = "Server thread";
		}elseif($thread instanceof Thread or $thread instanceof Worker){
			$threadName = $thread->getThreadName() . " thread";
		}else{
			$threadName = (new \ReflectionClass($thread))->getShortName() . " thread";
		}

		$message = sprintf($this->format, $time->format("H:i:s"), $color, $threadName, $prefix, TextFormat::clean($message, false));

		if(!Terminal::isInit()){
			Terminal::init($this->mainThreadHasFormattingCodes); //lazy-init colour codes because we don't know if they've been registered on this thread
		}

		$this->synchronized(function() use ($message, $level, $time) : void{
			echo Terminal::toANSI($message) . PHP_EOL;

			foreach($this->attachments as $attachment){
				$attachment->call($level, $message);
			}

			$this->logStream[] = $time->format("Y-m-d") . " " . TextFormat::clean($message) . PHP_EOL;
		});
	}

	/**
	 * @return void
	 */
	public function syncFlushBuffer(){
		$this->syncFlush = true;
		$this->synchronized(function() : void{
			$this->notify(); //write immediately

			while($this->syncFlush){
				$this->wait(); //block until it's all been written to disk
			}
		});
	}

	/**
	 * @param resource $logResource
	 */
	private function writeLogStream($logResource) : void{
		while($this->logStream->count() > 0){
			$chunk = $this->logStream->shift();
			fwrite($logResource, $chunk);
		}

		if($this->syncFlush){
			$this->syncFlush = false;
			$this->notify(); //if this was due to a sync flush, tell the caller to stop waiting
		}
	}

	/**
	 * @return void
	 */
	public function run(){
		$logResource = fopen($this->logFile, "ab");
		if(!is_resource($logResource)){
			throw new \RuntimeException("Couldn't open log file");
		}

		while(!$this->shutdown){
			$this->writeLogStream($logResource);
			$this->synchronized(function() : void{
				$this->wait(25000);
			});
		}

		$this->writeLogStream($logResource);

		fclose($logResource);
	}
}
<?php

/*
 * PocketMine Standard PHP Library
 * Copyright (C) 2014-2018 PocketMine Team <https://github.com/PocketMine/PocketMine-SPL>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
*/

abstract class AttachableThreadedLogger extends \ThreadedLogger{

	/** @var \Volatile|\ThreadedLoggerAttachment[] */
	protected $attachments;

	public function __construct(){
		$this->attachments = new \Volatile();
	}

	/**
	 * @param ThreadedLoggerAttachment $attachment
	 *
	 * @return void
	 */
	public function addAttachment(\ThreadedLoggerAttachment $attachment){
		$this->attachments[] = $attachment;
	}

	/**
	 * @param ThreadedLoggerAttachment $attachment
	 *
	 * @return void
	 */
	public function removeAttachment(\ThreadedLoggerAttachment $attachment){
		foreach($this->attachments as $i => $a){
			if($attachment === $a){
				unset($this->attachments[$i]);
			}
		}
	}

	/**
	 * @return void
	 */
	public function removeAttachments(){
		foreach($this->attachments as $i => $a){
			unset($this->attachments[$i]);
		}
	}

	/**
	 * @return \ThreadedLoggerAttachment[]
	 */
	public function getAttachments(){
		return (array) $this->attachments;
	}
}
<?php

/*
 * PocketMine Standard PHP Library
 * Copyright (C) 2014-2018 PocketMine Team <https://github.com/PocketMine/PocketMine-SPL>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
*/

abstract class ThreadedLogger extends \Thread implements Logger{

}
<?php

/*
 * PocketMine Standard PHP Library
 * Copyright (C) 2014-2018 PocketMine Team <https://github.com/PocketMine/PocketMine-SPL>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
*/

interface Logger{

	/**
	 * System is unusable
	 *
	 * @param string $message
	 *
	 * @return void
	 */
	public function emergency($message);

	/**
	 * Action must be taken immediately
	 *
	 * @param string $message
	 *
	 * @return void
	 */
	public function alert($message);

	/**
	 * Critical conditions
	 *
	 * @param string $message
	 *
	 * @return void
	 */
	public function critical($message);

	/**
	 * Runtime errors that do not require immediate action but should typically
	 * be logged and monitored.
	 *
	 * @param string $message
	 *
	 * @return void
	 */
	public function error($message);

	/**
	 * Exceptional occurrences that are not errors.
	 *
	 * Example: Use of deprecated APIs, poor use of an API, undesirable things
	 * that are not necessarily wrong.
	 *
	 * @param string $message
	 *
	 * @return void
	 */
	public function warning($message);

	/**
	 * Normal but significant events.
	 *
	 * @param string $message
	 *
	 * @return void
	 */
	public function notice($message);

	/**
	 * Interesting events.
	 *
	 * @param string $message
	 *
	 * @return void
	 */
	public function info($message);

	/**
	 * Detailed debug information.
	 *
	 * @param string $message
	 *
	 * @return void
	 */
	public function debug($message);

	/**
	 * Logs with an arbitrary level.
	 *
	 * @param mixed  $level
	 * @param string $message
	 *
	 * @return void
	 */
	public function log($level, $message);

	/**
	 * Logs a Throwable object
	 *
	 * @param Throwable  $e
	 * @param array|null $trace
	 * @phpstan-param list<array<string, mixed>>|null $trace
	 *
	 * @return void
	 */
	public function logException(\Throwable $e, $trace = null);
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;

use function is_array;
use function json_encode;
use function mb_scrub;
use function preg_quote;
use function preg_replace;
use function preg_split;
use function str_repeat;
use function str_replace;
use const JSON_UNESCAPED_SLASHES;
use const PREG_SPLIT_DELIM_CAPTURE;
use const PREG_SPLIT_NO_EMPTY;

/**
 * Class used to handle Minecraft chat format, and convert it to other formats like HTML
 */
abstract class TextFormat{
	public const ESCAPE = "\xc2\xa7"; //§
	public const EOL = "\n";

	public const BLACK = TextFormat::ESCAPE . "0";
	public const DARK_BLUE = TextFormat::ESCAPE . "1";
	public const DARK_GREEN = TextFormat::ESCAPE . "2";
	public const DARK_AQUA = TextFormat::ESCAPE . "3";
	public const DARK_RED = TextFormat::ESCAPE . "4";
	public const DARK_PURPLE = TextFormat::ESCAPE . "5";
	public const GOLD = TextFormat::ESCAPE . "6";
	public const GRAY = TextFormat::ESCAPE . "7";
	public const DARK_GRAY = TextFormat::ESCAPE . "8";
	public const BLUE = TextFormat::ESCAPE . "9";
	public const GREEN = TextFormat::ESCAPE . "a";
	public const AQUA = TextFormat::ESCAPE . "b";
	public const RED = TextFormat::ESCAPE . "c";
	public const LIGHT_PURPLE = TextFormat::ESCAPE . "d";
	public const YELLOW = TextFormat::ESCAPE . "e";
	public const WHITE = TextFormat::ESCAPE . "f";

	public const OBFUSCATED = TextFormat::ESCAPE . "k";
	public const BOLD = TextFormat::ESCAPE . "l";
	public const STRIKETHROUGH = TextFormat::ESCAPE . "m";
	public const UNDERLINE = TextFormat::ESCAPE . "n";
	public const ITALIC = TextFormat::ESCAPE . "o";
	public const RESET = TextFormat::ESCAPE . "r";

	/**
	 * Splits the string by Format tokens
	 *
	 * @return string[]
	 */
	public static function tokenize(string $string) : array{
		return preg_split("/(" . TextFormat::ESCAPE . "[0-9a-fk-or])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
	}

	/**
	 * Cleans the string from Minecraft codes, ANSI Escape Codes and invalid UTF-8 characters
	 *
	 * @return string valid clean UTF-8
	 */
	public static function clean(string $string, bool $removeFormat = true) : string{
		$string = mb_scrub($string, 'UTF-8');
		$string = preg_replace("/[\x{E000}-\x{F8FF}]/u", "", $string); //remove unicode private-use-area characters (they might break the console)
		if($removeFormat){
			$string = str_replace(TextFormat::ESCAPE, "", preg_replace("/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "", $string));
		}
		return str_replace("\x1b", "", preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string));
	}

	/**
	 * Replaces placeholders of § with the correct character. Only valid codes (as in the constants of the TextFormat class) will be converted.
	 *
	 * @param string $placeholder default "&"
	 */
	public static function colorize(string $string, string $placeholder = "&") : string{
		return preg_replace('/' . preg_quote($placeholder, "/") . '([0-9a-fk-or])/u', TextFormat::ESCAPE . '$1', $string);
	}

	/**
	 * Returns an JSON-formatted string with colors/markup
	 *
	 * @param string|string[] $string
	 */
	public static function toJSON($string) : string{
		if(!is_array($string)){
			$string = self::tokenize($string);
		}
		$newString = [];
		$pointer =& $newString;
		$color = "white";
		$bold = false;
		$italic = false;
		$underlined = false;
		$strikethrough = false;
		$obfuscated = false;
		$index = 0;

		foreach($string as $token){
			if(isset($pointer["text"])){
				if(!isset($newString["extra"])){
					$newString["extra"] = [];
				}
				$newString["extra"][$index] = [];
				$pointer =& $newString["extra"][$index];
				if($color !== "white"){
					$pointer["color"] = $color;
				}
				if($bold){
					$pointer["bold"] = true;
				}
				if($italic){
					$pointer["italic"] = true;
				}
				if($underlined){
					$pointer["underlined"] = true;
				}
				if($strikethrough){
					$pointer["strikethrough"] = true;
				}
				if($obfuscated){
					$pointer["obfuscated"] = true;
				}
				++$index;
			}
			switch($token){
				case TextFormat::BOLD:
					if(!$bold){
						$pointer["bold"] = true;
						$bold = true;
					}
					break;
				case TextFormat::OBFUSCATED:
					if(!$obfuscated){
						$pointer["obfuscated"] = true;
						$obfuscated = true;
					}
					break;
				case TextFormat::ITALIC:
					if(!$italic){
						$pointer["italic"] = true;
						$italic = true;
					}
					break;
				case TextFormat::UNDERLINE:
					if(!$underlined){
						$pointer["underlined"] = true;
						$underlined = true;
					}
					break;
				case TextFormat::STRIKETHROUGH:
					if(!$strikethrough){
						$pointer["strikethrough"] = true;
						$strikethrough = true;
					}
					break;
				case TextFormat::RESET:
					if($color !== "white"){
						$pointer["color"] = "white";
						$color = "white";
					}
					if($bold){
						$pointer["bold"] = false;
						$bold = false;
					}
					if($italic){
						$pointer["italic"] = false;
						$italic = false;
					}
					if($underlined){
						$pointer["underlined"] = false;
						$underlined = false;
					}
					if($strikethrough){
						$pointer["strikethrough"] = false;
						$strikethrough = false;
					}
					if($obfuscated){
						$pointer["obfuscated"] = false;
						$obfuscated = false;
					}
					break;

				//Colors
				case TextFormat::BLACK:
					$pointer["color"] = "black";
					$color = "black";
					break;
				case TextFormat::DARK_BLUE:
					$pointer["color"] = "dark_blue";
					$color = "dark_blue";
					break;
				case TextFormat::DARK_GREEN:
					$pointer["color"] = "dark_green";
					$color = "dark_green";
					break;
				case TextFormat::DARK_AQUA:
					$pointer["color"] = "dark_aqua";
					$color = "dark_aqua";
					break;
				case TextFormat::DARK_RED:
					$pointer["color"] = "dark_red";
					$color = "dark_red";
					break;
				case TextFormat::DARK_PURPLE:
					$pointer["color"] = "dark_purple";
					$color = "dark_purple";
					break;
				case TextFormat::GOLD:
					$pointer["color"] = "gold";
					$color = "gold";
					break;
				case TextFormat::GRAY:
					$pointer["color"] = "gray";
					$color = "gray";
					break;
				case TextFormat::DARK_GRAY:
					$pointer["color"] = "dark_gray";
					$color = "dark_gray";
					break;
				case TextFormat::BLUE:
					$pointer["color"] = "blue";
					$color = "blue";
					break;
				case TextFormat::GREEN:
					$pointer["color"] = "green";
					$color = "green";
					break;
				case TextFormat::AQUA:
					$pointer["color"] = "aqua";
					$color = "aqua";
					break;
				case TextFormat::RED:
					$pointer["color"] = "red";
					$color = "red";
					break;
				case TextFormat::LIGHT_PURPLE:
					$pointer["color"] = "light_purple";
					$color = "light_purple";
					break;
				case TextFormat::YELLOW:
					$pointer["color"] = "yellow";
					$color = "yellow";
					break;
				case TextFormat::WHITE:
					$pointer["color"] = "white";
					$color = "white";
					break;
				default:
					$pointer["text"] = $token;
					break;
			}
		}

		if(isset($newString["extra"])){
			foreach($newString["extra"] as $k => $d){
				if(!isset($d["text"])){
					unset($newString["extra"][$k]);
				}
			}
		}

		return json_encode($newString, JSON_UNESCAPED_SLASHES);
	}

	/**
	 * Returns an HTML-formatted string with colors/markup
	 *
	 * @param string|string[] $string
	 */
	public static function toHTML($string) : string{
		if(!is_array($string)){
			$string = self::tokenize($string);
		}
		$newString = "";
		$tokens = 0;
		foreach($string as $token){
			switch($token){
				case TextFormat::BOLD:
					$newString .= "<span style=font-weight:bold>";
					++$tokens;
					break;
				case TextFormat::OBFUSCATED:
					//$newString .= "<span style=text-decoration:line-through>";
					//++$tokens;
					break;
				case TextFormat::ITALIC:
					$newString .= "<span style=font-style:italic>";
					++$tokens;
					break;
				case TextFormat::UNDERLINE:
					$newString .= "<span style=text-decoration:underline>";
					++$tokens;
					break;
				case TextFormat::STRIKETHROUGH:
					$newString .= "<span style=text-decoration:line-through>";
					++$tokens;
					break;
				case TextFormat::RESET:
					$newString .= str_repeat("</span>", $tokens);
					$tokens = 0;
					break;

				//Colors
				case TextFormat::BLACK:
					$newString .= "<span style=color:#000>";
					++$tokens;
					break;
				case TextFormat::DARK_BLUE:
					$newString .= "<span style=color:#00A>";
					++$tokens;
					break;
				case TextFormat::DARK_GREEN:
					$newString .= "<span style=color:#0A0>";
					++$tokens;
					break;
				case TextFormat::DARK_AQUA:
					$newString .= "<span style=color:#0AA>";
					++$tokens;
					break;
				case TextFormat::DARK_RED:
					$newString .= "<span style=color:#A00>";
					++$tokens;
					break;
				case TextFormat::DARK_PURPLE:
					$newString .= "<span style=color:#A0A>";
					++$tokens;
					break;
				case TextFormat::GOLD:
					$newString .= "<span style=color:#FA0>";
					++$tokens;
					break;
				case TextFormat::GRAY:
					$newString .= "<span style=color:#AAA>";
					++$tokens;
					break;
				case TextFormat::DARK_GRAY:
					$newString .= "<span style=color:#555>";
					++$tokens;
					break;
				case TextFormat::BLUE:
					$newString .= "<span style=color:#55F>";
					++$tokens;
					break;
				case TextFormat::GREEN:
					$newString .= "<span style=color:#5F5>";
					++$tokens;
					break;
				case TextFormat::AQUA:
					$newString .= "<span style=color:#5FF>";
					++$tokens;
					break;
				case TextFormat::RED:
					$newString .= "<span style=color:#F55>";
					++$tokens;
					break;
				case TextFormat::LIGHT_PURPLE:
					$newString .= "<span style=color:#F5F>";
					++$tokens;
					break;
				case TextFormat::YELLOW:
					$newString .= "<span style=color:#FF5>";
					++$tokens;
					break;
				case TextFormat::WHITE:
					$newString .= "<span style=color:#FFF>";
					++$tokens;
					break;
				default:
					$newString .= $token;
					break;
			}
		}

		$newString .= str_repeat("</span>", $tokens);

		return $newString;
	}
}
<?php

/*
 * PocketMine Standard PHP Library
 * Copyright (C) 2014-2018 PocketMine Team <https://github.com/PocketMine/PocketMine-SPL>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
*/

class BaseClassLoader extends \Threaded implements ClassLoader{

	/** @var \ClassLoader|null */
	private $parent;
	/** @var \Threaded|string[] */
	private $lookup;
	/** @var \Threaded|string[] */
	private $classes;


	/**
	 * @param ClassLoader|null $parent
	 */
	public function __construct(ClassLoader $parent = null){
		$this->parent = $parent;
		$this->lookup = new \Threaded;
		$this->classes = new \Threaded;
	}

	/**
	 * Adds a path to the lookup list
	 *
	 * @param string $path
	 * @param bool   $prepend
	 *
	 * @return void
	 */
	public function addPath($path, $prepend = false){

		foreach($this->lookup as $p){
			if($p === $path){
				return;
			}
		}

		if($prepend){
			$this->lookup->synchronized(function($path){
				$entries = $this->getAndRemoveLookupEntries();
				$this->lookup[] = $path;
				foreach($entries as $entry){
					$this->lookup[] = $entry;
				}
			}, $path);
		}else{
			$this->lookup[] = $path;
		}
	}
	

	/**
	 * @return string[]
	 */
	protected function getAndRemoveLookupEntries(){
		$entries = [];
		while($this->lookup->count() > 0){
			$entries[] = $this->lookup->shift();
		}
		return $entries;
	}

	/**
	 * Removes a path from the lookup list
	 *
	 * @param string $path
	 *
	 * @return void
	 */
	public function removePath($path){
		foreach($this->lookup as $i => $p){
			if($p === $path){
				unset($this->lookup[$i]);
			}
		}
	}

	/**
	 * Returns an array of the classes loaded
	 *
	 * @return string[]
	 */
	public function getClasses(){
		$classes = [];
		foreach($this->classes as $class){
			$classes[] = $class;
		}
		return $classes;
	}

	/**
	 * Returns the parent ClassLoader, if any
	 *
	 * @return ClassLoader|null
	 */
	public function getParent(){
		return $this->parent;
	}

	/**
	 * Attaches the ClassLoader to the PHP runtime
	 *
	 * @param bool $prepend
	 *
	 * @return bool
	 */
	public function register($prepend = false){
		return spl_autoload_register(function(string $name) : void{
			$this->loadClass($name);
		}, true, $prepend);
	}

	/**
	 * Called when there is a class to load
	 *
	 * @param string $name
	 *
	 * @return bool
	 */
	public function loadClass($name){
		$path = $this->findClass($name);
		if($path !== null){
			include($path);
			if(!class_exists($name, false) and !interface_exists($name, false) and !trait_exists($name, false)){
				return false;
			}

			if(method_exists($name, "onClassLoaded") and (new ReflectionClass($name))->getMethod("onClassLoaded")->isStatic()){
				$name::onClassLoaded();
			}
			
			$this->classes[] = $name;

			return true;
		}

		return false;
	}

	/**
	 * Returns the path for the class, if any
	 *
	 * @param string $name
	 *
	 * @return string|null
	 */
	public function findClass($name){
		$baseName = str_replace("\\", DIRECTORY_SEPARATOR, $name);

		foreach($this->lookup as $path){
			if(PHP_INT_SIZE === 8 and file_exists($path . DIRECTORY_SEPARATOR . $baseName . "__64bit.php")){
				return $path . DIRECTORY_SEPARATOR . $baseName . "__64bit.php";
			}elseif(PHP_INT_SIZE === 4 and file_exists($path . DIRECTORY_SEPARATOR . $baseName . "__32bit.php")){
				return $path . DIRECTORY_SEPARATOR . $baseName . "__32bit.php";
			}elseif(file_exists($path . DIRECTORY_SEPARATOR . $baseName . ".php")){
				return $path . DIRECTORY_SEPARATOR . $baseName . ".php";
			}
		}

		return null;
	}
}
<?php

/*
 * PocketMine Standard PHP Library
 * Copyright (C) 2014-2018 PocketMine Team <https://github.com/PocketMine/PocketMine-SPL>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
*/

interface ClassLoader{

	/**
	 * @param ClassLoader $parent
	 */
	public function __construct(ClassLoader $parent = null);

	/**
	 * Adds a path to the lookup list
	 *
	 * @param string $path
	 * @param bool   $prepend
	 *
	 * @return void
	 */
	public function addPath($path, $prepend = false);

	/**
	 * Removes a path from the lookup list
	 *
	 * @param string $path
	 *
	 * @return void
	 */
	public function removePath($path);

	/**
	 * Returns an array of the classes loaded
	 *
	 * @return string[]
	 */
	public function getClasses();

	/**
	 * Returns the parent ClassLoader, if any
	 *
	 * @return ClassLoader
	 */
	public function getParent();

	/**
	 * Attaches the ClassLoader to the PHP runtime
	 *
	 * @param bool $prepend
	 *
	 * @return bool
	 */
	public function register($prepend = false);

	/**
	 * Called when there is a class to load
	 *
	 * @param string $name
	 *
	 * @return bool
	 */
	public function loadClass($name);

	/**
	 * Returns the path for the class, if any
	 *
	 * @param string $name
	 *
	 * @return string|null
	 */
	public function findClass($name);
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * PocketMine-MP is the Minecraft: PE multiplayer server software
 * Homepage: http://www.pocketmine.net/
 */
namespace pocketmine;

use pocketmine\block\BlockFactory;
use pocketmine\command\CommandReader;
use pocketmine\command\CommandSender;
use pocketmine\command\ConsoleCommandSender;
use pocketmine\command\PluginIdentifiableCommand;
use pocketmine\command\SimpleCommandMap;
use pocketmine\entity\Entity;
use pocketmine\entity\Skin;
use pocketmine\event\HandlerList;
use pocketmine\event\level\LevelInitEvent;
use pocketmine\event\level\LevelLoadEvent;
use pocketmine\event\player\PlayerDataSaveEvent;
use pocketmine\event\server\CommandEvent;
use pocketmine\event\server\QueryRegenerateEvent;
use pocketmine\event\server\ServerCommandEvent;
use pocketmine\inventory\CraftingManager;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\lang\BaseLang;
use pocketmine\lang\TextContainer;
use pocketmine\level\biome\Biome;
use pocketmine\level\format\io\LevelProvider;
use pocketmine\level\format\io\LevelProviderManager;
use pocketmine\level\generator\Generator;
use pocketmine\level\generator\GeneratorManager;
use pocketmine\level\Level;
use pocketmine\level\LevelException;
use pocketmine\metadata\EntityMetadataStore;
use pocketmine\metadata\LevelMetadataStore;
use pocketmine\metadata\PlayerMetadataStore;
use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\LongTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\AdvancedSourceInterface;
use pocketmine\network\CompressBatchedTask;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\RakLibInterface;
use pocketmine\network\Network;
use pocketmine\network\query\QueryHandler;
use pocketmine\network\rcon\RCON;
use pocketmine\network\upnp\UPnP;
use pocketmine\permission\BanList;
use pocketmine\permission\DefaultPermissions;
use pocketmine\permission\PermissionManager;
use pocketmine\plugin\PharPluginLoader;
use pocketmine\plugin\Plugin;
use pocketmine\plugin\PluginLoadOrder;
use pocketmine\plugin\PluginManager;
use pocketmine\plugin\ScriptPluginLoader;
use pocketmine\resourcepacks\ResourcePackManager;
use pocketmine\scheduler\AsyncPool;
use pocketmine\scheduler\SendUsageTask;
use pocketmine\snooze\SleeperHandler;
use pocketmine\snooze\SleeperNotifier;
use pocketmine\tile\Tile;
use pocketmine\timings\Timings;
use pocketmine\timings\TimingsHandler;
use pocketmine\updater\AutoUpdater;
use pocketmine\utils\Config;
use pocketmine\utils\Internet;
use pocketmine\utils\MainLogger;
use pocketmine\utils\Terminal;
use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils;
use pocketmine\utils\UUID;
use function array_filter;
use function array_key_exists;
use function array_shift;
use function array_sum;
use function asort;
use function assert;
use function base64_encode;
use function class_exists;
use function cli_set_process_title;
use function count;
use function define;
use function explode;
use function extension_loaded;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function filemtime;
use function function_exists;
use function get_class;
use function getmypid;
use function getopt;
use function gettype;
use function implode;
use function ini_set;
use function is_array;
use function is_bool;
use function is_dir;
use function is_object;
use function is_string;
use function is_subclass_of;
use function json_decode;
use function max;
use function microtime;
use function min;
use function mkdir;
use function ob_end_flush;
use function pcntl_signal;
use function pcntl_signal_dispatch;
use function preg_replace;
use function random_bytes;
use function random_int;
use function realpath;
use function register_shutdown_function;
use function rename;
use function round;
use function scandir;
use function sleep;
use function spl_object_hash;
use function sprintf;
use function str_repeat;
use function str_replace;
use function stripos;
use function strlen;
use function strrpos;
use function strtolower;
use function substr;
use function time;
use function touch;
use function trim;
use const DIRECTORY_SEPARATOR;
use const INT32_MAX;
use const INT32_MIN;
use const PHP_EOL;
use const PHP_INT_MAX;
use const PTHREADS_INHERIT_NONE;
use const SCANDIR_SORT_NONE;
use const SIGHUP;
use const SIGINT;
use const SIGTERM;

/**
 * The class that manages everything
 */
class Server{
	public const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin";
	public const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user";

	/** @var Server|null */
	private static $instance = null;

	/** @var \Threaded|null */
	private static $sleeper = null;

	/** @var SleeperHandler */
	private $tickSleeper;

	/** @var BanList */
	private $banByName;

	/** @var BanList */
	private $banByIP;

	/** @var Config */
	private $operators;

	/** @var Config */
	private $whitelist;

	/** @var bool */
	private $isRunning = true;

	/** @var bool */
	private $hasStopped = false;

	/** @var PluginManager */
	private $pluginManager;

	/** @var float */
	private $profilingTickRate = 20;

	/** @var AutoUpdater */
	private $updater;

	/** @var AsyncPool */
	private $asyncPool;

	/**
	 * Counts the ticks since the server start
	 *
	 * @var int
	 */
	private $tickCounter = 0;
	/** @var float */
	private $nextTick = 0;
	/** @var float[] */
	private $tickAverage = [20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20];
	/** @var float[] */
	private $useAverage = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
	/** @var float */
	private $currentTPS = 20;
	/** @var float */
	private $currentUse = 0;

	/** @var bool */
	private $doTitleTick = true;

	/** @var int */
	private $sendUsageTicker = 0;

	/** @var bool */
	private $dispatchSignals = false;

	/** @var \AttachableThreadedLogger */
	private $logger;

	/** @var MemoryManager */
	private $memoryManager;

	/** @var CommandReader */
	private $console;

	/** @var SimpleCommandMap */
	private $commandMap;

	/** @var CraftingManager */
	private $craftingManager;

	/** @var ResourcePackManager */
	private $resourceManager;

	/** @var int */
	private $maxPlayers;

	/** @var bool */
	private $onlineMode = true;

	/** @var bool */
	private $autoSave;

	/** @var RCON|null */
	private $rcon = null;

	/** @var EntityMetadataStore */
	private $entityMetadata;

	/** @var PlayerMetadataStore */
	private $playerMetadata;

	/** @var LevelMetadataStore */
	private $levelMetadata;

	/** @var Network */
	private $network;
	/** @var bool */
	private $networkCompressionAsync = true;
	/** @var int */
	public $networkCompressionLevel = 7;

	/** @var int */
	private $autoSaveTicker = 0;
	/** @var int */
	private $autoSaveTicks = 6000;

	/** @var BaseLang */
	private $baseLang;
	/** @var bool */
	private $forceLanguage = false;

	/** @var UUID */
	private $serverID;

	/** @var \ClassLoader */
	private $autoloader;
	/** @var string */
	private $dataPath;
	/** @var string */
	private $pluginPath;

	/**
	 * @var string[]
	 * @phpstan-var array<string, string>
	 */
	private $uniquePlayers = [];

	/** @var QueryHandler|null */
	private $queryHandler = null;

	/** @var QueryRegenerateEvent */
	private $queryRegenerateTask;

	/** @var Config */
	private $properties;
	/** @var mixed[] */
	private $propertyCache = [];

	/** @var Config */
	private $config;

	/** @var Player[] */
	private $players = [];

	/** @var Player[] */
	private $loggedInPlayers = [];

	/** @var Player[] */
	private $playerList = [];

	/** @var Level[] */
	private $levels = [];

	/** @var Level|null */
	private $levelDefault = null;

	public function getName() : string{
		return \pocketmine\NAME;
	}

	public function isRunning() : bool{
		return $this->isRunning;
	}

	public function getPocketMineVersion() : string{
		return \pocketmine\VERSION;
	}

	public function getVersion() : string{
		return ProtocolInfo::MINECRAFT_VERSION;
	}

	public function getApiVersion() : string{
		return \pocketmine\BASE_VERSION;
	}

	public function getFilePath() : string{
		return \pocketmine\PATH;
	}

	public function getResourcePath() : string{
		return \pocketmine\RESOURCE_PATH;
	}

	public function getDataPath() : string{
		return $this->dataPath;
	}

	public function getPluginPath() : string{
		return $this->pluginPath;
	}

	public function getMaxPlayers() : int{
		return $this->maxPlayers;
	}

	/**
	 * Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
	 * are not logged into Xbox Live will be disconnected.
	 */
	public function getOnlineMode() : bool{
		return $this->onlineMode;
	}

	/**
	 * Alias of {@link #getOnlineMode()}.
	 */
	public function requiresAuthentication() : bool{
		return $this->getOnlineMode();
	}

	public function getPort() : int{
		return $this->getConfigInt("server-port", 19132);
	}

	public function getViewDistance() : int{
		return max(2, $this->getConfigInt("view-distance", 8));
	}

	/**
	 * Returns a view distance up to the currently-allowed limit.
	 */
	public function getAllowedViewDistance(int $distance) : int{
		return max(2, min($distance, $this->memoryManager->getViewDistance($this->getViewDistance())));
	}

	public function getIp() : string{
		$str = $this->getConfigString("server-ip");
		return $str !== "" ? $str : "0.0.0.0";
	}

	/**
	 * @return UUID
	 */
	public function getServerUniqueId(){
		return $this->serverID;
	}

	public function getAutoSave() : bool{
		return $this->autoSave;
	}

	/**
	 * @return void
	 */
	public function setAutoSave(bool $value){
		$this->autoSave = $value;
		foreach($this->getLevels() as $level){
			$level->setAutoSave($this->autoSave);
		}
	}

	public function getLevelType() : string{
		return $this->getConfigString("level-type", "DEFAULT");
	}

	public function getGenerateStructures() : bool{
		return $this->getConfigBool("generate-structures", true);
	}

	public function getGamemode() : int{
		return $this->getConfigInt("gamemode", 0) & 0b11;
	}

	public function getForceGamemode() : bool{
		return $this->getConfigBool("force-gamemode", false);
	}

	/**
	 * Returns the gamemode text name
	 */
	public static function getGamemodeString(int $mode) : string{
		switch($mode){
			case Player::SURVIVAL:
				return "%gameMode.survival";
			case Player::CREATIVE:
				return "%gameMode.creative";
			case Player::ADVENTURE:
				return "%gameMode.adventure";
			case Player::SPECTATOR:
				return "%gameMode.spectator";
		}

		return "UNKNOWN";
	}

	public static function getGamemodeName(int $mode) : string{
		switch($mode){
			case Player::SURVIVAL:
				return "Survival";
			case Player::CREATIVE:
				return "Creative";
			case Player::ADVENTURE:
				return "Adventure";
			case Player::SPECTATOR:
				return "Spectator";
			default:
				throw new \InvalidArgumentException("Invalid gamemode $mode");
		}
	}

	/**
	 * Parses a string and returns a gamemode integer, -1 if not found
	 */
	public static function getGamemodeFromString(string $str) : int{
		switch(strtolower(trim($str))){
			case (string) Player::SURVIVAL:
			case "survival":
			case "s":
				return Player::SURVIVAL;

			case (string) Player::CREATIVE:
			case "creative":
			case "c":
				return Player::CREATIVE;

			case (string) Player::ADVENTURE:
			case "adventure":
			case "a":
				return Player::ADVENTURE;

			case (string) Player::SPECTATOR:
			case "spectator":
			case "view":
			case "v":
				return Player::SPECTATOR;
		}
		return -1;
	}

	/**
	 * Returns Server global difficulty. Note that this may be overridden in individual Levels.
	 */
	public function getDifficulty() : int{
		return $this->getConfigInt("difficulty", Level::DIFFICULTY_NORMAL);
	}

	public function hasWhitelist() : bool{
		return $this->getConfigBool("white-list", false);
	}

	public function getSpawnRadius() : int{
		return $this->getConfigInt("spawn-protection", 16);
	}

	/**
	 * @deprecated
	 */
	public function getAllowFlight() : bool{
		return true;
	}

	public function isHardcore() : bool{
		return $this->getConfigBool("hardcore", false);
	}

	public function getDefaultGamemode() : int{
		return $this->getConfigInt("gamemode", 0) & 0b11;
	}

	public function getMotd() : string{
		return $this->getConfigString("motd", \pocketmine\NAME . " Server");
	}

	/**
	 * @return \ClassLoader
	 */
	public function getLoader(){
		return $this->autoloader;
	}

	/**
	 * @return \AttachableThreadedLogger
	 */
	public function getLogger(){
		return $this->logger;
	}

	/**
	 * @return EntityMetadataStore
	 */
	public function getEntityMetadata(){
		return $this->entityMetadata;
	}

	/**
	 * @return PlayerMetadataStore
	 */
	public function getPlayerMetadata(){
		return $this->playerMetadata;
	}

	/**
	 * @return LevelMetadataStore
	 */
	public function getLevelMetadata(){
		return $this->levelMetadata;
	}

	/**
	 * @return AutoUpdater
	 */
	public function getUpdater(){
		return $this->updater;
	}

	/**
	 * @return PluginManager
	 */
	public function getPluginManager(){
		return $this->pluginManager;
	}

	/**
	 * @return CraftingManager
	 */
	public function getCraftingManager(){
		return $this->craftingManager;
	}

	public function getResourcePackManager() : ResourcePackManager{
		return $this->resourceManager;
	}

	public function getAsyncPool() : AsyncPool{
		return $this->asyncPool;
	}

	public function getTick() : int{
		return $this->tickCounter;
	}

	/**
	 * Returns the last server TPS measure
	 */
	public function getTicksPerSecond() : float{
		return round($this->currentTPS, 2);
	}

	/**
	 * Returns the last server TPS average measure
	 */
	public function getTicksPerSecondAverage() : float{
		return round(array_sum($this->tickAverage) / count($this->tickAverage), 2);
	}

	/**
	 * Returns the TPS usage/load in %
	 */
	public function getTickUsage() : float{
		return round($this->currentUse * 100, 2);
	}

	/**
	 * Returns the TPS usage/load average in %
	 */
	public function getTickUsageAverage() : float{
		return round((array_sum($this->useAverage) / count($this->useAverage)) * 100, 2);
	}

	/**
	 * @return SimpleCommandMap
	 */
	public function getCommandMap(){
		return $this->commandMap;
	}

	/**
	 * @return Player[]
	 */
	public function getLoggedInPlayers() : array{
		return $this->loggedInPlayers;
	}

	/**
	 * @return Player[]
	 */
	public function getOnlinePlayers() : array{
		return $this->playerList;
	}

	public function shouldSavePlayerData() : bool{
		return (bool) $this->getProperty("player.save-player-data", true);
	}

	/**
	 * @return OfflinePlayer|Player
	 */
	public function getOfflinePlayer(string $name){
		$name = strtolower($name);
		$result = $this->getPlayerExact($name);

		if($result === null){
			$result = new OfflinePlayer($this, $name);
		}

		return $result;
	}

	/**
	 * Returns whether the server has stored any saved data for this player.
	 */
	public function hasOfflinePlayerData(string $name) : bool{
		$name = strtolower($name);
		return file_exists($this->getDataPath() . "players/$name.dat");
	}

	public function getOfflinePlayerData(string $name) : CompoundTag{
		$name = strtolower($name);
		$path = $this->getDataPath() . "players/";
		if($this->shouldSavePlayerData()){
			if(file_exists($path . "$name.dat")){
				try{
					$nbt = new BigEndianNBTStream();
					$compound = $nbt->readCompressed(file_get_contents($path . "$name.dat"));
					if(!($compound instanceof CompoundTag)){
						throw new \RuntimeException("Invalid data found in \"$name.dat\", expected " . CompoundTag::class . ", got " . (is_object($compound) ? get_class($compound) : gettype($compound)));
					}

					return $compound;
				}catch(\Throwable $e){ //zlib decode error / corrupt data
					rename($path . "$name.dat", $path . "$name.dat.bak");
					$this->logger->notice($this->getLanguage()->translateString("pocketmine.data.playerCorrupted", [$name]));
				}
			}else{
				$this->logger->notice($this->getLanguage()->translateString("pocketmine.data.playerNotFound", [$name]));
			}
		}
		$spawn = $this->getDefaultLevel()->getSafeSpawn();
		$currentTimeMillis = (int) (microtime(true) * 1000);

		$nbt = new CompoundTag("", [
			new LongTag("firstPlayed", $currentTimeMillis),
			new LongTag("lastPlayed", $currentTimeMillis),
			new ListTag("Pos", [
				new DoubleTag("", $spawn->x),
				new DoubleTag("", $spawn->y),
				new DoubleTag("", $spawn->z)
			], NBT::TAG_Double),
			new StringTag("Level", $this->getDefaultLevel()->getFolderName()),
			//new StringTag("SpawnLevel", $this->getDefaultLevel()->getFolderName()),
			//new IntTag("SpawnX", $spawn->getFloorX()),
			//new IntTag("SpawnY", $spawn->getFloorY()),
			//new IntTag("SpawnZ", $spawn->getFloorZ()),
			//new ByteTag("SpawnForced", 1), //TODO
			new ListTag("Inventory", [], NBT::TAG_Compound),
			new ListTag("EnderChestInventory", [], NBT::TAG_Compound),
			new CompoundTag("Achievements", []),
			new IntTag("playerGameType", $this->getGamemode()),
			new ListTag("Motion", [
				new DoubleTag("", 0.0),
				new DoubleTag("", 0.0),
				new DoubleTag("", 0.0)
			], NBT::TAG_Double),
			new ListTag("Rotation", [
				new FloatTag("", 0.0),
				new FloatTag("", 0.0)
			], NBT::TAG_Float),
			new FloatTag("FallDistance", 0.0),
			new ShortTag("Fire", 0),
			new ShortTag("Air", 300),
			new ByteTag("OnGround", 1),
			new ByteTag("Invulnerable", 0),
			new StringTag("NameTag", $name)
		]);

		return $nbt;

	}

	/**
	 * @return void
	 */
	public function saveOfflinePlayerData(string $name, CompoundTag $nbtTag){
		$ev = new PlayerDataSaveEvent($nbtTag, $name);
		$ev->setCancelled(!$this->shouldSavePlayerData());

		$ev->call();

		if(!$ev->isCancelled()){
			$nbt = new BigEndianNBTStream();
			try{
				file_put_contents($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed($ev->getSaveData()));
			}catch(\Throwable $e){
				$this->logger->critical($this->getLanguage()->translateString("pocketmine.data.saveError", [$name, $e->getMessage()]));
				$this->logger->logException($e);
			}
		}
	}

	/**
	 * Returns an online player whose name begins with or equals the given string (case insensitive).
	 * The closest match will be returned, or null if there are no online matches.
	 *
	 * @see Server::getPlayerExact()
	 *
	 * @return Player|null
	 */
	public function getPlayer(string $name){
		$found = null;
		$name = strtolower($name);
		$delta = PHP_INT_MAX;
		foreach($this->getOnlinePlayers() as $player){
			if(stripos($player->getName(), $name) === 0){
				$curDelta = strlen($player->getName()) - strlen($name);
				if($curDelta < $delta){
					$found = $player;
					$delta = $curDelta;
				}
				if($curDelta === 0){
					break;
				}
			}
		}

		return $found;
	}

	/**
	 * Returns an online player with the given name (case insensitive), or null if not found.
	 *
	 * @return Player|null
	 */
	public function getPlayerExact(string $name){
		$name = strtolower($name);
		foreach($this->getOnlinePlayers() as $player){
			if($player->getLowerCaseName() === $name){
				return $player;
			}
		}

		return null;
	}

	/**
	 * Returns a list of online players whose names contain with the given string (case insensitive).
	 * If an exact match is found, only that match is returned.
	 *
	 * @return Player[]
	 */
	public function matchPlayer(string $partialName) : array{
		$partialName = strtolower($partialName);
		$matchedPlayers = [];
		foreach($this->getOnlinePlayers() as $player){
			if($player->getLowerCaseName() === $partialName){
				$matchedPlayers = [$player];
				break;
			}elseif(stripos($player->getName(), $partialName) !== false){
				$matchedPlayers[] = $player;
			}
		}

		return $matchedPlayers;
	}

	/**
	 * Returns the player online with the specified raw UUID, or null if not found
	 */
	public function getPlayerByRawUUID(string $rawUUID) : ?Player{
		return $this->playerList[$rawUUID] ?? null;
	}

	/**
	 * Returns the player online with a UUID equivalent to the specified UUID object, or null if not found
	 */
	public function getPlayerByUUID(UUID $uuid) : ?Player{
		return $this->getPlayerByRawUUID($uuid->toBinary());
	}

	/**
	 * @return Level[]
	 */
	public function getLevels() : array{
		return $this->levels;
	}

	public function getDefaultLevel() : ?Level{
		return $this->levelDefault;
	}

	/**
	 * Sets the default level to a different level
	 * This won't change the level-name property,
	 * it only affects the server on runtime
	 */
	public function setDefaultLevel(?Level $level) : void{
		if($level === null or ($this->isLevelLoaded($level->getFolderName()) and $level !== $this->levelDefault)){
			$this->levelDefault = $level;
		}
	}

	public function isLevelLoaded(string $name) : bool{
		return $this->getLevelByName($name) instanceof Level;
	}

	public function getLevel(int $levelId) : ?Level{
		return $this->levels[$levelId] ?? null;
	}

	/**
	 * NOTE: This matches levels based on the FOLDER name, NOT the display name.
	 */
	public function getLevelByName(string $name) : ?Level{
		foreach($this->getLevels() as $level){
			if($level->getFolderName() === $name){
				return $level;
			}
		}

		return null;
	}

	/**
	 * @throws \InvalidStateException
	 */
	public function unloadLevel(Level $level, bool $forceUnload = false) : bool{
		if($level === $this->getDefaultLevel() and !$forceUnload){
			throw new \InvalidStateException("The default world cannot be unloaded while running, please switch worlds.");
		}

		return $level->unload($forceUnload);
	}

	/**
	 * @internal
	 */
	public function removeLevel(Level $level) : void{
		unset($this->levels[$level->getId()]);
	}

	/**
	 * Loads a level from the data directory
	 *
	 * @throws LevelException
	 */
	public function loadLevel(string $name) : bool{
		if(trim($name) === ""){
			throw new LevelException("Invalid empty world name");
		}
		if($this->isLevelLoaded($name)){
			return true;
		}elseif(!$this->isLevelGenerated($name)){
			$this->logger->notice($this->getLanguage()->translateString("pocketmine.level.notFound", [$name]));

			return false;
		}

		$path = $this->getDataPath() . "worlds/" . $name . "/";

		$providerClass = LevelProviderManager::getProvider($path);

		if($providerClass === null){
			$this->logger->error($this->getLanguage()->translateString("pocketmine.level.loadError", [$name, "Cannot identify format of world"]));

			return false;
		}

		try{
			/**
			 * @var LevelProvider $provider
			 * @see LevelProvider::__construct()
			 */
			$provider = new $providerClass($path);
		}catch(LevelException $e){
			$this->logger->error($this->getLanguage()->translateString("pocketmine.level.loadError", [$name, $e->getMessage()]));
			return false;
		}
		try{
			GeneratorManager::getGenerator($provider->getGenerator(), true);
		}catch(\InvalidArgumentException $e){
			$this->logger->error($this->getLanguage()->translateString("pocketmine.level.loadError", [$name, "Unknown generator \"" . $provider->getGenerator() . "\""]));
			return false;
		}

		$level = new Level($this, $name, $provider);

		$this->levels[$level->getId()] = $level;

		(new LevelLoadEvent($level))->call();

		return true;
	}

	/**
	 * Generates a new level if it does not exist
	 *
	 * @param string|null $generator Class name that extends pocketmine\level\generator\Generator
	 * @phpstan-param class-string<Generator> $generator
	 * @phpstan-param array<string, mixed>    $options
	 */
	public function generateLevel(string $name, int $seed = null, $generator = null, array $options = []) : bool{
		if(trim($name) === "" or $this->isLevelGenerated($name)){
			return false;
		}

		$seed = $seed ?? random_int(INT32_MIN, INT32_MAX);

		if(!isset($options["preset"])){
			$options["preset"] = $this->getConfigString("generator-settings", "");
		}

		if(!($generator !== null and class_exists($generator, true) and is_subclass_of($generator, Generator::class))){
			$generator = GeneratorManager::getGenerator($this->getLevelType());
		}

		if(($providerClass = LevelProviderManager::getProviderByName($this->getProperty("level-settings.default-format", "pmanvil"))) === null){
			$providerClass = LevelProviderManager::getProviderByName("pmanvil");
			if($providerClass === null){
				throw new \InvalidStateException("Default world provider has not been registered");
			}
		}

		$path = $this->getDataPath() . "worlds/" . $name . "/";
		/** @var LevelProvider $providerClass */
		$providerClass::generate($path, $name, $seed, $generator, $options);

		/** @see LevelProvider::__construct() */
		$level = new Level($this, $name, new $providerClass($path));
		$this->levels[$level->getId()] = $level;

		(new LevelInitEvent($level))->call();

		(new LevelLoadEvent($level))->call();

		$this->getLogger()->notice($this->getLanguage()->translateString("pocketmine.level.backgroundGeneration", [$name]));

		$spawnLocation = $level->getSpawnLocation();
		$centerX = $spawnLocation->getFloorX() >> 4;
		$centerZ = $spawnLocation->getFloorZ() >> 4;

		$order = [];

		for($X = -3; $X <= 3; ++$X){
			for($Z = -3; $Z <= 3; ++$Z){
				$distance = $X ** 2 + $Z ** 2;
				$chunkX = $X + $centerX;
				$chunkZ = $Z + $centerZ;
				$index = ((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF);
				$order[$index] = $distance;
			}
		}

		asort($order);

		foreach($order as $index => $distance){
			 $chunkX = ($index >> 32);  $chunkZ = ($index & 0xFFFFFFFF) << 32 >> 32;
			$level->populateChunk($chunkX, $chunkZ, true);
		}

		return true;
	}

	public function isLevelGenerated(string $name) : bool{
		if(trim($name) === ""){
			return false;
		}
		$path = $this->getDataPath() . "worlds/" . $name . "/";
		if(!($this->getLevelByName($name) instanceof Level)){
			return is_dir($path) and count(array_filter(scandir($path, SCANDIR_SORT_NONE), function(string $v) : bool{
				return $v !== ".." and $v !== ".";
			})) > 0;
		}

		return true;
	}

	/**
	 * Searches all levels for the entity with the specified ID.
	 * Useful for tracking entities across multiple worlds without needing strong references.
	 *
	 * @param Level|null $expectedLevel @deprecated Level to look in first for the target
	 *
	 * @return Entity|null
	 */
	public function findEntity(int $entityId, Level $expectedLevel = null){
		foreach($this->levels as $level){
			assert(!$level->isClosed());
			if(($entity = $level->getEntity($entityId)) instanceof Entity){
				return $entity;
			}
		}

		return null;
	}

	/**
	 * @param mixed  $defaultValue
	 *
	 * @return mixed
	 */
	public function getProperty(string $variable, $defaultValue = null){
		if(!array_key_exists($variable, $this->propertyCache)){
			$v = getopt("", ["$variable::"]);
			if(isset($v[$variable])){
				$this->propertyCache[$variable] = $v[$variable];
			}else{
				$this->propertyCache[$variable] = $this->config->getNested($variable);
			}
		}

		return $this->propertyCache[$variable] ?? $defaultValue;
	}

	public function getConfigString(string $variable, string $defaultValue = "") : string{
		$v = getopt("", ["$variable::"]);
		if(isset($v[$variable])){
			return (string) $v[$variable];
		}

		return $this->properties->exists($variable) ? (string) $this->properties->get($variable) : $defaultValue;
	}

	/**
	 * @return void
	 */
	public function setConfigString(string $variable, string $value){
		$this->properties->set($variable, $value);
	}

	public function getConfigInt(string $variable, int $defaultValue = 0) : int{
		$v = getopt("", ["$variable::"]);
		if(isset($v[$variable])){
			return (int) $v[$variable];
		}

		return $this->properties->exists($variable) ? (int) $this->properties->get($variable) : $defaultValue;
	}

	/**
	 * @return void
	 */
	public function setConfigInt(string $variable, int $value){
		$this->properties->set($variable, $value);
	}

	public function getConfigBool(string $variable, bool $defaultValue = false) : bool{
		$v = getopt("", ["$variable::"]);
		if(isset($v[$variable])){
			$value = $v[$variable];
		}else{
			$value = $this->properties->exists($variable) ? $this->properties->get($variable) : $defaultValue;
		}

		if(is_bool($value)){
			return $value;
		}
		switch(strtolower($value)){
			case "on":
			case "true":
			case "1":
			case "yes":
				return true;
		}

		return false;
	}

	/**
	 * @return void
	 */
	public function setConfigBool(string $variable, bool $value){
		$this->properties->set($variable, $value ? "1" : "0");
	}

	/**
	 * @return PluginIdentifiableCommand|null
	 */
	public function getPluginCommand(string $name){
		if(($command = $this->commandMap->getCommand($name)) instanceof PluginIdentifiableCommand){
			return $command;
		}else{
			return null;
		}
	}

	/**
	 * @return BanList
	 */
	public function getNameBans(){
		return $this->banByName;
	}

	/**
	 * @return BanList
	 */
	public function getIPBans(){
		return $this->banByIP;
	}

	/**
	 * @return void
	 */
	public function addOp(string $name){
		$this->operators->set(strtolower($name), true);

		if(($player = $this->getPlayerExact($name)) !== null){
			$player->recalculatePermissions();
		}
		$this->operators->save();
	}

	/**
	 * @return void
	 */
	public function removeOp(string $name){
		$this->operators->remove(strtolower($name));

		if(($player = $this->getPlayerExact($name)) !== null){
			$player->recalculatePermissions();
		}
		$this->operators->save();
	}

	/**
	 * @return void
	 */
	public function addWhitelist(string $name){
		$this->whitelist->set(strtolower($name), true);
		$this->whitelist->save();
	}

	/**
	 * @return void
	 */
	public function removeWhitelist(string $name){
		$this->whitelist->remove(strtolower($name));
		$this->whitelist->save();
	}

	public function isWhitelisted(string $name) : bool{
		return !$this->hasWhitelist() or $this->operators->exists($name, true) or $this->whitelist->exists($name, true);
	}

	public function isOp(string $name) : bool{
		return $this->operators->exists($name, true);
	}

	/**
	 * @return Config
	 */
	public function getWhitelisted(){
		return $this->whitelist;
	}

	/**
	 * @return Config
	 */
	public function getOps(){
		return $this->operators;
	}

	/**
	 * @return void
	 */
	public function reloadWhitelist(){
		$this->whitelist->reload();
	}

	/**
	 * @return string[][]
	 */
	public function getCommandAliases() : array{
		$section = $this->getProperty("aliases");
		$result = [];
		if(is_array($section)){
			foreach($section as $key => $value){
				$commands = [];
				if(is_array($value)){
					$commands = $value;
				}else{
					$commands[] = (string) $value;
				}

				$result[$key] = $commands;
			}
		}

		return $result;
	}

	public static function getInstance() : Server{
		if(self::$instance === null){
			throw new \RuntimeException("Attempt to retrieve Server instance outside server thread");
		}
		return self::$instance;
	}

	/**
	 * @return void
	 */
	public static function microSleep(int $microseconds){
		if(self::$sleeper === null){
			self::$sleeper = new \Threaded();
		}
		self::$sleeper->synchronized(function(int $ms) : void{
			Server::$sleeper->wait($ms);
		}, $microseconds);
	}

	public function __construct(\ClassLoader $autoloader, \AttachableThreadedLogger $logger, string $dataPath, string $pluginPath){
		if(self::$instance !== null){
			throw new \InvalidStateException("Only one server instance can exist at once");
		}
		self::$instance = $this;
		$this->tickSleeper = new SleeperHandler();
		$this->autoloader = $autoloader;
		$this->logger = $logger;

		try{
			if(!file_exists($dataPath . "worlds/")){
				mkdir($dataPath . "worlds/", 0777);
			}

			if(!file_exists($dataPath . "players/")){
				mkdir($dataPath . "players/", 0777);
			}

			if(!file_exists($pluginPath)){
				mkdir($pluginPath, 0777);
			}

			$this->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
			$this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;

			$this->logger->info("Loading pocketmine.yml...");
			if(!file_exists($this->dataPath . "pocketmine.yml")){
				$content = file_get_contents(\pocketmine\RESOURCE_PATH . "pocketmine.yml");
				if(\pocketmine\IS_DEVELOPMENT_BUILD){
					$content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content);
				}
				@file_put_contents($this->dataPath . "pocketmine.yml", $content);
			}
			$this->config = new Config($this->dataPath . "pocketmine.yml", Config::YAML, []);

			$this->logger->info("Loading server properties...");
			$this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, [
				"motd" => \pocketmine\NAME . " Server",
				"server-port" => 19132,
				"white-list" => false,
				"announce-player-achievements" => true,
				"spawn-protection" => 16,
				"max-players" => 20,
				"gamemode" => 0,
				"force-gamemode" => false,
				"hardcore" => false,
				"pvp" => true,
				"difficulty" => Level::DIFFICULTY_NORMAL,
				"generator-settings" => "",
				"level-name" => "world",
				"level-seed" => "",
				"level-type" => "DEFAULT",
				"enable-query" => true,
				"enable-rcon" => false,
				"rcon.password" => substr(base64_encode(random_bytes(20)), 3, 10),
				"auto-save" => true,
				"view-distance" => 8,
				"xbox-auth" => true,
				"language" => "eng"
			]);

			define('pocketmine\DEBUG', (int) $this->getProperty("debug.level", 1));

			$this->forceLanguage = (bool) $this->getProperty("settings.force-language", false);
			$this->baseLang = new BaseLang($this->getConfigString("language", $this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE)));
			$this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));

			if(\pocketmine\IS_DEVELOPMENT_BUILD and !((bool) $this->getProperty("settings.enable-dev-builds", false))){
				$this->logger->emergency($this->baseLang->translateString("pocketmine.server.devBuild.error1", [\pocketmine\NAME]));
				$this->logger->emergency($this->baseLang->translateString("pocketmine.server.devBuild.error2"));
				$this->logger->emergency($this->baseLang->translateString("pocketmine.server.devBuild.error3"));
				$this->logger->emergency($this->baseLang->translateString("pocketmine.server.devBuild.error4", ["settings.enable-dev-builds"]));
				$this->logger->emergency($this->baseLang->translateString("pocketmine.server.devBuild.error5", ["https://github.com/pmmp/PocketMine-MP/releases"]));
				$this->forceShutdown();
				return;
			}

			if($this->logger instanceof MainLogger){
				$this->logger->setLogDebug(\pocketmine\DEBUG > 1);
			}

			$this->memoryManager = new MemoryManager($this);

			$this->logger->info($this->getLanguage()->translateString("pocketmine.server.start", [TextFormat::AQUA . $this->getVersion() . TextFormat::RESET]));

			if(($poolSize = $this->getProperty("settings.async-workers", "auto")) === "auto"){
				$poolSize = 2;
				$processors = Utils::getCoreCount() - 2;

				if($processors > 0){
					$poolSize = max(1, $processors);
				}
			}else{
				$poolSize = max(1, (int) $poolSize);
			}

			$this->asyncPool = new AsyncPool($this, $poolSize, max(-1, (int) $this->getProperty("memory.async-worker-hard-limit", 256)), $this->autoloader, $this->logger);

			if($this->getProperty("network.batch-threshold", 256) >= 0){
				Network::$BATCH_THRESHOLD = (int) $this->getProperty("network.batch-threshold", 256);
			}else{
				Network::$BATCH_THRESHOLD = -1;
			}

			$this->networkCompressionLevel = $this->getProperty("network.compression-level", 7);
			if($this->networkCompressionLevel < 1 or $this->networkCompressionLevel > 9){
				$this->logger->warning("Invalid network compression level $this->networkCompressionLevel set, setting to default 7");
				$this->networkCompressionLevel = 7;
			}
			$this->networkCompressionAsync = (bool) $this->getProperty("network.async-compression", true);

			$this->doTitleTick = ((bool) $this->getProperty("console.title-tick", true)) && Terminal::hasFormattingCodes();

			$consoleSender = new ConsoleCommandSender();
			PermissionManager::getInstance()->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $consoleSender);

			$consoleNotifier = new SleeperNotifier();
			$this->console = new CommandReader($consoleNotifier);
			$this->tickSleeper->addNotifier($consoleNotifier, function() use ($consoleSender) : void{
				Timings::$serverCommandTimer->startTiming();
				while(($line = $this->console->getLine()) !== null){
					$ev = new ServerCommandEvent($consoleSender, $line);
					$ev->call();
					if(!$ev->isCancelled()){
						$this->dispatchCommand($ev->getSender(), $ev->getCommand());
					}
				}
				Timings::$serverCommandTimer->stopTiming();
			});
			$this->console->start(PTHREADS_INHERIT_NONE);

			if($this->getConfigBool("enable-rcon", false)){
				try{
					$this->rcon = new RCON(
						$this,
						$this->getConfigString("rcon.password", ""),
						$this->getConfigInt("rcon.port", $this->getPort()),
						$this->getIp(),
						$this->getConfigInt("rcon.max-clients", 50)
					);
				}catch(\Exception $e){
					$this->getLogger()->critical("RCON can't be started: " . $e->getMessage());
				}
			}

			$this->entityMetadata = new EntityMetadataStore();
			$this->playerMetadata = new PlayerMetadataStore();
			$this->levelMetadata = new LevelMetadataStore();

			$this->operators = new Config($this->dataPath . "ops.txt", Config::ENUM);
			$this->whitelist = new Config($this->dataPath . "white-list.txt", Config::ENUM);
			if(file_exists($this->dataPath . "banned.txt") and !file_exists($this->dataPath . "banned-players.txt")){
				@rename($this->dataPath . "banned.txt", $this->dataPath . "banned-players.txt");
			}
			@touch($this->dataPath . "banned-players.txt");
			$this->banByName = new BanList($this->dataPath . "banned-players.txt");
			$this->banByName->load();
			@touch($this->dataPath . "banned-ips.txt");
			$this->banByIP = new BanList($this->dataPath . "banned-ips.txt");
			$this->banByIP->load();

			$this->maxPlayers = $this->getConfigInt("max-players", 20);
			$this->setAutoSave($this->getConfigBool("auto-save", true));

			$this->onlineMode = $this->getConfigBool("xbox-auth", true);
			if($this->onlineMode){
				$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.auth.enabled"));
				$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.authProperty.enabled"));
			}else{
				$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.auth.disabled"));
				$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authWarning"));
				$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authProperty.disabled"));
			}

			if($this->getConfigBool("hardcore", false) and $this->getDifficulty() < Level::DIFFICULTY_HARD){
				$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
			}

			if(\pocketmine\DEBUG >= 0){
				@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
			}

			$this->logger->info($this->getLanguage()->translateString("pocketmine.server.networkStart", [$this->getIp(), $this->getPort()]));
			define("BOOTUP_RANDOM", random_bytes(16));
			$this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort());

			$this->getLogger()->debug("Server unique id: " . $this->getServerUniqueId());
			$this->getLogger()->debug("Machine unique id: " . Utils::getMachineUniqueId());

			$this->network = new Network($this);
			$this->network->setName($this->getMotd());

			$this->logger->info($this->getLanguage()->translateString("pocketmine.server.info", [
				$this->getName(),
				(\pocketmine\IS_DEVELOPMENT_BUILD ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET
			]));
			$this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));

			Timings::init();
			TimingsHandler::setEnabled((bool) $this->getProperty("settings.enable-profiling", false));

			$this->commandMap = new SimpleCommandMap($this);

			Entity::init();
			Tile::init();
			BlockFactory::init();
			Enchantment::init();
			ItemFactory::init();
			Item::initCreativeItems();
			Biome::init();

			LevelProviderManager::init();
			if(extension_loaded("leveldb")){
				$this->logger->debug($this->getLanguage()->translateString("pocketmine.debug.enable"));
			}
			GeneratorManager::registerDefaultGenerators();

			$this->craftingManager = new CraftingManager();

			$this->resourceManager = new ResourcePackManager($this->getDataPath() . "resource_packs" . DIRECTORY_SEPARATOR, $this->logger);

			$this->pluginManager = new PluginManager($this, $this->commandMap, ((bool) $this->getProperty("plugins.legacy-data-dir", true)) ? null : $this->getDataPath() . "plugin_data" . DIRECTORY_SEPARATOR);
			$this->profilingTickRate = (float) $this->getProperty("settings.profile-report-trigger", 20);
			$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
			$this->pluginManager->registerInterface(new ScriptPluginLoader());

			register_shutdown_function([$this, "crashDump"]);

			$this->queryRegenerateTask = new QueryRegenerateEvent($this);

			$this->updater = new AutoUpdater($this, $this->getProperty("auto-updater.host", "update.pmmp.io"));

			$this->pluginManager->loadPlugins($this->pluginPath);
			$this->enablePlugins(PluginLoadOrder::STARTUP);

			$this->network->registerInterface(new RakLibInterface($this));

			foreach((array) $this->getProperty("worlds", []) as $name => $options){
				if($options === null){
					$options = [];
				}elseif(!is_array($options)){
					continue;
				}
				if(!$this->loadLevel($name)){
					if(isset($options["generator"])){
						$generatorOptions = explode(":", $options["generator"]);
						$generator = GeneratorManager::getGenerator(array_shift($generatorOptions));
						if(count($options) > 0){
							$options["preset"] = implode(":", $generatorOptions);
						}
					}else{
						$generator = GeneratorManager::getGenerator("default");
					}

					$this->generateLevel($name, Generator::convertSeed((string) ($options["seed"] ?? "")), $generator, $options);
				}
			}

			if($this->getDefaultLevel() === null){
				$default = $this->getConfigString("level-name", "world");
				if(trim($default) == ""){
					$this->getLogger()->warning("level-name cannot be null, using default");
					$default = "world";
					$this->setConfigString("level-name", "world");
				}
				if(!$this->loadLevel($default)){
					$this->generateLevel($default, Generator::convertSeed($this->getConfigString("level-seed")));
				}

				$this->setDefaultLevel($this->getLevelByName($default));
			}

			if($this->properties->hasChanged()){
				$this->properties->save();
			}

			if(!($this->getDefaultLevel() instanceof Level)){
				$this->getLogger()->emergency($this->getLanguage()->translateString("pocketmine.level.defaultError"));
				$this->forceShutdown();

				return;
			}

			if($this->getProperty("ticks-per.autosave", 6000) > 0){
				$this->autoSaveTicks = (int) $this->getProperty("ticks-per.autosave", 6000);
			}

			$this->enablePlugins(PluginLoadOrder::POSTWORLD);

			$this->start();
		}catch(\Throwable $e){
			$this->exceptionHandler($e);
		}
	}

	/**
	 * @param TextContainer|string $message
	 * @param CommandSender[]|null $recipients
	 */
	public function broadcastMessage($message, array $recipients = null) : int{
		if(!is_array($recipients)){
			return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
		}

		foreach($recipients as $recipient){
			$recipient->sendMessage($message);
		}

		return count($recipients);
	}

	/**
	 * @param Player[]|null $recipients
	 */
	public function broadcastTip(string $tip, array $recipients = null) : int{
		if(!is_array($recipients)){
			/** @var Player[] $recipients */
			$recipients = [];
			foreach(PermissionManager::getInstance()->getPermissionSubscriptions(self::BROADCAST_CHANNEL_USERS) as $permissible){
				if($permissible instanceof Player and $permissible->hasPermission(self::BROADCAST_CHANNEL_USERS)){
					$recipients[spl_object_hash($permissible)] = $permissible; // do not send messages directly, or some might be repeated
				}
			}
		}

		foreach($recipients as $recipient){
			$recipient->sendTip($tip);
		}

		return count($recipients);
	}

	/**
	 * @param Player[]|null $recipients
	 */
	public function broadcastPopup(string $popup, array $recipients = null) : int{
		if(!is_array($recipients)){
			/** @var Player[] $recipients */
			$recipients = [];

			foreach(PermissionManager::getInstance()->getPermissionSubscriptions(self::BROADCAST_CHANNEL_USERS) as $permissible){
				if($permissible instanceof Player and $permissible->hasPermission(self::BROADCAST_CHANNEL_USERS)){
					$recipients[spl_object_hash($permissible)] = $permissible; // do not send messages directly, or some might be repeated
				}
			}
		}

		foreach($recipients as $recipient){
			$recipient->sendPopup($popup);
		}

		return count($recipients);
	}

	/**
	 * @param int           $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
	 * @param int           $stay Duration in ticks to stay on screen for
	 * @param int           $fadeOut Duration in ticks for fade-out.
	 * @param Player[]|null $recipients
	 */
	public function broadcastTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1, array $recipients = null) : int{
		if(!is_array($recipients)){
			/** @var Player[] $recipients */
			$recipients = [];

			foreach(PermissionManager::getInstance()->getPermissionSubscriptions(self::BROADCAST_CHANNEL_USERS) as $permissible){
				if($permissible instanceof Player and $permissible->hasPermission(self::BROADCAST_CHANNEL_USERS)){
					$recipients[spl_object_hash($permissible)] = $permissible; // do not send messages directly, or some might be repeated
				}
			}
		}

		foreach($recipients as $recipient){
			$recipient->addTitle($title, $subtitle, $fadeIn, $stay, $fadeOut);
		}

		return count($recipients);
	}

	/**
	 * @param TextContainer|string $message
	 */
	public function broadcast($message, string $permissions) : int{
		/** @var CommandSender[] $recipients */
		$recipients = [];
		foreach(explode(";", $permissions) as $permission){
			foreach(PermissionManager::getInstance()->getPermissionSubscriptions($permission) as $permissible){
				if($permissible instanceof CommandSender and $permissible->hasPermission($permission)){
					$recipients[spl_object_hash($permissible)] = $permissible; // do not send messages directly, or some might be repeated
				}
			}
		}

		foreach($recipients as $recipient){
			$recipient->sendMessage($message);
		}

		return count($recipients);
	}

	/**
	 * Broadcasts a Minecraft packet to a list of players
	 *
	 * @param Player[]   $players
	 *
	 * @return void
	 */
	public function broadcastPacket(array $players, DataPacket $packet){
		$packet->encode();
		$this->batchPackets($players, [$packet], false);
	}

	/**
	 * Broadcasts a list of packets in a batch to a list of players
	 *
	 * @param Player[]     $players
	 * @param DataPacket[] $packets
	 *
	 * @return void
	 */
	public function batchPackets(array $players, array $packets, bool $forceSync = false, bool $immediate = false){
		if(count($packets) === 0){
			throw new \InvalidArgumentException("Cannot send empty batch");
		}
		Timings::$playerNetworkTimer->startTiming();

		$targets = array_filter($players, function(Player $player) : bool{ return $player->isConnected(); });

		if(count($targets) > 0){
			$pk = new BatchPacket();

			foreach($packets as $p){
				$pk->addPacket($p);
			}

			if(Network::$BATCH_THRESHOLD >= 0 and strlen($pk->payload) >= Network::$BATCH_THRESHOLD){
				$pk->setCompressionLevel($this->networkCompressionLevel);
			}else{
				$pk->setCompressionLevel(0); //Do not compress packets under the threshold
				$forceSync = true;
			}

			if(!$forceSync and !$immediate and $this->networkCompressionAsync){
				$task = new CompressBatchedTask($pk, $targets);
				$this->asyncPool->submitTask($task);
			}else{
				$this->broadcastPacketsCallback($pk, $targets, $immediate);
			}
		}

		Timings::$playerNetworkTimer->stopTiming();
	}

	/**
	 * @param Player[]    $players
	 *
	 * @return void
	 */
	public function broadcastPacketsCallback(BatchPacket $pk, array $players, bool $immediate = false){
		if(!$pk->isEncoded){
			$pk->encode();
		}

		foreach($players as $i){
			$i->sendDataPacket($pk, false, $immediate);
		}
	}

	/**
	 * @return void
	 */
	public function enablePlugins(int $type){
		foreach($this->pluginManager->getPlugins() as $plugin){
			if(!$plugin->isEnabled() and $plugin->getDescription()->getOrder() === $type){
				$this->enablePlugin($plugin);
			}
		}

		if($type === PluginLoadOrder::POSTWORLD){
			$this->commandMap->registerServerAliases();
			DefaultPermissions::registerCorePermissions();
		}
	}

	/**
	 * @return void
	 */
	public function enablePlugin(Plugin $plugin){
		$this->pluginManager->enablePlugin($plugin);
	}

	/**
	 * @return void
	 */
	public function disablePlugins(){
		$this->pluginManager->disablePlugins();
	}

	/**
	 * Executes a command from a CommandSender
	 */
	public function dispatchCommand(CommandSender $sender, string $commandLine, bool $internal = false) : bool{
		if(!$internal){
			$ev = new CommandEvent($sender, $commandLine);
			$ev->call();
			if($ev->isCancelled()){
				return false;
			}

			$commandLine = $ev->getCommand();
		}

		if($this->commandMap->dispatch($sender, $commandLine)){
			return true;
		}

		$sender->sendMessage($this->getLanguage()->translateString(TextFormat::RED . "%commands.generic.notFound"));

		return false;
	}

	/**
	 * @return void
	 */
	public function reload(){
		$this->logger->info("Saving worlds...");

		foreach($this->levels as $level){
			$level->save();
		}

		$this->pluginManager->disablePlugins();
		$this->pluginManager->clearPlugins();
		PermissionManager::getInstance()->clearPermissions();
		$this->commandMap->clearCommands();

		$this->logger->info("Reloading properties...");
		$this->properties->reload();
		$this->maxPlayers = $this->getConfigInt("max-players", 20);

		if($this->getConfigBool("hardcore", false) and $this->getDifficulty() < Level::DIFFICULTY_HARD){
			$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
		}

		$this->banByIP->load();
		$this->banByName->load();
		$this->reloadWhitelist();
		$this->operators->reload();

		foreach($this->getIPBans()->getEntries() as $entry){
			$this->getNetwork()->blockAddress($entry->getName(), -1);
		}

		$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
		$this->pluginManager->registerInterface(new ScriptPluginLoader());
		$this->pluginManager->loadPlugins($this->pluginPath);
		$this->enablePlugins(PluginLoadOrder::STARTUP);
		$this->enablePlugins(PluginLoadOrder::POSTWORLD);
		TimingsHandler::reload();
	}

	/**
	 * Shuts the server down correctly
	 *
	 * @return void
	 */
	public function shutdown(){
		$this->isRunning = false;
	}

	/**
	 * @return void
	 */
	public function forceShutdown(){
		if($this->hasStopped){
			return;
		}

		if($this->doTitleTick){
			echo "\x1b]0;\x07";
		}

		try{
			if(!$this->isRunning()){
				$this->sendUsage(SendUsageTask::TYPE_CLOSE);
			}

			$this->hasStopped = true;

			$this->shutdown();
			if($this->rcon instanceof RCON){
				$this->rcon->stop();
			}

			if((bool) $this->getProperty("network.upnp-forwarding", false)){
				$this->logger->info("[UPnP] Removing port forward...");
				UPnP::RemovePortForward($this->getPort());
			}

			if($this->pluginManager instanceof PluginManager){
				$this->getLogger()->debug("Disabling all plugins");
				$this->pluginManager->disablePlugins();
			}

			foreach($this->players as $player){
				$player->close($player->getLeaveMessage(), $this->getProperty("settings.shutdown-message", "Server closed"));
			}

			$this->getLogger()->debug("Unloading all worlds");
			foreach($this->getLevels() as $level){
				$this->unloadLevel($level, true);
			}

			$this->getLogger()->debug("Removing event handlers");
			HandlerList::unregisterAll();

			if($this->asyncPool instanceof AsyncPool){
				$this->getLogger()->debug("Shutting down async task worker pool");
				$this->asyncPool->shutdown();
			}

			if($this->properties !== null and $this->properties->hasChanged()){
				$this->getLogger()->debug("Saving properties");
				$this->properties->save();
			}

			if($this->console instanceof CommandReader){
				$this->getLogger()->debug("Closing console");
				$this->console->shutdown();
				$this->console->notify();
			}

			if($this->network instanceof Network){
				$this->getLogger()->debug("Stopping network interfaces");
				foreach($this->network->getInterfaces() as $interface){
					$this->getLogger()->debug("Stopping network interface " . get_class($interface));
					$interface->shutdown();
					$this->network->unregisterInterface($interface);
				}
			}
		}catch(\Throwable $e){
			$this->logger->logException($e);
			$this->logger->emergency("Crashed while crashing, killing process");
			@Utils::kill(getmypid());
		}

	}

	/**
	 * @return QueryRegenerateEvent
	 */
	public function getQueryInformation(){
		return $this->queryRegenerateTask;
	}

	/**
	 * Starts the PocketMine-MP server and starts processing ticks and packets
	 */
	private function start() : void{
		if($this->getConfigBool("enable-query", true)){
			$this->queryHandler = new QueryHandler();
		}

		foreach($this->getIPBans()->getEntries() as $entry){
			$this->network->blockAddress($entry->getName(), -1);
		}

		if((bool) $this->getProperty("settings.send-usage", true)){
			$this->sendUsageTicker = 6000;
			$this->sendUsage(SendUsageTask::TYPE_OPEN);
		}

		if((bool) $this->getProperty("network.upnp-forwarding", false)){
			$this->logger->info("[UPnP] Trying to port forward...");
			try{
				UPnP::PortForward($this->getPort());
			}catch(\Exception $e){
				$this->logger->alert("UPnP portforward failed: " . $e->getMessage());
			}
		}

		$this->tickCounter = 0;

		if(function_exists("pcntl_signal")){
			pcntl_signal(SIGTERM, [$this, "handleSignal"]);
			pcntl_signal(SIGINT, [$this, "handleSignal"]);
			pcntl_signal(SIGHUP, [$this, "handleSignal"]);
			$this->dispatchSignals = true;
		}

		$this->logger->info($this->getLanguage()->translateString("pocketmine.server.defaultGameMode", [self::getGamemodeString($this->getGamemode())]));

		$this->logger->info($this->getLanguage()->translateString("pocketmine.server.donate", [TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET]));
		$this->logger->info($this->getLanguage()->translateString("pocketmine.server.startFinished", [round(microtime(true) - \pocketmine\START_TIME, 3)]));

		$this->tickProcessor();
		$this->forceShutdown();
	}

	/**
	 * @param int $signo
	 *
	 * @return void
	 */
	public function handleSignal($signo){
		if($signo === SIGTERM or $signo === SIGINT or $signo === SIGHUP){
			$this->shutdown();
		}
	}

	/**
	 * @param mixed[][]|null $trace
	 * @phpstan-param list<array<string, mixed>>|null $trace
	 *
	 * @return void
	 */
	public function exceptionHandler(\Throwable $e, $trace = null){
		while(@ob_end_flush()){}
		global $lastError;

		if($trace === null){
			$trace = $e->getTrace();
		}

		$errstr = $e->getMessage();
		$errfile = $e->getFile();
		$errline = $e->getLine();

		$errstr = preg_replace('/\s+/', ' ', trim($errstr));

		$errfile = Utils::cleanPath($errfile);

		$this->logger->logException($e, $trace);

		$lastError = [
			"type" => get_class($e),
			"message" => $errstr,
			"fullFile" => $e->getFile(),
			"file" => $errfile,
			"line" => $errline,
			"trace" => $trace
		];

		global $lastExceptionError, $lastError;
		$lastExceptionError = $lastError;
		$this->crashDump();
	}

	/**
	 * @return void
	 */
	public function crashDump(){
		while(@ob_end_flush()){}
		if(!$this->isRunning){
			return;
		}
		if($this->sendUsageTicker > 0){
			$this->sendUsage(SendUsageTask::TYPE_CLOSE);
		}
		$this->hasStopped = false;

		ini_set("error_reporting", '0');
		ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems
		try{
			$this->logger->emergency($this->getLanguage()->translateString("pocketmine.crash.create"));
			$dump = new CrashDump($this);

			$this->logger->emergency($this->getLanguage()->translateString("pocketmine.crash.submit", [$dump->getPath()]));

			if($this->getProperty("auto-report.enabled", true) !== false){
				$report = true;

				$stamp = $this->getDataPath() . "crashdumps/.last_crash";
				$crashInterval = 120; //2 minutes
				if(file_exists($stamp) and !($report = (filemtime($stamp) + $crashInterval < time()))){
					$this->logger->debug("Not sending crashdump due to last crash less than $crashInterval seconds ago");
				}
				@touch($stamp); //update file timestamp

				$plugin = $dump->getData()["plugin"];
				if(is_string($plugin)){
					$p = $this->pluginManager->getPlugin($plugin);
					if($p instanceof Plugin and !($p->getPluginLoader() instanceof PharPluginLoader)){
						$this->logger->debug("Not sending crashdump due to caused by non-phar plugin");
						$report = false;
					}
				}

				if($dump->getData()["error"]["type"] === \ParseError::class){
					$report = false;
				}

				if(strrpos(\pocketmine\GIT_COMMIT, "-dirty") !== false or \pocketmine\GIT_COMMIT === str_repeat("00", 20)){
					$this->logger->debug("Not sending crashdump due to locally modified");
					$report = false; //Don't send crashdumps for locally modified builds
				}

				if($report){
					$url = ((bool) $this->getProperty("auto-report.use-https", true) ? "https" : "http") . "://" . $this->getProperty("auto-report.host", "crash.pmmp.io") . "/submit/api";
					$reply = Internet::postURL($url, [
						"report" => "yes",
						"name" => $this->getName() . " " . $this->getPocketMineVersion(),
						"email" => "crash@pocketmine.net",
						"reportPaste" => base64_encode($dump->getEncodedData())
					]);

					if($reply !== false and ($data = json_decode($reply)) !== null and isset($data->crashId) and isset($data->crashUrl)){
						$reportId = $data->crashId;
						$reportUrl = $data->crashUrl;
						$this->logger->emergency($this->getLanguage()->translateString("pocketmine.crash.archive", [$reportUrl, $reportId]));
					}
				}
			}
		}catch(\Throwable $e){
			$this->logger->logException($e);
			try{
				$this->logger->critical($this->getLanguage()->translateString("pocketmine.crash.error", [$e->getMessage()]));
			}catch(\Throwable $e){}
		}

		$this->forceShutdown();
		$this->isRunning = false;

		//Force minimum uptime to be >= 120 seconds, to reduce the impact of spammy crash loops
		$spacing = ((int) \pocketmine\START_TIME) - time() + 120;
		if($spacing > 0){
			echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL;
			sleep($spacing);
		}
		@Utils::kill(getmypid());
		exit(1);
	}

	/**
	 * @return mixed[]
	 */
	public function __debugInfo(){
		return [];
	}

	public function getTickSleeper() : SleeperHandler{
		return $this->tickSleeper;
	}

	private function tickProcessor() : void{
		$this->nextTick = microtime(true);

		while($this->isRunning){
			$this->tick();

			//sleeps are self-correcting - if we undersleep 1ms on this tick, we'll sleep an extra ms on the next tick
			$this->tickSleeper->sleepUntil($this->nextTick);
		}
	}

	/**
	 * @return void
	 */
	public function onPlayerLogin(Player $player){
		if($this->sendUsageTicker > 0){
			$this->uniquePlayers[$player->getRawUniqueId()] = $player->getRawUniqueId();
		}

		$this->loggedInPlayers[$player->getRawUniqueId()] = $player;
	}

	/**
	 * @return void
	 */
	public function onPlayerLogout(Player $player){
		unset($this->loggedInPlayers[$player->getRawUniqueId()]);
	}

	/**
	 * @return void
	 */
	public function addPlayer(Player $player){
		$this->players[spl_object_hash($player)] = $player;
	}

	/**
	 * @return void
	 */
	public function removePlayer(Player $player){
		unset($this->players[spl_object_hash($player)]);
	}

	/**
	 * @return void
	 */
	public function addOnlinePlayer(Player $player){
		$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin(), $player->getXuid());

		$this->playerList[$player->getRawUniqueId()] = $player;
	}

	/**
	 * @return void
	 */
	public function removeOnlinePlayer(Player $player){
		if(isset($this->playerList[$player->getRawUniqueId()])){
			unset($this->playerList[$player->getRawUniqueId()]);

			$this->removePlayerListData($player->getUniqueId());
		}
	}

	/**
	 * @param Player[]|null $players
	 *
	 * @return void
	 */
	public function updatePlayerListData(UUID $uuid, int $entityId, string $name, Skin $skin, string $xboxUserId = "", array $players = null){
		$pk = new PlayerListPacket();
		$pk->type = PlayerListPacket::TYPE_ADD;

		$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, SkinAdapterSingleton::get()->toSkinData($skin), $xboxUserId);

		$this->broadcastPacket($players ?? $this->playerList, $pk);
	}

	/**
	 * @param Player[]|null $players
	 *
	 * @return void
	 */
	public function removePlayerListData(UUID $uuid, array $players = null){
		$pk = new PlayerListPacket();
		$pk->type = PlayerListPacket::TYPE_REMOVE;
		$pk->entries[] = PlayerListEntry::createRemovalEntry($uuid);
		$this->broadcastPacket($players ?? $this->playerList, $pk);
	}

	/**
	 * @return void
	 */
	public function sendFullPlayerListData(Player $p){
		$pk = new PlayerListPacket();
		$pk->type = PlayerListPacket::TYPE_ADD;
		foreach($this->playerList as $player){
			$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), SkinAdapterSingleton::get()->toSkinData($player->getSkin()), $player->getXuid());
		}

		$p->dataPacket($pk);
	}

	private function checkTickUpdates(int $currentTick, float $tickTime) : void{
		foreach($this->players as $p){
			if(!$p->loggedIn and ($tickTime - $p->creationTime) >= 10){
				$p->close("", "Login timeout");
			}
		}

		//Do level ticks
		foreach($this->levels as $k => $level){
			if(!isset($this->levels[$k])){
				// Level unloaded during the tick of a level earlier in this loop, perhaps by plugin
				continue;
			}

			$levelTime = microtime(true);
			$level->doTick($currentTick);
			$tickMs = (microtime(true) - $levelTime) * 1000;
			$level->tickRateTime = $tickMs;
			if($tickMs >= 50){
				$this->getLogger()->debug(sprintf("World \"%s\" took too long to tick: %gms (%g ticks)", $level->getName(), $tickMs, round($tickMs / 50, 2)));
			}
		}
	}

	/**
	 * @return void
	 */
	public function doAutoSave(){
		if($this->getAutoSave()){
			Timings::$worldSaveTimer->startTiming();
			foreach($this->players as $index => $player){
				if($player->spawned){
					$player->save();
				}elseif(!$player->isConnected()){
					$this->removePlayer($player);
				}
			}

			foreach($this->getLevels() as $level){
				$level->save(false);
			}
			Timings::$worldSaveTimer->stopTiming();
		}
	}

	/**
	 * @param int $type
	 *
	 * @return void
	 */
	public function sendUsage($type = SendUsageTask::TYPE_STATUS){
		if((bool) $this->getProperty("anonymous-statistics.enabled", true)){
			$this->asyncPool->submitTask(new SendUsageTask($this, $type, $this->uniquePlayers));
		}
		$this->uniquePlayers = [];
	}

	/**
	 * @return BaseLang
	 */
	public function getLanguage(){
		return $this->baseLang;
	}

	public function isLanguageForced() : bool{
		return $this->forceLanguage;
	}

	/**
	 * @return Network
	 */
	public function getNetwork(){
		return $this->network;
	}

	/**
	 * @return MemoryManager
	 */
	public function getMemoryManager(){
		return $this->memoryManager;
	}

	private function titleTick() : void{
		Timings::$titleTickTimer->startTiming();
		$d = Utils::getRealMemoryUsage();

		$u = Utils::getMemoryUsage(true);
		$usage = sprintf("%g/%g/%g/%g MB @ %d threads", round(($u[0] / 1024) / 1024, 2), round(($d[0] / 1024) / 1024, 2), round(($u[1] / 1024) / 1024, 2), round(($u[2] / 1024) / 1024, 2), Utils::getThreadCount());

		echo "\x1b]0;" . $this->getName() . " " .
			$this->getPocketMineVersion() .
			" | Online " . count($this->players) . "/" . $this->getMaxPlayers() .
			" | Memory " . $usage .
			" | U " . round($this->network->getUpload() / 1024, 2) .
			" D " . round($this->network->getDownload() / 1024, 2) .
			" kB/s | TPS " . $this->getTicksPerSecondAverage() .
			" | Load " . $this->getTickUsageAverage() . "%\x07";

		Timings::$titleTickTimer->stopTiming();
	}

	/**
	 * @return void
	 *
	 * TODO: move this to Network
	 */
	public function handlePacket(AdvancedSourceInterface $interface, string $address, int $port, string $payload){
		try{
			if(strlen($payload) > 2 and substr($payload, 0, 2) === "\xfe\xfd" and $this->queryHandler instanceof QueryHandler){
				$this->queryHandler->handle($interface, $address, $port, $payload);
			}else{
				$this->logger->debug("Unhandled raw packet from $address $port: " . base64_encode($payload));
			}
		}catch(\Throwable $e){
			$this->logger->logException($e);

			$this->getNetwork()->blockAddress($address, 600);
		}
		//TODO: add raw packet events
	}

	/**
	 * Tries to execute a server tick
	 */
	private function tick() : void{
		$tickTime = microtime(true);
		if(($tickTime - $this->nextTick) < -0.025){ //Allow half a tick of diff
			return;
		}

		Timings::$serverTickTimer->startTiming();

		++$this->tickCounter;

		Timings::$connectionTimer->startTiming();
		$this->network->processInterfaces();
		Timings::$connectionTimer->stopTiming();

		Timings::$schedulerTimer->startTiming();
		$this->pluginManager->tickSchedulers($this->tickCounter);
		Timings::$schedulerTimer->stopTiming();

		Timings::$schedulerAsyncTimer->startTiming();
		$this->asyncPool->collectTasks();
		Timings::$schedulerAsyncTimer->stopTiming();

		$this->checkTickUpdates($this->tickCounter, $tickTime);

		foreach($this->players as $player){
			$player->checkNetwork();
		}

		if(($this->tickCounter % 20) === 0){
			if($this->doTitleTick){
				$this->titleTick();
			}
			$this->currentTPS = 20;
			$this->currentUse = 0;

			($this->queryRegenerateTask = new QueryRegenerateEvent($this))->call();

			$this->network->updateName();
			$this->network->resetStatistics();
		}

		if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){
			$this->autoSaveTicker = 0;
			$this->getLogger()->debug("[Auto Save] Saving worlds...");
			$start = microtime(true);
			$this->doAutoSave();
			$time = (microtime(true) - $start);
			$this->getLogger()->debug("[Auto Save] Save completed in " . ($time >= 1 ? round($time, 3) . "s" : round($time * 1000) . "ms"));
		}

		if($this->sendUsageTicker > 0 and --$this->sendUsageTicker === 0){
			$this->sendUsageTicker = 6000;
			$this->sendUsage(SendUsageTask::TYPE_STATUS);
		}

		if(($this->tickCounter % 100) === 0){
			foreach($this->levels as $level){
				$level->clearCache();
			}

			if($this->getTicksPerSecondAverage() < 12){
				$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.tickOverload"));
			}
		}

		if($this->dispatchSignals and $this->tickCounter % 5 === 0){
			pcntl_signal_dispatch();
		}

		$this->getMemoryManager()->check();

		Timings::$serverTickTimer->stopTiming();

		$now = microtime(true);
		$this->currentTPS = min(20, 1 / max(0.001, $now - $tickTime));
		$this->currentUse = min(1, ($now - $tickTime) / 0.05);

		TimingsHandler::tick($this->currentTPS <= $this->profilingTickRate);

		$idx = $this->tickCounter % 20;
		$this->tickAverage[$idx] = $this->currentTPS;
		$this->useAverage[$idx] = $this->currentUse;

		if(($this->nextTick - $tickTime) < -1){
			$this->nextTick = $tickTime;
		}else{
			$this->nextTick += 0.05;
		}
	}

	/**
	 * Called when something attempts to serialize the server instance.
	 *
	 * @throws \BadMethodCallException because Server instances cannot be serialized
	 */
	public function __sleep(){
		throw new \BadMethodCallException("Cannot serialize Server instance");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\snooze;

use function assert;
use function microtime;

/**
 * Manages a Threaded sleeper which can be waited on for notifications. Calls callbacks for attached notifiers when
 * notifications are received from the notifiers.
 */
class SleeperHandler{
	/** @var ThreadedSleeper */
	private $threadedSleeper;

	/** @var SleeperNotifier[] */
	private $notifiers = [];
	/**
	 * @var callable[]
	 * this is stored separately from notifiers otherwise pthreads would break closures referencing variables
	 */
	private $handlers = [];

	/** @var int */
	private $nextSleeperId = 0;

	public function __construct(){
		$this->threadedSleeper = new ThreadedSleeper();
	}

	public function getThreadedSleeper() : ThreadedSleeper{
		return $this->threadedSleeper;
	}

	/**
	 * @param SleeperNotifier $notifier
	 * @param callable        $handler Called when the notifier wakes the server up, of the signature `function() : void`
	 */
	public function addNotifier(SleeperNotifier $notifier, callable $handler) : void{
		$id = $this->nextSleeperId++;
		$notifier->attachSleeper($this->threadedSleeper, $id);
		$this->notifiers[$id] = $notifier;
		$this->handlers[$id] = $handler;
	}

	/**
	 * Removes a notifier from the sleeper. Note that this does not prevent the notifier waking the sleeper up - it just
	 * stops the notifier getting actions processed from the main thread.
	 *
	 * @param SleeperNotifier $notifier
	 */
	public function removeNotifier(SleeperNotifier $notifier) : void{
		unset($this->notifiers[$notifier->getSleeperId()], $this->handlers[$notifier->getSleeperId()]);
	}

	/**
	 * Sleeps until the given timestamp. Sleep may be interrupted by notifications, which will be processed before going
	 * back to sleep.
	 *
	 * @param float $unixTime
	 */
	public function sleepUntil(float $unixTime) : void{
		while(true){
			$this->processNotifications();

			$sleepTime = (int) (($unixTime - microtime(true)) * 1000000);
			if($sleepTime > 0){
				$this->threadedSleeper->sleep($sleepTime);
			}else{
				break;
			}
		}
	}

	/**
	 * Blocks until notifications are received, then processes notifications. Will not sleep if notifications are
	 * already waiting.
	 */
	public function sleepUntilNotification() : void{
		$this->threadedSleeper->sleep(0);
		$this->processNotifications();
	}

	/**
	 * Processes any notifications from notifiers and calls handlers for received notifications.
	 */
	public function processNotifications() : void{
		while($this->threadedSleeper->hasNotifications()){
			$processed = 0;
			foreach($this->notifiers as $id => $notifier){
				if($notifier->hasNotification()){
					++$processed;

					$notifier->clearNotification();
					if(isset($this->notifiers[$id])){
						/*
						 * Notifiers can end up getting removed due to a previous notifier's callback. Since a foreach
						 * iterates on a copy of the notifiers array, the removal isn't reflected by the foreach. This
						 * ensures that we do not attempt to fire callbacks for notifiers which have been removed.
						 */
						assert(isset($this->handlers[$id]));
						$this->handlers[$id]();
					}
				}
			}

			assert($processed > 0);

			$this->threadedSleeper->clearNotifications($processed);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\snooze;

use function assert;

/**
 * Notifiable Threaded class which tracks counts of notifications it receives.
 */
class ThreadedSleeper extends \Threaded{
	/**
	 * @var int
	 */
	private $notifCount = 0;

	/**
	 * Called from the main thread to wait for notifications, or until timeout.
	 *
	 * @param int $timeout defaults to 0 (no timeout, wait indefinitely)
	 */
	public function sleep(int $timeout = 0) : void{
		$this->synchronized(function(int $timeout) : void{
			assert($this->notifCount >= 0, "notification count should be >= 0, got $this->notifCount");
			if($this->notifCount === 0){
				$this->wait($timeout);
			}
		}, $timeout);
	}

	/**
	 * Call this from sleeper notifiers to wake up the main thread.
	 */
	public function wakeup() : void{
		$this->synchronized(function(){
			++$this->notifCount;
			$this->notify();
		});
	}

	/**
	 * Decreases pending notification count by the given number.
	 *
	 * @param int $notifCount
	 */
	public function clearNotifications(int $notifCount) : void{
		$this->synchronized(function() use ($notifCount) : void{
			/*
			child threads can flag themselves as having a notification, which can get detected while the server is
			awake. In these cases it's possible for the notification count to drop below zero due to getting
			decremented here before incrementing on the child thread. This is quite a psychotic edge case, but it
			means that it's necessary to synchronize for this, even though it's a simple statement.
			*/
			$this->notifCount -= $notifCount;
			assert($this->notifCount >= 0, "notification count should be >= 0, got $this->notifCount");
		});
	}

	public function hasNotifications() : bool{
		//don't need to synchronize here, pthreads automatically locks/unlocks
		return $this->notifCount > 0;
	}
}
<?php

/*
 * PocketMine Standard PHP Library
 * Copyright (C) 2014-2018 PocketMine Team <https://github.com/PocketMine/PocketMine-SPL>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
*/

interface LogLevel{
	const EMERGENCY = "emergency";
	const ALERT = "alert";
	const CRITICAL = "critical";
	const ERROR = "error";
	const WARNING = "warning";
	const NOTICE = "notice";
	const INFO = "info";
	const DEBUG = "debug";
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;

use function array_change_key_case;
use function array_keys;
use function array_pop;
use function array_shift;
use function basename;
use function count;
use function date;
use function explode;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function implode;
use function is_array;
use function is_bool;
use function json_decode;
use function json_encode;
use function preg_match_all;
use function preg_replace;
use function serialize;
use function str_replace;
use function strlen;
use function strtolower;
use function substr;
use function trim;
use function unserialize;
use function yaml_emit;
use function yaml_parse;
use const CASE_LOWER;
use const JSON_BIGINT_AS_STRING;
use const JSON_PRETTY_PRINT;

/**
 * Config Class for simple config manipulation of multiple formats.
 */
class Config{
	public const DETECT = -1; //Detect by file extension
	public const PROPERTIES = 0; // .properties
	public const CNF = Config::PROPERTIES; // .cnf
	public const JSON = 1; // .js, .json
	public const YAML = 2; // .yml, .yaml
	//const EXPORT = 3; // .export, .xport
	public const SERIALIZED = 4; // .sl
	public const ENUM = 5; // .txt, .list, .enum
	public const ENUMERATION = Config::ENUM;

	/**
	 * @var mixed[]
	 * @phpstan-var array<string, mixed>
	 */
	private $config = [];

	/**
	 * @var mixed[]
	 * @phpstan-var array<string, mixed>
	 */
	private $nestedCache = [];

	/** @var string */
	private $file;
	/** @var bool */
	private $correct = false;
	/** @var int */
	private $type = Config::DETECT;
	/** @var int */
	private $jsonOptions = JSON_PRETTY_PRINT | JSON_BIGINT_AS_STRING;

	/** @var bool */
	private $changed = false;

	/** @var int[] */
	public static $formats = [
		"properties" => Config::PROPERTIES,
		"cnf" => Config::CNF,
		"conf" => Config::CNF,
		"config" => Config::CNF,
		"json" => Config::JSON,
		"js" => Config::JSON,
		"yml" => Config::YAML,
		"yaml" => Config::YAML,
		//"export" => Config::EXPORT,
		//"xport" => Config::EXPORT,
		"sl" => Config::SERIALIZED,
		"serialize" => Config::SERIALIZED,
		"txt" => Config::ENUM,
		"list" => Config::ENUM,
		"enum" => Config::ENUM
	];

	/**
	 * @param string  $file    Path of the file to be loaded
	 * @param int     $type    Config type to load, -1 by default (detect)
	 * @param mixed[] $default Array with the default values that will be written to the file if it did not exist
	 * @param null    $correct reference parameter, Sets correct to true if everything has been loaded correctly
	 * @phpstan-param array<string, mixed> $default
	 */
	public function __construct(string $file, int $type = Config::DETECT, array $default = [], &$correct = null){
		$this->load($file, $type, $default);
		$correct = $this->correct;
	}

	/**
	 * Removes all the changes in memory and loads the file again
	 *
	 * @return void
	 */
	public function reload(){
		$this->config = [];
		$this->nestedCache = [];
		$this->correct = false;
		$this->load($this->file, $this->type);
	}

	public function hasChanged() : bool{
		return $this->changed;
	}

	public function setChanged(bool $changed = true) : void{
		$this->changed = $changed;
	}

	public static function fixYAMLIndexes(string $str) : string{
		return preg_replace("#^( *)(y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)( *)\:#m", "$1\"$2\"$3:", $str);
	}

	/**
	 * @param mixed[] $default
	 * @phpstan-param array<string, mixed> $default
	 */
	public function load(string $file, int $type = Config::DETECT, array $default = []) : bool{
		$this->correct = true;
		$this->file = $file;

		$this->type = $type;
		if($this->type === Config::DETECT){
			$extension = explode(".", basename($this->file));
			$extension = strtolower(trim(array_pop($extension)));
			if(isset(Config::$formats[$extension])){
				$this->type = Config::$formats[$extension];
			}else{
				$this->correct = false;
			}
		}

		if(!file_exists($file)){
			$this->config = $default;
			$this->save();
		}else{
			if($this->correct){
				$content = file_get_contents($this->file);
				$config = null;
				switch($this->type){
					case Config::PROPERTIES:
						$config = $this->parseProperties($content);
						break;
					case Config::JSON:
						$config = json_decode($content, true);
						break;
					case Config::YAML:
						$content = self::fixYAMLIndexes($content);
						$config = yaml_parse($content);
						break;
					case Config::SERIALIZED:
						$config = unserialize($content);
						break;
					case Config::ENUM:
						$config = self::parseList($content);
						break;
					default:
						$this->correct = false;

						return false;
				}
				$this->config = is_array($config) ? $config : $default;
				if($this->fillDefaults($default, $this->config) > 0){
					$this->save();
				}
			}else{
				return false;
			}
		}

		return true;
	}

	public function check() : bool{
		return $this->correct;
	}

	public function save() : bool{
		if($this->correct){
			$content = null;
			switch($this->type){
				case Config::PROPERTIES:
					$content = $this->writeProperties();
					break;
				case Config::JSON:
					$content = json_encode($this->config, $this->jsonOptions);
					break;
				case Config::YAML:
					$content = yaml_emit($this->config, YAML_UTF8_ENCODING);
					break;
				case Config::SERIALIZED:
					$content = serialize($this->config);
					break;
				case Config::ENUM:
					$content = implode("\r\n", array_keys($this->config));
					break;
				default:
					throw new \InvalidStateException("Config type is unknown, has not been set or not detected");
			}

			file_put_contents($this->file, $content);

			$this->changed = false;

			return true;
		}else{
			return false;
		}
	}

	/**
	 * Sets the options for the JSON encoding when saving
	 *
	 * @return Config $this
	 * @throws \RuntimeException if the Config is not in JSON
	 * @see json_encode
	 */
	public function setJsonOptions(int $options) : Config{
		if($this->type !== Config::JSON){
			throw new \RuntimeException("Attempt to set JSON options for non-JSON config");
		}
		$this->jsonOptions = $options;
		$this->changed = true;

		return $this;
	}

	/**
	 * Enables the given option in addition to the currently set JSON options
	 *
	 * @return Config $this
	 * @throws \RuntimeException if the Config is not in JSON
	 * @see json_encode
	 */
	public function enableJsonOption(int $option) : Config{
		if($this->type !== Config::JSON){
			throw new \RuntimeException("Attempt to enable JSON option for non-JSON config");
		}
		$this->jsonOptions |= $option;
		$this->changed = true;

		return $this;
	}

	/**
	 * Disables the given option for the JSON encoding when saving
	 *
	 * @return Config $this
	 * @throws \RuntimeException if the Config is not in JSON
	 * @see json_encode
	 */
	public function disableJsonOption(int $option) : Config{
		if($this->type !== Config::JSON){
			throw new \RuntimeException("Attempt to disable JSON option for non-JSON config");
		}
		$this->jsonOptions &= ~$option;
		$this->changed = true;

		return $this;
	}

	/**
	 * Returns the options for the JSON encoding when saving
	 *
	 * @throws \RuntimeException if the Config is not in JSON
	 * @see json_encode
	 */
	public function getJsonOptions() : int{
		if($this->type !== Config::JSON){
			throw new \RuntimeException("Attempt to get JSON options for non-JSON config");
		}
		return $this->jsonOptions;
	}

	/**
	 * @param string $k
	 *
	 * @return bool|mixed
	 */
	public function __get($k){
		return $this->get($k);
	}

	/**
	 * @param string $k
	 * @param mixed  $v
	 *
	 * @return void
	 */
	public function __set($k, $v){
		$this->set($k, $v);
	}

	/**
	 * @param string $k
	 *
	 * @return bool
	 */
	public function __isset($k){
		return $this->exists($k);
	}

	/**
	 * @param string $k
	 */
	public function __unset($k){
		$this->remove($k);
	}

	/**
	 * @param string $key
	 * @param mixed  $value
	 *
	 * @return void
	 */
	public function setNested($key, $value){
		$vars = explode(".", $key);
		$base = array_shift($vars);

		if(!isset($this->config[$base])){
			$this->config[$base] = [];
		}

		$base =& $this->config[$base];

		while(count($vars) > 0){
			$baseKey = array_shift($vars);
			if(!isset($base[$baseKey])){
				$base[$baseKey] = [];
			}
			$base =& $base[$baseKey];
		}

		$base = $value;
		$this->nestedCache = [];
		$this->changed = true;
	}

	/**
	 * @param string $key
	 * @param mixed  $default
	 *
	 * @return mixed
	 */
	public function getNested($key, $default = null){
		if(isset($this->nestedCache[$key])){
			return $this->nestedCache[$key];
		}

		$vars = explode(".", $key);
		$base = array_shift($vars);
		if(isset($this->config[$base])){
			$base = $this->config[$base];
		}else{
			return $default;
		}

		while(count($vars) > 0){
			$baseKey = array_shift($vars);
			if(is_array($base) and isset($base[$baseKey])){
				$base = $base[$baseKey];
			}else{
				return $default;
			}
		}

		return $this->nestedCache[$key] = $base;
	}

	public function removeNested(string $key) : void{
		$this->nestedCache = [];
		$this->changed = true;

		$vars = explode(".", $key);

		$currentNode =& $this->config;
		while(count($vars) > 0){
			$nodeName = array_shift($vars);
			if(isset($currentNode[$nodeName])){
				if(count($vars) === 0){ //final node
					unset($currentNode[$nodeName]);
				}elseif(is_array($currentNode[$nodeName])){
					$currentNode =& $currentNode[$nodeName];
				}
			}else{
				break;
			}
		}
	}

	/**
	 * @param string $k
	 * @param mixed  $default
	 *
	 * @return bool|mixed
	 */
	public function get($k, $default = false){
		return ($this->correct and isset($this->config[$k])) ? $this->config[$k] : $default;
	}

	/**
	 * @param string $k key to be set
	 * @param mixed  $v value to set key
	 *
	 * @return void
	 */
	public function set($k, $v = true){
		$this->config[$k] = $v;
		$this->changed = true;
		foreach($this->nestedCache as $nestedKey => $nvalue){
			if(substr($nestedKey, 0, strlen($k) + 1) === ($k . ".")){
				unset($this->nestedCache[$nestedKey]);
			}
		}
	}

	/**
	 * @param mixed[] $v
	 * @phpstan-param array<string, mixed> $v
	 *
	 * @return void
	 */
	public function setAll(array $v){
		$this->config = $v;
		$this->changed = true;
	}

	/**
	 * @param string $k
	 * @param bool   $lowercase If set, searches Config in single-case / lowercase.
	 */
	public function exists($k, bool $lowercase = false) : bool{
		if($lowercase){
			$k = strtolower($k); //Convert requested  key to lower
			$array = array_change_key_case($this->config, CASE_LOWER); //Change all keys in array to lower
			return isset($array[$k]); //Find $k in modified array
		}else{
			return isset($this->config[$k]);
		}
	}

	/**
	 * @param string $k
	 *
	 * @return void
	 */
	public function remove($k){
		unset($this->config[$k]);
		$this->changed = true;
	}

	/**
	 * @return mixed[]
	 * @phpstan-return list<string>|array<string, mixed>
	 */
	public function getAll(bool $keys = false) : array{
		return ($keys ? array_keys($this->config) : $this->config);
	}

	/**
	 * @param mixed[] $defaults
	 * @phpstan-param array<string, mixed> $defaults
	 *
	 * @return void
	 */
	public function setDefaults(array $defaults){
		$this->fillDefaults($defaults, $this->config);
	}

	/**
	 * @param mixed[] $default
	 * @param mixed[] $data reference parameter
	 * @phpstan-param array<string, mixed> $default
	 * @phpstan-param array<string, mixed> $data
	 */
	private function fillDefaults(array $default, &$data) : int{
		$changed = 0;
		foreach($default as $k => $v){
			if(is_array($v)){
				if(!isset($data[$k]) or !is_array($data[$k])){
					$data[$k] = [];
				}
				$changed += $this->fillDefaults($v, $data[$k]);
			}elseif(!isset($data[$k])){
				$data[$k] = $v;
				++$changed;
			}
		}

		if($changed > 0){
			$this->changed = true;
		}

		return $changed;
	}

	/**
	 * @return true[]
	 * @phpstan-return array<string, true>
	 */
	private static function parseList(string $content) : array{
		$result = [];
		foreach(explode("\n", trim(str_replace("\r\n", "\n", $content))) as $v){
			$v = trim($v);
			if($v == ""){
				continue;
			}
			$result[$v] = true;
		}
		return $result;
	}

	private function writeProperties() : string{
		$content = "#Properties Config file\r\n#" . date("D M j H:i:s T Y") . "\r\n";
		foreach($this->config as $k => $v){
			if(is_bool($v)){
				$v = $v ? "on" : "off";
			}elseif(is_array($v)){
				$v = implode(";", $v);
			}
			$content .= $k . "=" . $v . "\r\n";
		}

		return $content;
	}

	/**
	 * @return mixed[]
	 * @phpstan-return array<string, mixed>
	 */
	private function parseProperties(string $content) : array{
		$result = [];
		if(preg_match_all('/^\s*([a-zA-Z0-9\-_\.]+)[ \t]*=([^\r\n]*)/um', $content, $matches) > 0){ //false or 0 matches
			foreach($matches[1] as $i => $k){
				$v = trim($matches[2][$i]);
				switch(strtolower($v)){
					case "on":
					case "true":
					case "yes":
						$v = true;
						break;
					case "off":
					case "false":
					case "no":
						$v = false;
						break;
				}
				if(isset($result[$k])){
					MainLogger::getLogger()->debug("[Config] Repeated property " . $k . " on file " . $this->file);
				}
				$result[$k] = $v;
			}
		}

		return $result;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * All Level related classes are here, like Generators, Populators, Noise, ...
 */
namespace pocketmine\level;

use pocketmine\block\Air;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\entity\Entity;
use pocketmine\entity\object\ExperienceOrb;
use pocketmine\entity\object\ItemEntity;
use pocketmine\event\block\BlockBreakEvent;
use pocketmine\event\block\BlockPlaceEvent;
use pocketmine\event\block\BlockUpdateEvent;
use pocketmine\event\level\ChunkLoadEvent;
use pocketmine\event\level\ChunkPopulateEvent;
use pocketmine\event\level\ChunkUnloadEvent;
use pocketmine\event\level\LevelSaveEvent;
use pocketmine\event\level\LevelUnloadEvent;
use pocketmine\event\level\SpawnChangeEvent;
use pocketmine\event\player\PlayerInteractEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\biome\Biome;
use pocketmine\level\format\Chunk;
use pocketmine\level\format\ChunkException;
use pocketmine\level\format\EmptySubChunk;
use pocketmine\level\format\io\BaseLevelProvider;
use pocketmine\level\format\io\ChunkRequestTask;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\level\format\io\exception\UnsupportedChunkFormatException;
use pocketmine\level\format\io\LevelProvider;
use pocketmine\level\generator\Generator;
use pocketmine\level\generator\GeneratorManager;
use pocketmine\level\generator\GeneratorRegisterTask;
use pocketmine\level\generator\GeneratorUnregisterTask;
use pocketmine\level\generator\PopulationTask;
use pocketmine\level\light\BlockLightUpdate;
use pocketmine\level\light\LightPopulationTask;
use pocketmine\level\light\SkyLightUpdate;
use pocketmine\level\particle\DestroyBlockParticle;
use pocketmine\level\particle\Particle;
use pocketmine\level\sound\Sound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector2;
use pocketmine\math\Vector3;
use pocketmine\metadata\BlockMetadataStore;
use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
use pocketmine\network\mcpe\protocol\SetTimePacket;
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
use pocketmine\Player;
use pocketmine\plugin\Plugin;
use pocketmine\Server;
use pocketmine\tile\Chest;
use pocketmine\tile\Container;
use pocketmine\tile\Tile;
use pocketmine\timings\Timings;
use pocketmine\utils\ReversePriorityQueue;
use function abs;
use function array_fill_keys;
use function array_map;
use function array_merge;
use function array_sum;
use function assert;
use function cos;
use function count;
use function floor;
use function get_class;
use function gettype;
use function is_a;
use function is_array;
use function is_object;
use function lcg_value;
use function max;
use function microtime;
use function min;
use function mt_rand;
use function strtolower;
use function trim;
use const INT32_MAX;
use const INT32_MIN;
use const M_PI;
use const PHP_INT_MAX;
use const PHP_INT_MIN;


class Level implements ChunkManager, Metadatable{

	/** @var int */
	private static $levelIdCounter = 1;
	/** @var int */
	private static $chunkLoaderCounter = 1;

	public const Y_MASK = 0xFF;
	public const Y_MAX = 0x100; //256

	public const TIME_DAY = 0;
	public const TIME_SUNSET = 12000;
	public const TIME_NIGHT = 14000;
	public const TIME_SUNRISE = 23000;

	public const TIME_FULL = 24000;

	public const DIFFICULTY_PEACEFUL = 0;
	public const DIFFICULTY_EASY = 1;
	public const DIFFICULTY_NORMAL = 2;
	public const DIFFICULTY_HARD = 3;

	/** @var Tile[] */
	private $tiles = [];

	/** @var Player[] */
	private $players = [];

	/** @var Entity[] */
	private $entities = [];

	/** @var Entity[] */
	public $updateEntities = [];
	/** @var Tile[] */
	public $updateTiles = [];
	/** @var Block[][] */
	private $blockCache = [];

	/** @var BatchPacket[] */
	private $chunkCache = [];

	/** @var int */
	private $sendTimeTicker = 0;

	/** @var Server */
	private $server;

	/** @var int */
	private $levelId;

	/** @var LevelProvider */
	private $provider;
	/** @var int */
	private $providerGarbageCollectionTicker = 0;

	/** @var int */
	private $worldHeight;

	/** @var ChunkLoader[] */
	private $loaders = [];
	/** @var int[] */
	private $loaderCounter = [];
	/** @var ChunkLoader[][] */
	private $chunkLoaders = [];
	/** @var Player[][] */
	private $playerLoaders = [];

	/** @var DataPacket[][] */
	private $chunkPackets = [];
	/** @var DataPacket[] */
	private $globalPackets = [];

	/** @var float[] */
	private $unloadQueue = [];

	/** @var int */
	private $time;
	/** @var bool */
	public $stopTime = false;

	/** @var float */
	private $sunAnglePercentage = 0.0;
	/** @var int */
	private $skyLightReduction = 0;

	/** @var string */
	private $folderName;
	/** @var string */
	private $displayName;

	/** @var Chunk[] */
	private $chunks = [];

	/** @var Vector3[][] */
	private $changedBlocks = [];

	/** @var ReversePriorityQueue */
	private $scheduledBlockUpdateQueue;
	/** @var int[] */
	private $scheduledBlockUpdateQueueIndex = [];

	/** @var \SplQueue */
	private $neighbourBlockUpdateQueue;

	/** @var Player[][] */
	private $chunkSendQueue = [];
	/** @var ChunkRequestTask[] */
	private $chunkSendTasks = [];

	/** @var bool[] */
	private $chunkPopulationQueue = [];
	/** @var bool[] */
	private $chunkPopulationLock = [];
	/** @var int */
	private $chunkPopulationQueueSize = 2;
	/** @var bool[] */
	private $generatorRegisteredWorkers = [];

	/** @var bool */
	private $autoSave = true;

	/** @var BlockMetadataStore */
	private $blockMetadata;

	/** @var Position */
	private $temporalPosition;
	/** @var Vector3 */
	private $temporalVector;

	/**
	 * @var \SplFixedArray
	 * @phpstan-var \SplFixedArray<Block>
	 */
	private $blockStates;

	/** @var int */
	private $sleepTicks = 0;

	/** @var int */
	private $chunkTickRadius;
	/** @var int[] */
	private $chunkTickList = [];
	/** @var int */
	private $chunksPerTick;
	/** @var bool */
	private $clearChunksOnTick;
	/** @var \SplFixedArray<Block|null> */
	private $randomTickBlocks;

	/** @var LevelTimings */
	public $timings;

	/** @var float */
	public $tickRateTime = 0;
	/**
	 * @deprecated
	 * @var int
	 */
	public $tickRateCounter = 0;

	/** @var bool */
	private $doingTick = false;

	/** @var string|Generator */
	private $generator;

	/** @var bool */
	private $closed = false;

	/** @var BlockLightUpdate|null */
	private $blockLightUpdate = null;
	/** @var SkyLightUpdate|null */
	private $skyLightUpdate = null;

	public static function chunkHash(int $x, int $z) : int{
		return (($x & 0xFFFFFFFF) << 32) | ($z & 0xFFFFFFFF);
	}

	public static function blockHash(int $x, int $y, int $z) : int{
		if($y < 0 or $y >= Level::Y_MAX){
			throw new \InvalidArgumentException("Y coordinate $y is out of range!");
		}
		return (($x & 0xFFFFFFF) << 36) | (($y & Level::Y_MASK) << 28) | ($z & 0xFFFFFFF);
	}

	/**
	 * Computes a small index relative to chunk base from the given coordinates.
	 */
	public static function chunkBlockHash(int $x, int $y, int $z) : int{
		return ($y << 8) | (($z & 0xf) << 4) | ($x & 0xf);
	}

	public static function getBlockXYZ(int $hash, ?int &$x, ?int &$y, ?int &$z) : void{
		$x = $hash >> 36;
		$y = ($hash >> 28) & Level::Y_MASK; //it's always positive
		$z = ($hash & 0xFFFFFFF) << 36 >> 36;
	}

	public static function getXZ(int $hash, ?int &$x, ?int &$z) : void{
		$x = $hash >> 32;
		$z = ($hash & 0xFFFFFFFF) << 32 >> 32;
	}

	public static function generateChunkLoaderId(ChunkLoader $loader) : int{
		if($loader->getLoaderId() === 0){
			return self::$chunkLoaderCounter++;
		}else{
			throw new \InvalidStateException("ChunkLoader has a loader id already assigned: " . $loader->getLoaderId());
		}
	}

	public static function getDifficultyFromString(string $str) : int{
		switch(strtolower(trim($str))){
			case "0":
			case "peaceful":
			case "p":
				return Level::DIFFICULTY_PEACEFUL;

			case "1":
			case "easy":
			case "e":
				return Level::DIFFICULTY_EASY;

			case "2":
			case "normal":
			case "n":
				return Level::DIFFICULTY_NORMAL;

			case "3":
			case "hard":
			case "h":
				return Level::DIFFICULTY_HARD;
		}

		return -1;
	}

	/**
	 * Init the default level data
	 */
	public function __construct(Server $server, string $name, LevelProvider $provider){
		$this->blockStates = BlockFactory::getBlockStatesArray();
		$this->levelId = static::$levelIdCounter++;
		$this->blockMetadata = new BlockMetadataStore($this);
		$this->server = $server;
		$this->autoSave = $server->getAutoSave();

		$this->provider = $provider;

		$this->displayName = $this->provider->getName();
		$this->worldHeight = $this->provider->getWorldHeight();

		$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.level.preparing", [$this->displayName]));
		$this->generator = GeneratorManager::getGenerator($this->provider->getGenerator(), true);
		//TODO: validate generator options

		$this->folderName = $name;

		$this->scheduledBlockUpdateQueue = new ReversePriorityQueue();
		$this->scheduledBlockUpdateQueue->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);

		$this->neighbourBlockUpdateQueue = new \SplQueue();

		$this->time = $this->provider->getTime();

		$this->chunkTickRadius = min($this->server->getViewDistance(), max(1, (int) $this->server->getProperty("chunk-ticking.tick-radius", 4)));
		$this->chunksPerTick = (int) $this->server->getProperty("chunk-ticking.per-tick", 40);
		$this->chunkPopulationQueueSize = (int) $this->server->getProperty("chunk-generation.population-queue-size", 2);
		$this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", true);

		$dontTickBlocks = array_fill_keys($this->server->getProperty("chunk-ticking.disable-block-ticking", []), true);

		$this->randomTickBlocks = new \SplFixedArray(256);
		foreach($this->randomTickBlocks as $id => $null){
			$block = BlockFactory::get($id); //Make sure it's a copy
			if(!isset($dontTickBlocks[$id]) and $block->ticksRandomly()){
				$this->randomTickBlocks[$id] = $block;
			}
		}

		$this->timings = new LevelTimings($this);
		$this->temporalPosition = new Position(0, 0, 0, $this);
		$this->temporalVector = new Vector3(0, 0, 0);
	}

	/**
	 * @deprecated
	 */
	public function getTickRate() : int{
		return 1;
	}

	public function getTickRateTime() : float{
		return $this->tickRateTime;
	}

	/**
	 * @deprecated does nothing
	 *
	 * @return void
	 */
	public function setTickRate(int $tickRate){

	}

	public function registerGeneratorToWorker(int $worker) : void{
		$this->generatorRegisteredWorkers[$worker] = true;
		$this->server->getAsyncPool()->submitTaskToWorker(new GeneratorRegisterTask($this, $this->generator, $this->provider->getGeneratorOptions()), $worker);
	}

	/**
	 * @return void
	 */
	public function unregisterGenerator(){
		$pool = $this->server->getAsyncPool();
		foreach($pool->getRunningWorkers() as $i){
			if(isset($this->generatorRegisteredWorkers[$i])){
				$pool->submitTaskToWorker(new GeneratorUnregisterTask($this), $i);
			}
		}
		$this->generatorRegisteredWorkers = [];
	}

	public function getBlockMetadata() : BlockMetadataStore{
		return $this->blockMetadata;
	}

	public function getServer() : Server{
		return $this->server;
	}

	final public function getProvider() : LevelProvider{
		return $this->provider;
	}

	/**
	 * Returns the unique level identifier
	 */
	final public function getId() : int{
		return $this->levelId;
	}

	public function isClosed() : bool{
		return $this->closed;
	}

	/**
	 * @return void
	 */
	public function close(){
		if($this->closed){
			throw new \InvalidStateException("Tried to close a world which is already closed");
		}

		foreach($this->chunks as $chunk){
			$this->unloadChunk($chunk->getX(), $chunk->getZ(), false);
		}

		$this->save();

		$this->unregisterGenerator();

		$this->provider->close();
		$this->provider = null;
		$this->blockMetadata = null;
		$this->blockCache = [];
		$this->temporalPosition = null;

		$this->closed = true;
	}

	/**
	 * @param Player[]|null $players
	 *
	 * @return void
	 */
	public function addSound(Sound $sound, array $players = null){
		$pk = $sound->encode();
		if(!is_array($pk)){
			$pk = [$pk];
		}
		if(count($pk) > 0){
			if($players === null){
				foreach($pk as $e){
					$this->broadcastPacketToViewers($sound, $e);
				}
			}else{
				$this->server->batchPackets($players, $pk, false);
			}
		}
	}

	/**
	 * @param Player[]|null $players
	 *
	 * @return void
	 */
	public function addParticle(Particle $particle, array $players = null){
		$pk = $particle->encode();
		if(!is_array($pk)){
			$pk = [$pk];
		}
		if(count($pk) > 0){
			if($players === null){
				foreach($pk as $e){
					$this->broadcastPacketToViewers($particle, $e);
				}
			}else{
				$this->server->batchPackets($players, $pk, false);
			}
		}
	}

	/**
	 * Broadcasts a LevelEvent to players in the area. This could be sound, particles, weather changes, etc.
	 *
	 * @param Vector3|null $pos If null, broadcasts to every player in the Level
	 *
	 * @return void
	 */
	public function broadcastLevelEvent(?Vector3 $pos, int $evid, int $data = 0){
		$pk = new LevelEventPacket();
		$pk->evid = $evid;
		$pk->data = $data;
		if($pos !== null){
			$pk->position = $pos->asVector3();
			$this->broadcastPacketToViewers($pos, $pk);
		}else{
			$pk->position = null;
			$this->broadcastGlobalPacket($pk);
		}
	}

	/**
	 * Broadcasts a LevelSoundEvent to players in the area.
	 *
	 * @param bool    $disableRelativeVolume If true, all players receiving this sound-event will hear the sound at full volume regardless of distance
	 *
	 * @return void
	 */
	public function broadcastLevelSoundEvent(Vector3 $pos, int $soundId, int $extraData = -1, int $entityTypeId = -1, bool $isBabyMob = false, bool $disableRelativeVolume = false){
		$pk = new LevelSoundEventPacket();
		$pk->sound = $soundId;
		$pk->extraData = $extraData;
		$pk->entityType = AddActorPacket::LEGACY_ID_MAP_BC[$entityTypeId] ?? ":";
		$pk->isBabyMob = $isBabyMob;
		$pk->disableRelativeVolume = $disableRelativeVolume;
		$pk->position = $pos->asVector3();
		$this->broadcastPacketToViewers($pos, $pk);
	}

	public function getAutoSave() : bool{
		return $this->autoSave;
	}

	/**
	 * @return void
	 */
	public function setAutoSave(bool $value){
		$this->autoSave = $value;
	}

	/**
	 * @internal
	 * @see Server::unloadLevel()
	 *
	 * Unloads the current level from memory safely
	 *
	 * @param bool $force default false, force unload of default level
	 *
	 * @throws \InvalidStateException if trying to unload a level during level tick
	 */
	public function unload(bool $force = false) : bool{
		if($this->doingTick and !$force){
			throw new \InvalidStateException("Cannot unload a world during world tick");
		}

		$ev = new LevelUnloadEvent($this);

		if($this === $this->server->getDefaultLevel() and !$force){
			$ev->setCancelled(true);
		}

		$ev->call();

		if(!$force and $ev->isCancelled()){
			return false;
		}

		$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.level.unloading", [$this->getName()]));
		$defaultLevel = $this->server->getDefaultLevel();
		foreach($this->getPlayers() as $player){
			if($this === $defaultLevel or $defaultLevel === null){
				$player->close($player->getLeaveMessage(), "Forced default world unload");
			}else{
				$player->teleport($defaultLevel->getSafeSpawn());
			}
		}

		if($this === $defaultLevel){
			$this->server->setDefaultLevel(null);
		}

		$this->server->removeLevel($this);

		$this->close();

		return true;
	}

	/**
	 * @deprecated WARNING: This function has a misleading name. Contrary to what the name might imply, this function
	 * DOES NOT return players who are IN a chunk, rather, it returns players who can SEE the chunk.
	 *
	 * Returns a list of players who have the target chunk within their view distance.
	 *
	 * @return Player[]
	 */
	public function getChunkPlayers(int $chunkX, int $chunkZ) : array{
		return $this->playerLoaders[((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)] ?? [];
	}

	/**
	 * Gets the chunk loaders being used in a specific chunk
	 *
	 * @return ChunkLoader[]
	 */
	public function getChunkLoaders(int $chunkX, int $chunkZ) : array{
		return $this->chunkLoaders[((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)] ?? [];
	}

	/**
	 * Returns an array of players who have the target position within their view distance.
	 *
	 * @return Player[]
	 */
	public function getViewersForPosition(Vector3 $pos) : array{
		return $this->getChunkPlayers($pos->getFloorX() >> 4, $pos->getFloorZ() >> 4);
	}

	/**
	 * Queues a DataPacket to be sent to all players using the chunk at the specified X/Z coordinates at the end of the
	 * current tick.
	 *
	 * @return void
	 */
	public function addChunkPacket(int $chunkX, int $chunkZ, DataPacket $packet){
		if(!isset($this->chunkPackets[$index = ((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)])){
			$this->chunkPackets[$index] = [$packet];
		}else{
			$this->chunkPackets[$index][] = $packet;
		}
	}

	/**
	 * Broadcasts a packet to every player who has the target position within their view distance.
	 */
	public function broadcastPacketToViewers(Vector3 $pos, DataPacket $packet) : void{
		$this->addChunkPacket($pos->getFloorX() >> 4, $pos->getFloorZ() >> 4, $packet);
	}

	/**
	 * Broadcasts a packet to every player in the level.
	 */
	public function broadcastGlobalPacket(DataPacket $packet) : void{
		$this->globalPackets[] = $packet;
	}

	/**
	 * @deprecated
	 * @see Level::broadcastGlobalPacket()
	 */
	public function addGlobalPacket(DataPacket $packet) : void{
		$this->globalPackets[] = $packet;
	}

	/**
	 * @return void
	 */
	public function registerChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ, bool $autoLoad = true){
		$loaderId = $loader->getLoaderId();

		if(!isset($this->chunkLoaders[$chunkHash = ((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)])){
			$this->chunkLoaders[$chunkHash] = [];
			$this->playerLoaders[$chunkHash] = [];
		}elseif(isset($this->chunkLoaders[$chunkHash][$loaderId])){
			return;
		}

		$this->chunkLoaders[$chunkHash][$loaderId] = $loader;
		if($loader instanceof Player){
			$this->playerLoaders[$chunkHash][$loaderId] = $loader;
		}

		if(!isset($this->loaders[$loaderId])){
			$this->loaderCounter[$loaderId] = 1;
			$this->loaders[$loaderId] = $loader;
		}else{
			++$this->loaderCounter[$loaderId];
		}

		$this->cancelUnloadChunkRequest($chunkX, $chunkZ);

		if($autoLoad){
			$this->loadChunk($chunkX, $chunkZ);
		}
	}

	/**
	 * @return void
	 */
	public function unregisterChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ){
		$chunkHash = ((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF);
		$loaderId = $loader->getLoaderId();
		if(isset($this->chunkLoaders[$chunkHash][$loaderId])){
			unset($this->chunkLoaders[$chunkHash][$loaderId]);
			unset($this->playerLoaders[$chunkHash][$loaderId]);
			if(count($this->chunkLoaders[$chunkHash]) === 0){
				unset($this->chunkLoaders[$chunkHash]);
				unset($this->playerLoaders[$chunkHash]);
				$this->unloadChunkRequest($chunkX, $chunkZ, true);
			}

			if(--$this->loaderCounter[$loaderId] === 0){
				unset($this->loaderCounter[$loaderId]);
				unset($this->loaders[$loaderId]);
			}
		}
	}

	/**
	 * @internal
	 *
	 * @param Player ...$targets If empty, will send to all players in the level.
	 *
	 * @return void
	 */
	public function sendTime(Player ...$targets){
		$pk = new SetTimePacket();
		$pk->time = $this->time & 0xffffffff; //avoid overflowing the field, since the packet uses an int32

		$this->server->broadcastPacket(count($targets) > 0 ? $targets : $this->players, $pk);
	}

	/**
	 * @internal
	 *
	 * @return void
	 */
	public function doTick(int $currentTick){
		if($this->closed){
			throw new \InvalidStateException("Attempted to tick a world which has been closed");
		}

		$this->timings->doTick->startTiming();
		$this->doingTick = true;
		try{
			$this->actuallyDoTick($currentTick);
		}finally{
			$this->doingTick = false;
			$this->timings->doTick->stopTiming();
		}
	}

	protected function actuallyDoTick(int $currentTick) : void{
		if(!$this->stopTime){
			//this simulates an overflow, as would happen in any language which doesn't do stupid things to var types
			if($this->time === PHP_INT_MAX){
				$this->time = PHP_INT_MIN;
			}else{
				$this->time++;
			}
		}

		$this->sunAnglePercentage = $this->computeSunAnglePercentage(); //Sun angle depends on the current time
		$this->skyLightReduction = $this->computeSkyLightReduction(); //Sky light reduction depends on the sun angle

		if(++$this->sendTimeTicker === 200){
			$this->sendTime();
			$this->sendTimeTicker = 0;
		}

		$this->unloadChunks();
		if(++$this->providerGarbageCollectionTicker >= 6000){
			$this->provider->doGarbageCollection();
			$this->providerGarbageCollectionTicker = 0;
		}

		//Do block updates
		$this->timings->doTickPending->startTiming();

		//Delayed updates
		while($this->scheduledBlockUpdateQueue->count() > 0 and $this->scheduledBlockUpdateQueue->current()["priority"] <= $currentTick){
			/** @var Vector3 $vec */
			$vec = $this->scheduledBlockUpdateQueue->extract()["data"];
			unset($this->scheduledBlockUpdateQueueIndex[((($vec->x) & 0xFFFFFFF) << 36) | ((( $vec->y) & 0xff) << 28) | (( $vec->z) & 0xFFFFFFF)]);
			if(!$this->isInLoadedTerrain($vec)){
				continue;
			}
			$block = $this->getBlock($vec);
			$block->onScheduledUpdate();
		}

		//Normal updates
		while($this->neighbourBlockUpdateQueue->count() > 0){
			$index = $this->neighbourBlockUpdateQueue->dequeue();
			 $x = ($index >> 36);  $y = (($index >> 28) & 0xff);  $z = ($index & 0xFFFFFFF) << 36 >> 36;

			$block = $this->getBlockAt($x, $y, $z);
			$block->clearCaches(); //for blocks like fences, force recalculation of connected AABBs

			$ev = new BlockUpdateEvent($block);
			$ev->call();
			if(!$ev->isCancelled()){
				$block->onNearbyBlockChange();
			}
		}

		$this->timings->doTickPending->stopTiming();

		$this->timings->entityTick->startTiming();
		//Update entities that need update
		Timings::$tickEntityTimer->startTiming();
		foreach($this->updateEntities as $id => $entity){
			if($entity->isClosed() or !$entity->onUpdate($currentTick)){
				unset($this->updateEntities[$id]);
			}
			if($entity->isFlaggedForDespawn()){
				$entity->close();
			}
		}
		Timings::$tickEntityTimer->stopTiming();
		$this->timings->entityTick->stopTiming();

		$this->timings->tileEntityTick->startTiming();
		Timings::$tickTileEntityTimer->startTiming();
		//Update tiles that need update
		foreach($this->updateTiles as $id => $tile){
			if(!$tile->onUpdate()){
				unset($this->updateTiles[$id]);
			}
		}
		Timings::$tickTileEntityTimer->stopTiming();
		$this->timings->tileEntityTick->stopTiming();

		$this->timings->doTickTiles->startTiming();
		$this->tickChunks();
		$this->timings->doTickTiles->stopTiming();

		$this->executeQueuedLightUpdates();

		if(count($this->changedBlocks) > 0){
			if(count($this->players) > 0){
				foreach($this->changedBlocks as $index => $blocks){
					if(count($blocks) === 0){ //blocks can be set normally and then later re-set with direct send
						continue;
					}
					unset($this->chunkCache[$index]);
					 $chunkX = ($index >> 32);  $chunkZ = ($index & 0xFFFFFFFF) << 32 >> 32;
					if(count($blocks) > 512){
						$chunk = $this->getChunk($chunkX, $chunkZ);
						foreach($this->getChunkPlayers($chunkX, $chunkZ) as $p){
							$p->onChunkChanged($chunk);
						}
					}else{
						$this->sendBlocks($this->getChunkPlayers($chunkX, $chunkZ), $blocks, UpdateBlockPacket::FLAG_ALL);
					}
				}
			}else{
				$this->chunkCache = [];
			}

			$this->changedBlocks = [];

		}

		$this->processChunkRequest();

		if($this->sleepTicks > 0 and --$this->sleepTicks <= 0){
			$this->checkSleep();
		}

		if(count($this->globalPackets) > 0){
			if(count($this->players) > 0){
				$this->server->batchPackets($this->players, $this->globalPackets);
			}
			$this->globalPackets = [];
		}

		foreach($this->chunkPackets as $index => $entries){
			 $chunkX = ($index >> 32);  $chunkZ = ($index & 0xFFFFFFFF) << 32 >> 32;
			$chunkPlayers = $this->getChunkPlayers($chunkX, $chunkZ);
			if(count($chunkPlayers) > 0){
				$this->server->batchPackets($chunkPlayers, $entries, false, false);
			}
		}

		$this->chunkPackets = [];
	}

	/**
	 * @return void
	 */
	public function checkSleep(){
		if(count($this->players) === 0){
			return;
		}

		$resetTime = true;
		foreach($this->getPlayers() as $p){
			if(!$p->isSleeping()){
				$resetTime = false;
				break;
			}
		}

		if($resetTime){
			$time = $this->getTime() % Level::TIME_FULL;

			if($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE){
				$this->setTime($this->getTime() + Level::TIME_FULL - $time);

				foreach($this->getPlayers() as $p){
					$p->stopSleep();
				}
			}
		}
	}

	public function setSleepTicks(int $ticks) : void{
		$this->sleepTicks = $ticks;
	}

	/**
	 * @param Player[]  $target
	 * @param Vector3[] $blocks
	 *
	 * @return void
	 */
	public function sendBlocks(array $target, array $blocks, int $flags = UpdateBlockPacket::FLAG_NONE, bool $optimizeRebuilds = false){
		$packets = [];
		if($optimizeRebuilds){
			$chunks = [];
			foreach($blocks as $b){
				if(!($b instanceof Vector3)){
					throw new \TypeError("Expected Vector3 in blocks array, got " . (is_object($b) ? get_class($b) : gettype($b)));
				}
				$pk = new UpdateBlockPacket();

				$first = false;
				if(!isset($chunks[$index = ((($b->x >> 4) & 0xFFFFFFFF) << 32) | (( $b->z >> 4) & 0xFFFFFFFF)])){
					$chunks[$index] = true;
					$first = true;
				}

				$pk->x = $b->x;
				$pk->y = $b->y;
				$pk->z = $b->z;

				if($b instanceof Block){
					$pk->blockRuntimeId = $b->getRuntimeId();
				}else{
					$fullBlock = $this->getFullBlock($b->x, $b->y, $b->z);
					$pk->blockRuntimeId = RuntimeBlockMapping::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf);
				}

				$pk->flags = $first ? $flags : UpdateBlockPacket::FLAG_NONE;

				$packets[] = $pk;
			}
		}else{
			foreach($blocks as $b){
				if(!($b instanceof Vector3)){
					throw new \TypeError("Expected Vector3 in blocks array, got " . (is_object($b) ? get_class($b) : gettype($b)));
				}
				$pk = new UpdateBlockPacket();

				$pk->x = $b->x;
				$pk->y = $b->y;
				$pk->z = $b->z;

				if($b instanceof Block){
					$pk->blockRuntimeId = $b->getRuntimeId();
				}else{
					$fullBlock = $this->getFullBlock($b->x, $b->y, $b->z);
					$pk->blockRuntimeId = RuntimeBlockMapping::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf);
				}

				$pk->flags = $flags;

				$packets[] = $pk;
			}
		}

		$this->server->batchPackets($target, $packets, false, false);
	}

	/**
	 * @return void
	 */
	public function clearCache(bool $force = false){
		if($force){
			$this->chunkCache = [];
			$this->blockCache = [];
		}else{
			$count = 0;
			foreach($this->blockCache as $list){
				$count += count($list);
				if($count > 2048){
					$this->blockCache = [];
					break;
				}
			}
		}
	}

	/**
	 * @return void
	 */
	public function clearChunkCache(int $chunkX, int $chunkZ){
		unset($this->chunkCache[((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)]);
	}

	/**
	 * @phpstan-return \SplFixedArray<Block|null>
	 */
	public function getRandomTickedBlocks() : \SplFixedArray{
		return $this->randomTickBlocks;
	}

	/**
	 * @return void
	 */
	public function addRandomTickedBlock(int $id){
		$this->randomTickBlocks[$id] = BlockFactory::get($id);
	}

	/**
	 * @return void
	 */
	public function removeRandomTickedBlock(int $id){
		$this->randomTickBlocks[$id] = null;
	}

	private function tickChunks() : void{
		if($this->chunksPerTick <= 0 or count($this->loaders) === 0){
			$this->chunkTickList = [];
			return;
		}

		$chunksPerLoader = min(200, max(1, (int) ((($this->chunksPerTick - count($this->loaders)) / count($this->loaders)) + 0.5)));
		$randRange = 3 + $chunksPerLoader / 30;
		$randRange = (int) ($randRange > $this->chunkTickRadius ? $this->chunkTickRadius : $randRange);

		foreach($this->loaders as $loader){
			$chunkX = (int) floor($loader->getX()) >> 4;
			$chunkZ = (int) floor($loader->getZ()) >> 4;

			$index = ((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF);
			$existingLoaders = max(0, $this->chunkTickList[$index] ?? 0);
			$this->chunkTickList[$index] = $existingLoaders + 1;
			for($chunk = 0; $chunk < $chunksPerLoader; ++$chunk){
				$dx = mt_rand(-$randRange, $randRange);
				$dz = mt_rand(-$randRange, $randRange);
				$hash = ((($dx + $chunkX) & 0xFFFFFFFF) << 32) | (( $dz + $chunkZ) & 0xFFFFFFFF);
				if(!isset($this->chunkTickList[$hash]) and isset($this->chunks[$hash])){
					$this->chunkTickList[$hash] = -1;
				}
			}
		}

		foreach($this->chunkTickList as $index => $loaders){
			 $chunkX = ($index >> 32);  $chunkZ = ($index & 0xFFFFFFFF) << 32 >> 32;

			for($cx = -1; $cx <= 1; ++$cx){
				for($cz = -1; $cz <= 1; ++$cz){
					if(!isset($this->chunks[((($chunkX + $cx) & 0xFFFFFFFF) << 32) | (( $chunkZ + $cz) & 0xFFFFFFFF)])){
						unset($this->chunkTickList[$index]);
						goto skip_to_next; //no "continue 3" thanks!
					}
				}
			}

			if($loaders <= 0){
				unset($this->chunkTickList[$index]);
			}

			$chunk = $this->chunks[$index];
			foreach($chunk->getEntities() as $entity){
				$entity->scheduleUpdate();
			}

			foreach($chunk->getSubChunks() as $Y => $subChunk){
				if(!($subChunk instanceof EmptySubChunk)){
					$k = mt_rand(0, 0xfffffffff); //36 bits
					for($i = 0; $i < 3; ++$i){
						$x = $k & 0x0f;
						$y = ($k >> 4) & 0x0f;
						$z = ($k >> 8) & 0x0f;
						$k >>= 12;

						$blockId = $subChunk->getBlockId($x, $y, $z);
						if($this->randomTickBlocks[$blockId] !== null){
							/** @var Block $block */
							$block = clone $this->randomTickBlocks[$blockId];
							$block->setDamage($subChunk->getBlockData($x, $y, $z));

							$block->x = $chunkX * 16 + $x;
							$block->y = ($Y << 4) + $y;
							$block->z = $chunkZ * 16 + $z;
							$block->level = $this;
							$block->onRandomTick();
						}
					}
				}
			}

			skip_to_next: //dummy label to break out of nested loops
		}

		if($this->clearChunksOnTick){
			$this->chunkTickList = [];
		}
	}

	/**
	 * @return mixed[]
	 */
	public function __debugInfo() : array{
		return [];
	}

	public function save(bool $force = false) : bool{

		if(!$this->getAutoSave() and !$force){
			return false;
		}

		(new LevelSaveEvent($this))->call();

		$this->provider->setTime($this->time);
		$this->saveChunks();
		if($this->provider instanceof BaseLevelProvider){
			$this->provider->saveLevelData();
		}

		return true;
	}

	/**
	 * @return void
	 */
	public function saveChunks(){
		$this->timings->syncChunkSaveTimer->startTiming();
		try{
			foreach($this->chunks as $chunk){
				if(($chunk->hasChanged() or count($chunk->getTiles()) > 0 or count($chunk->getSavableEntities()) > 0) and $chunk->isGenerated()){
					$this->provider->saveChunk($chunk);
					$chunk->setChanged(false);
				}
			}
		}finally{
			$this->timings->syncChunkSaveTimer->stopTiming();
		}
	}

	/**
	 * Schedules a block update to be executed after the specified number of ticks.
	 * Blocks will be updated with the scheduled update type.
	 *
	 * @return void
	 */
	public function scheduleDelayedBlockUpdate(Vector3 $pos, int $delay){
		if(
			!$this->isInWorld($pos->x, $pos->y, $pos->z) or
			(isset($this->scheduledBlockUpdateQueueIndex[$index = ((($pos->x) & 0xFFFFFFF) << 36) | ((( $pos->y) & 0xff) << 28) | (( $pos->z) & 0xFFFFFFF)]) and $this->scheduledBlockUpdateQueueIndex[$index] <= $delay)
		){
			return;
		}
		$this->scheduledBlockUpdateQueueIndex[$index] = $delay;
		$this->scheduledBlockUpdateQueue->insert(new Vector3((int) $pos->x, (int) $pos->y, (int) $pos->z), $delay + $this->server->getTick());
	}

	/**
	 * Schedules the blocks around the specified position to be updated at the end of this tick.
	 * Blocks will be updated with the normal update type.
	 *
	 * @return void
	 */
	public function scheduleNeighbourBlockUpdates(Vector3 $pos){
		$pos = $pos->floor();

		for($i = 0; $i <= 5; ++$i){
			$side = $pos->getSide($i);
			if($this->isInWorld($side->x, $side->y, $side->z)){
				$this->neighbourBlockUpdateQueue->enqueue(((($side->x) & 0xFFFFFFF) << 36) | ((( $side->y) & 0xff) << 28) | (( $side->z) & 0xFFFFFFF));
			}
		}
	}

	/**
	 * @return Block[]
	 */
	public function getCollisionBlocks(AxisAlignedBB $bb, bool $targetFirst = false) : array{
		$minX = (int) floor($bb->minX - 1);
		$minY = (int) floor($bb->minY - 1);
		$minZ = (int) floor($bb->minZ - 1);
		$maxX = (int) floor($bb->maxX + 1);
		$maxY = (int) floor($bb->maxY + 1);
		$maxZ = (int) floor($bb->maxZ + 1);

		$collides = [];

		if($targetFirst){
			for($z = $minZ; $z <= $maxZ; ++$z){
				for($x = $minX; $x <= $maxX; ++$x){
					for($y = $minY; $y <= $maxY; ++$y){
						$block = $this->getBlockAt($x, $y, $z);
						if(!$block->canPassThrough() and $block->collidesWithBB($bb)){
							return [$block];
						}
					}
				}
			}
		}else{
			for($z = $minZ; $z <= $maxZ; ++$z){
				for($x = $minX; $x <= $maxX; ++$x){
					for($y = $minY; $y <= $maxY; ++$y){
						$block = $this->getBlockAt($x, $y, $z);
						if(!$block->canPassThrough() and $block->collidesWithBB($bb)){
							$collides[] = $block;
						}
					}
				}
			}
		}

		return $collides;
	}

	public function isFullBlock(Vector3 $pos) : bool{
		if($pos instanceof Block){
			if($pos->isSolid()){
				return true;
			}
			$bb = $pos->getBoundingBox();
		}else{
			$bb = $this->getBlock($pos)->getBoundingBox();
		}

		return $bb !== null and $bb->getAverageEdgeLength() >= 1;
	}

	/**
	 * @return AxisAlignedBB[]
	 */
	public function getCollisionCubes(Entity $entity, AxisAlignedBB $bb, bool $entities = true) : array{
		$minX = (int) floor($bb->minX - 1);
		$minY = (int) floor($bb->minY - 1);
		$minZ = (int) floor($bb->minZ - 1);
		$maxX = (int) floor($bb->maxX + 1);
		$maxY = (int) floor($bb->maxY + 1);
		$maxZ = (int) floor($bb->maxZ + 1);

		$collides = [];

		for($z = $minZ; $z <= $maxZ; ++$z){
			for($x = $minX; $x <= $maxX; ++$x){
				for($y = $minY; $y <= $maxY; ++$y){
					$block = $this->getBlockAt($x, $y, $z);
					if(!$block->canPassThrough()){
						foreach($block->getCollisionBoxes() as $blockBB){
							if($blockBB->intersectsWith($bb)){
								$collides[] = $blockBB;
							}
						}
					}
				}
			}
		}

		if($entities){
			foreach($this->getCollidingEntities($bb->expandedCopy(0.25, 0.25, 0.25), $entity) as $ent){
				$collides[] = clone $ent->boundingBox;
			}
		}

		return $collides;
	}

	public function getFullLight(Vector3 $pos) : int{
		return $this->getFullLightAt($pos->x, $pos->y, $pos->z);
	}

	public function getFullLightAt(int $x, int $y, int $z) : int{
		$skyLight = $this->getRealBlockSkyLightAt($x, $y, $z);
		if($skyLight < 15){
			return max($skyLight, ($this->getChunk($x >> 4,  $z >> 4, true)->getBlockLight($x & 0x0f,  $y,  $z & 0x0f)));
		}else{
			return $skyLight;
		}
	}

	/**
	 * Computes the percentage of a circle away from noon the sun is currently at. This can be multiplied by 2 * M_PI to
	 * get an angle in radians, or by 360 to get an angle in degrees.
	 */
	public function computeSunAnglePercentage() : float{
		$timeProgress = ($this->time % 24000) / 24000;

		//0.0 needs to be high noon, not dusk
		$sunProgress = $timeProgress + ($timeProgress < 0.25 ? 0.75 : -0.25);

		//Offset the sun progress to be above the horizon longer at dusk and dawn
		//this is roughly an inverted sine curve, which pushes the sun progress back at dusk and forwards at dawn
		$diff = (((1 - ((cos($sunProgress * M_PI) + 1) / 2)) - $sunProgress) / 3);

		return $sunProgress + $diff;
	}

	/**
	 * Returns the percentage of a circle away from noon the sun is currently at.
	 */
	public function getSunAnglePercentage() : float{
		return $this->sunAnglePercentage;
	}

	/**
	 * Returns the current sun angle in radians.
	 */
	public function getSunAngleRadians() : float{
		return $this->sunAnglePercentage * 2 * M_PI;
	}

	/**
	 * Returns the current sun angle in degrees.
	 */
	public function getSunAngleDegrees() : float{
		return $this->sunAnglePercentage * 360.0;
	}

	/**
	 * Computes how many points of sky light is subtracted based on the current time. Used to offset raw chunk sky light
	 * to get a real light value.
	 */
	public function computeSkyLightReduction() : int{
		$percentage = max(0, min(1, -(cos($this->getSunAngleRadians()) * 2 - 0.5)));

		//TODO: check rain and thunder level

		return (int) ($percentage * 11);
	}

	/**
	 * Returns how many points of sky light is subtracted based on the current time.
	 */
	public function getSkyLightReduction() : int{
		return $this->skyLightReduction;
	}

	/**
	 * Returns the sky light level at the specified coordinates, offset by the current time and weather.
	 *
	 * @return int 0-15
	 */
	public function getRealBlockSkyLightAt(int $x, int $y, int $z) : int{
		$light = ($this->getChunk($x >> 4,  $z >> 4, true)->getBlockSkyLight($x & 0x0f,  $y,  $z & 0x0f)) - $this->skyLightReduction;
		return $light < 0 ? 0 : $light;
	}

	/**
	 * @return int bitmap, (id << 4) | data
	 */
	public function getFullBlock(int $x, int $y, int $z) : int{
		return $this->getChunk($x >> 4, $z >> 4, false)->getFullBlock($x & 0x0f, $y, $z & 0x0f);
	}

	public function isInWorld(int $x, int $y, int $z) : bool{
		return (
			$x <= INT32_MAX and $x >= INT32_MIN and
			$y < $this->worldHeight and $y >= 0 and
			$z <= INT32_MAX and $z >= INT32_MIN
		);
	}

	/**
	 * Gets the Block object at the Vector3 location. This method wraps around {@link getBlockAt}, converting the
	 * vector components to integers.
	 *
	 * Note: If you're using this for performance-sensitive code, and you're guaranteed to be supplying ints in the
	 * specified vector, consider using {@link getBlockAt} instead for better performance.
	 *
	 * @param bool    $cached Whether to use the block cache for getting the block (faster, but may be inaccurate)
	 * @param bool    $addToCache Whether to cache the block object created by this method call.
	 */
	public function getBlock(Vector3 $pos, bool $cached = true, bool $addToCache = true) : Block{
		return $this->getBlockAt((int) floor($pos->x), (int) floor($pos->y), (int) floor($pos->z), $cached, $addToCache);
	}

	/**
	 * Gets the Block object at the specified coordinates.
	 *
	 * Note for plugin developers: If you are using this method a lot (thousands of times for many positions for
	 * example), you may want to set addToCache to false to avoid using excessive amounts of memory.
	 *
	 * @param bool $cached Whether to use the block cache for getting the block (faster, but may be inaccurate)
	 * @param bool $addToCache Whether to cache the block object created by this method call.
	 */
	public function getBlockAt(int $x, int $y, int $z, bool $cached = true, bool $addToCache = true) : Block{
		$fullState = 0;
		$relativeBlockHash = null;
		$chunkHash = ((($x >> 4) & 0xFFFFFFFF) << 32) | (( $z >> 4) & 0xFFFFFFFF);

		if($this->isInWorld($x, $y, $z)){
			$relativeBlockHash = Level::chunkBlockHash($x, $y, $z);

			if($cached and isset($this->blockCache[$chunkHash][$relativeBlockHash])){
				return $this->blockCache[$chunkHash][$relativeBlockHash];
			}

			$chunk = $this->chunks[$chunkHash] ?? null;
			if($chunk !== null){
				$fullState = $chunk->getFullBlock($x & 0x0f, $y, $z & 0x0f);
			}else{
				$addToCache = false;
			}
		}

		$block = clone $this->blockStates[$fullState & 0xfff];

		$block->x = $x;
		$block->y = $y;
		$block->z = $z;
		$block->level = $this;

		if($addToCache and $relativeBlockHash !== null){
			$this->blockCache[$chunkHash][$relativeBlockHash] = $block;
		}

		return $block;
	}

	/**
	 * @return void
	 */
	public function updateAllLight(Vector3 $pos){
		$this->updateBlockSkyLight($pos->x, $pos->y, $pos->z);
		$this->updateBlockLight($pos->x, $pos->y, $pos->z);
	}

	/**
	 * Returns the highest block light level available in the positions adjacent to the specified block coordinates.
	 */
	public function getHighestAdjacentBlockSkyLight(int $x, int $y, int $z) : int{
		return max([
			($this->getChunk($x + 1 >> 4,  $z >> 4, true)->getBlockSkyLight($x + 1 & 0x0f,  $y,  $z & 0x0f)),
			($this->getChunk($x - 1 >> 4,  $z >> 4, true)->getBlockSkyLight($x - 1 & 0x0f,  $y,  $z & 0x0f)),
			($this->getChunk($x >> 4,  $z >> 4, true)->getBlockSkyLight($x & 0x0f,  $y + 1,  $z & 0x0f)),
			($this->getChunk($x >> 4,  $z >> 4, true)->getBlockSkyLight($x & 0x0f,  $y - 1,  $z & 0x0f)),
			($this->getChunk($x >> 4,  $z + 1 >> 4, true)->getBlockSkyLight($x & 0x0f,  $y,  $z + 1 & 0x0f)),
			($this->getChunk($x >> 4,  $z - 1 >> 4, true)->getBlockSkyLight($x & 0x0f,  $y,  $z - 1 & 0x0f))
		]);
	}

	/**
	 * @return void
	 */
	public function updateBlockSkyLight(int $x, int $y, int $z){
		$this->timings->doBlockSkyLightUpdates->startTiming();

		$oldHeightMap = $this->getHeightMap($x, $z);
		$sourceId = ($this->getChunk($x >> 4,  $z >> 4, true)->getBlockId($x & 0x0f,  $y,  $z & 0x0f));

		$yPlusOne = $y + 1;

		if($yPlusOne === $oldHeightMap){ //Block changed directly beneath the heightmap. Check if a block was removed or changed to a different light-filter.
			$newHeightMap = $this->getChunk($x >> 4, $z >> 4)->recalculateHeightMapColumn($x & 0x0f, $z & 0x0f);
		}elseif($yPlusOne > $oldHeightMap){ //Block changed above the heightmap.
			if(BlockFactory::$lightFilter[$sourceId] > 1 or BlockFactory::$diffusesSkyLight[$sourceId]){
				$this->setHeightMap($x, $z, $yPlusOne);
				$newHeightMap = $yPlusOne;
			}else{ //Block changed which has no effect on direct sky light, for example placing or removing glass.
				$this->timings->doBlockSkyLightUpdates->stopTiming();
				return;
			}
		}else{ //Block changed below heightmap
			$newHeightMap = $oldHeightMap;
		}

		if($this->skyLightUpdate === null){
			$this->skyLightUpdate = new SkyLightUpdate($this);
		}
		if($newHeightMap > $oldHeightMap){ //Heightmap increase, block placed, remove sky light
			for($i = $y; $i >= $oldHeightMap; --$i){
				$this->skyLightUpdate->setAndUpdateLight($x, $i, $z, 0); //Remove all light beneath, adjacent recalculation will handle the rest.
			}
		}elseif($newHeightMap < $oldHeightMap){ //Heightmap decrease, block changed or removed, add sky light
			for($i = $y; $i >= $newHeightMap; --$i){
				$this->skyLightUpdate->setAndUpdateLight($x, $i, $z, 15);
			}
		}else{ //No heightmap change, block changed "underground"
			$this->skyLightUpdate->setAndUpdateLight($x, $y, $z, max(0, $this->getHighestAdjacentBlockSkyLight($x, $y, $z) - BlockFactory::$lightFilter[$sourceId]));
		}

		$this->timings->doBlockSkyLightUpdates->stopTiming();
	}

	/**
	 * Returns the highest block light level available in the positions adjacent to the specified block coordinates.
	 */
	public function getHighestAdjacentBlockLight(int $x, int $y, int $z) : int{
		return max([
			($this->getChunk($x + 1 >> 4,  $z >> 4, true)->getBlockLight($x + 1 & 0x0f,  $y,  $z & 0x0f)),
			($this->getChunk($x - 1 >> 4,  $z >> 4, true)->getBlockLight($x - 1 & 0x0f,  $y,  $z & 0x0f)),
			($this->getChunk($x >> 4,  $z >> 4, true)->getBlockLight($x & 0x0f,  $y + 1,  $z & 0x0f)),
			($this->getChunk($x >> 4,  $z >> 4, true)->getBlockLight($x & 0x0f,  $y - 1,  $z & 0x0f)),
			($this->getChunk($x >> 4,  $z + 1 >> 4, true)->getBlockLight($x & 0x0f,  $y,  $z + 1 & 0x0f)),
			($this->getChunk($x >> 4,  $z - 1 >> 4, true)->getBlockLight($x & 0x0f,  $y,  $z - 1 & 0x0f))
		]);
	}

	/**
	 * @return void
	 */
	public function updateBlockLight(int $x, int $y, int $z){
		$this->timings->doBlockLightUpdates->startTiming();

		$id = ($this->getChunk($x >> 4,  $z >> 4, true)->getBlockId($x & 0x0f,  $y,  $z & 0x0f));
		$newLevel = max(BlockFactory::$light[$id], $this->getHighestAdjacentBlockLight($x, $y, $z) - BlockFactory::$lightFilter[$id]);

		if($this->blockLightUpdate === null){
			$this->blockLightUpdate = new BlockLightUpdate($this);
		}
		$this->blockLightUpdate->setAndUpdateLight($x, $y, $z, $newLevel);

		$this->timings->doBlockLightUpdates->stopTiming();
	}

	public function executeQueuedLightUpdates() : void{
		if($this->blockLightUpdate !== null){
			$this->timings->doBlockLightUpdates->startTiming();
			$this->blockLightUpdate->execute();
			$this->blockLightUpdate = null;
			$this->timings->doBlockLightUpdates->stopTiming();
		}

		if($this->skyLightUpdate !== null){
			$this->timings->doBlockSkyLightUpdates->startTiming();
			$this->skyLightUpdate->execute();
			$this->skyLightUpdate = null;
			$this->timings->doBlockSkyLightUpdates->stopTiming();
		}
	}

	/**
	 * Sets on Vector3 the data from a Block object,
	 * does block updates and puts the changes to the send queue.
	 *
	 * If $direct is true, it'll send changes directly to players. if false, it'll be queued
	 * and the best way to send queued changes will be done in the next tick.
	 * This way big changes can be sent on a single chunk update packet instead of thousands of packets.
	 *
	 * If $update is true, it'll get the neighbour blocks (6 sides) and update them.
	 * If you are doing big changes, you might want to set this to false, then update manually.
	 *
	 * @param bool    $direct @deprecated
	 *
	 * @return bool Whether the block has been updated or not
	 */
	public function setBlock(Vector3 $pos, Block $block, bool $direct = false, bool $update = true) : bool{
		$pos = $pos->floor();
		if(!$this->isInWorld($pos->x, $pos->y, $pos->z)){
			return false;
		}

		$this->timings->setBlock->startTiming();

		if($this->getChunkAtPosition($pos, true)->setBlock($pos->x & 0x0f, $pos->y, $pos->z & 0x0f, $block->getId(), $block->getDamage())){
			if(!($pos instanceof Position)){
				$pos = $this->temporalPosition->setComponents($pos->x, $pos->y, $pos->z);
			}

			$block = clone $block;

			$block->position($pos);
			$block->clearCaches();

			$chunkHash = ((($pos->x >> 4) & 0xFFFFFFFF) << 32) | (( $pos->z >> 4) & 0xFFFFFFFF);
			$relativeBlockHash = Level::chunkBlockHash($pos->x, $pos->y, $pos->z);

			unset($this->blockCache[$chunkHash][$relativeBlockHash]);

			if($direct){
				$this->sendBlocks($this->getChunkPlayers($pos->x >> 4, $pos->z >> 4), [$block], UpdateBlockPacket::FLAG_ALL_PRIORITY);
				unset($this->chunkCache[$chunkHash], $this->changedBlocks[$chunkHash][$relativeBlockHash]);
			}else{
				if(!isset($this->changedBlocks[$chunkHash])){
					$this->changedBlocks[$chunkHash] = [];
				}

				$this->changedBlocks[$chunkHash][$relativeBlockHash] = $block;
			}

			foreach($this->getChunkLoaders($pos->x >> 4, $pos->z >> 4) as $loader){
				$loader->onBlockChanged($block);
			}

			if($update){
				$this->updateAllLight($block);

				$ev = new BlockUpdateEvent($block);
				$ev->call();
				if(!$ev->isCancelled()){
					foreach($this->getNearbyEntities(new AxisAlignedBB($block->x - 1, $block->y - 1, $block->z - 1, $block->x + 2, $block->y + 2, $block->z + 2)) as $entity){
						$entity->onNearbyBlockChange();
					}
					$ev->getBlock()->onNearbyBlockChange();
					$this->scheduleNeighbourBlockUpdates($pos);
				}
			}

			$this->timings->setBlock->stopTiming();

			return true;
		}

		$this->timings->setBlock->stopTiming();

		return false;
	}

	/**
	 * @return ItemEntity|null
	 */
	public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, int $delay = 10){
		$motion = $motion ?? new Vector3(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1);
		$itemTag = $item->nbtSerialize();
		$itemTag->setName("Item");

		if(!$item->isNull()){
			$nbt = Entity::createBaseNBT($source, $motion, lcg_value() * 360, 0);
			$nbt->setShort("Health", 5);
			$nbt->setShort("PickupDelay", $delay);
			$nbt->setTag($itemTag);
			$itemEntity = Entity::createEntity("Item", $this, $nbt);

			if($itemEntity instanceof ItemEntity){
				$itemEntity->spawnToAll();

				return $itemEntity;
			}
		}
		return null;
	}

	/**
	 * Drops XP orbs into the world for the specified amount, splitting the amount into several orbs if necessary.
	 *
	 * @return ExperienceOrb[]
	 */
	public function dropExperience(Vector3 $pos, int $amount) : array{
		/** @var ExperienceOrb[] $orbs */
		$orbs = [];

		foreach(ExperienceOrb::splitIntoOrbSizes($amount) as $split){
			$nbt = Entity::createBaseNBT(
				$pos,
				$this->temporalVector->setComponents((lcg_value() * 0.2 - 0.1) * 2, lcg_value() * 0.4, (lcg_value() * 0.2 - 0.1) * 2),
				lcg_value() * 360,
				0
			);
			$nbt->setShort(ExperienceOrb::TAG_VALUE_PC, $split);

			$orb = Entity::createEntity("XPOrb", $this, $nbt);
			if($orb === null){
				continue;
			}

			$orb->spawnToAll();
			if($orb instanceof ExperienceOrb){
				$orbs[] = $orb;
			}
		}

		return $orbs;
	}

	/**
	 * Checks if the level spawn protection radius will prevent the player from using items or building at the specified
	 * Vector3 position.
	 *
	 * @return bool true if spawn protection cancelled the action, false if not.
	 */
	public function checkSpawnProtection(Player $player, Vector3 $vector) : bool{
		if(!$player->hasPermission("pocketmine.spawnprotect.bypass") and ($distance = $this->server->getSpawnRadius()) > -1){
			$t = new Vector2($vector->x, $vector->z);

			$spawnLocation = $this->getSpawnLocation();
			$s = new Vector2($spawnLocation->x, $spawnLocation->z);
			if($t->distance($s) <= $distance){
				return true;
			}
		}

		return false;
	}

	/**
	 * Tries to break a block using a item, including Player time checks if available
	 * It'll try to lower the durability if Item is a tool, and set it to Air if broken.
	 *
	 * @param Item    $item reference parameter (if null, can break anything)
	 */
	public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = null, bool $createParticles = false) : bool{
		$target = $this->getBlock($vector);
		$affectedBlocks = $target->getAffectedBlocks();

		if($item === null){
			$item = ItemFactory::get(Item::AIR, 0, 0);
		}

		$drops = [];
		if($player === null or !$player->isCreative()){
			$drops = array_merge(...array_map(function(Block $block) use ($item) : array{ return $block->getDrops($item); }, $affectedBlocks));
		}

		$xpDrop = 0;
		if($player !== null and !$player->isCreative()){
			$xpDrop = array_sum(array_map(function(Block $block) use ($item) : int{ return $block->getXpDropForTool($item); }, $affectedBlocks));
		}

		if($player !== null){
			$ev = new BlockBreakEvent($player, $target, $item, $player->isCreative(), $drops, $xpDrop);

			if($target instanceof Air or ($player->isSurvival() and !$target->isBreakable($item)) or $player->isSpectator()){
				$ev->setCancelled();
			}elseif($this->checkSpawnProtection($player, $target)){
				$ev->setCancelled(); //set it to cancelled so plugins can bypass this
			}

			if($player->isAdventure(true) and !$ev->isCancelled()){
				$tag = $item->getNamedTagEntry("CanDestroy");
				$canBreak = false;
				if($tag instanceof ListTag){
					foreach($tag as $v){
						if($v instanceof StringTag){
							$entry = ItemFactory::fromString($v->getValue());
							if($entry->getId() > 0 and $entry->getBlock()->getId() === $target->getId()){
								$canBreak = true;
								break;
							}
						}
					}
				}

				$ev->setCancelled(!$canBreak);
			}

			$ev->call();
			if($ev->isCancelled()){
				return false;
			}

			$drops = $ev->getDrops();
			$xpDrop = $ev->getXpDropAmount();

		}elseif(!$target->isBreakable($item)){
			return false;
		}

		foreach($affectedBlocks as $t){
			$this->destroyBlockInternal($t, $item, $player, $createParticles);
		}

		$item->onDestroyBlock($target);

		if(count($drops) > 0){
			$dropPos = $target->add(0.5, 0.5, 0.5);
			foreach($drops as $drop){
				if(!$drop->isNull()){
					$this->dropItem($dropPos, $drop);
				}
			}
		}

		if($xpDrop > 0){
			$this->dropExperience($target->add(0.5, 0.5, 0.5), $xpDrop);
		}

		return true;
	}

	private function destroyBlockInternal(Block $target, Item $item, ?Player $player = null, bool $createParticles = false) : void{
		if($createParticles){
			$this->addParticle(new DestroyBlockParticle($target->add(0.5, 0.5, 0.5), $target));
		}

		$target->onBreak($item, $player);

		$tile = $this->getTile($target);
		if($tile !== null){
			if($tile instanceof Container){
				if($tile instanceof Chest){
					$tile->unpair();
				}

				$tile->getInventory()->dropContents($this, $target);
			}

			$tile->close();
		}
	}

	/**
	 * Uses a item on a position and face, placing it or activating the block
	 *
	 * @param Player|null  $player default null
	 * @param bool         $playSound Whether to play a block-place sound if the block was placed successfully.
	 */
	public function useItemOn(Vector3 $vector, Item &$item, int $face, Vector3 $clickVector = null, Player $player = null, bool $playSound = false) : bool{
		$blockClicked = $this->getBlock($vector);
		$blockReplace = $blockClicked->getSide($face);

		if($clickVector === null){
			$clickVector = new Vector3(0.0, 0.0, 0.0);
		}

		if(!$this->isInWorld($blockReplace->x, $blockReplace->y, $blockReplace->z)){
			//TODO: build height limit messages for custom world heights and mcregion cap
			return false;
		}

		if($blockClicked->getId() === Block::AIR){
			return false;
		}

		if($player !== null){
			$ev = new PlayerInteractEvent($player, $item, $blockClicked, $clickVector, $face, PlayerInteractEvent::RIGHT_CLICK_BLOCK);
			if($this->checkSpawnProtection($player, $blockClicked)){
				$ev->setCancelled(); //set it to cancelled so plugins can bypass this
			}

			$ev->call();
			if(!$ev->isCancelled()){
				if(!$player->isSneaking() and $blockClicked->onActivate($item, $player)){
					return true;
				}

				if(!$player->isSneaking() and $item->onActivate($player, $blockReplace, $blockClicked, $face, $clickVector)){
					return true;
				}
			}else{
				return false;
			}
		}elseif($blockClicked->onActivate($item, $player)){
			return true;
		}

		if($item->canBePlaced()){
			$hand = $item->getBlock();
			$hand->position($blockReplace);
		}else{
			return false;
		}

		if($hand->canBePlacedAt($blockClicked, $clickVector, $face, true)){
			$blockReplace = $blockClicked;
			$hand->position($blockReplace);
		}elseif(!$hand->canBePlacedAt($blockReplace, $clickVector, $face, false)){
			return false;
		}

		if($hand->isSolid()){
			foreach($hand->getCollisionBoxes() as $collisionBox){
				if(count($this->getCollidingEntities($collisionBox)) > 0){
					return false;  //Entity in block
				}

				if($player !== null){
					if(($diff = $player->getNextPosition()->subtract($player->getPosition())) and $diff->lengthSquared() > 0.00001){
						$bb = $player->getBoundingBox()->offsetCopy($diff->x, $diff->y, $diff->z);
						if($collisionBox->intersectsWith($bb)){
							return false; //Inside player BB
						}
					}
				}
			}
		}

		if($player !== null){
			$ev = new BlockPlaceEvent($player, $hand, $blockReplace, $blockClicked, $item);
			if($this->checkSpawnProtection($player, $blockClicked)){
				$ev->setCancelled();
			}

			if($player->isAdventure(true) and !$ev->isCancelled()){
				$canPlace = false;
				$tag = $item->getNamedTagEntry("CanPlaceOn");
				if($tag instanceof ListTag){
					foreach($tag as $v){
						if($v instanceof StringTag){
							$entry = ItemFactory::fromString($v->getValue());
							if($entry->getId() > 0 and $entry->getBlock()->getId() === $blockClicked->getId()){
								$canPlace = true;
								break;
							}
						}
					}
				}

				$ev->setCancelled(!$canPlace);
			}

			$ev->call();
			if($ev->isCancelled()){
				return false;
			}
		}

		if(!$hand->place($item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
			return false;
		}

		if($playSound){
			$this->broadcastLevelSoundEvent($hand, LevelSoundEventPacket::SOUND_PLACE, $hand->getRuntimeId());
		}

		$item->pop();

		return true;
	}

	/**
	 * @return Entity|null
	 */
	public function getEntity(int $entityId){
		return $this->entities[$entityId] ?? null;
	}

	/**
	 * Gets the list of all the entities in this level
	 *
	 * @return Entity[]
	 */
	public function getEntities() : array{
		return $this->entities;
	}

	/**
	 * Returns the entities colliding the current one inside the AxisAlignedBB
	 *
	 * @return Entity[]
	 */
	public function getCollidingEntities(AxisAlignedBB $bb, Entity $entity = null) : array{
		$nearby = [];

		if($entity === null or $entity->canCollide){
			$minX = ((int) floor($bb->minX - 2)) >> 4;
			$maxX = ((int) floor($bb->maxX + 2)) >> 4;
			$minZ = ((int) floor($bb->minZ - 2)) >> 4;
			$maxZ = ((int) floor($bb->maxZ + 2)) >> 4;

			for($x = $minX; $x <= $maxX; ++$x){
				for($z = $minZ; $z <= $maxZ; ++$z){
					foreach((($______chunk = $this->getChunk($x,  $z)) !== null ? $______chunk->getEntities() : []) as $ent){
						/** @var Entity|null $entity */
						if($ent->canBeCollidedWith() and ($entity === null or ($ent !== $entity and $entity->canCollideWith($ent))) and $ent->boundingBox->intersectsWith($bb)){
							$nearby[] = $ent;
						}
					}
				}
			}
		}

		return $nearby;
	}

	/**
	 * Returns the entities near the current one inside the AxisAlignedBB
	 *
	 * @return Entity[]
	 */
	public function getNearbyEntities(AxisAlignedBB $bb, Entity $entity = null) : array{
		$nearby = [];

		$minX = ((int) floor($bb->minX - 2)) >> 4;
		$maxX = ((int) floor($bb->maxX + 2)) >> 4;
		$minZ = ((int) floor($bb->minZ - 2)) >> 4;
		$maxZ = ((int) floor($bb->maxZ + 2)) >> 4;

		for($x = $minX; $x <= $maxX; ++$x){
			for($z = $minZ; $z <= $maxZ; ++$z){
				foreach((($______chunk = $this->getChunk($x,  $z)) !== null ? $______chunk->getEntities() : []) as $ent){
					if($ent !== $entity and $ent->boundingBox->intersectsWith($bb)){
						$nearby[] = $ent;
					}
				}
			}
		}

		return $nearby;
	}

	/**
	 * Returns the closest Entity to the specified position, within the given radius.
	 *
	 * @param string  $entityType Class of entity to use for instanceof
	 * @param bool    $includeDead Whether to include entitites which are dead
	 * @phpstan-template TEntity of Entity
	 * @phpstan-param class-string<TEntity> $entityType
	 *
	 * @return Entity|null an entity of type $entityType, or null if not found
	 * @phpstan-return TEntity
	 */
	public function getNearestEntity(Vector3 $pos, float $maxDistance, string $entityType = Entity::class, bool $includeDead = false) : ?Entity{
		assert(is_a($entityType, Entity::class, true));

		$minX = ((int) floor($pos->x - $maxDistance)) >> 4;
		$maxX = ((int) floor($pos->x + $maxDistance)) >> 4;
		$minZ = ((int) floor($pos->z - $maxDistance)) >> 4;
		$maxZ = ((int) floor($pos->z + $maxDistance)) >> 4;

		$currentTargetDistSq = $maxDistance ** 2;

		/**
		 * @var Entity|null $currentTarget
		 * @phpstan-var TEntity|null $currentTarget
		 */
		$currentTarget = null;

		for($x = $minX; $x <= $maxX; ++$x){
			for($z = $minZ; $z <= $maxZ; ++$z){
				foreach((($______chunk = $this->getChunk($x,  $z)) !== null ? $______chunk->getEntities() : []) as $entity){
					if(!($entity instanceof $entityType) or $entity->isClosed() or $entity->isFlaggedForDespawn() or (!$includeDead and !$entity->isAlive())){
						continue;
					}
					$distSq = $entity->distanceSquared($pos);
					if($distSq < $currentTargetDistSq){
						$currentTargetDistSq = $distSq;
						$currentTarget = $entity;
					}
				}
			}
		}

		return $currentTarget;
	}

	/**
	 * Returns a list of the Tile entities in this level
	 *
	 * @return Tile[]
	 */
	public function getTiles() : array{
		return $this->tiles;
	}

	/**
	 * @return Tile|null
	 */
	public function getTileById(int $tileId){
		return $this->tiles[$tileId] ?? null;
	}

	/**
	 * Returns a list of the players in this level
	 *
	 * @return Player[]
	 */
	public function getPlayers() : array{
		return $this->players;
	}

	/**
	 * @return ChunkLoader[]
	 */
	public function getLoaders() : array{
		return $this->loaders;
	}

	/**
	 * Returns the Tile in a position, or null if not found.
	 *
	 * Note: This method wraps getTileAt(). If you're guaranteed to be passing integers, and you're using this method
	 * in performance-sensitive code, consider using getTileAt() instead of this method for better performance.
	 */
	public function getTile(Vector3 $pos) : ?Tile{
		return $this->getTileAt((int) floor($pos->x), (int) floor($pos->y), (int) floor($pos->z));
	}

	/**
	 * Returns the tile at the specified x,y,z coordinates, or null if it does not exist.
	 */
	public function getTileAt(int $x, int $y, int $z) : ?Tile{
		$chunk = $this->getChunk($x >> 4, $z >> 4);

		if($chunk !== null){
			return $chunk->getTile($x & 0x0f, $y, $z & 0x0f);
		}

		return null;
	}

	/**
	 * Returns a list of the entities on a given chunk
	 *
	 * @return Entity[]
	 */
	public function getChunkEntities(int $X, int $Z) : array{
		return ($chunk = $this->getChunk($X, $Z)) !== null ? $chunk->getEntities() : [];
	}

	/**
	 * Gives a list of the Tile entities on a given chunk
	 *
	 * @return Tile[]
	 */
	public function getChunkTiles(int $X, int $Z) : array{
		return ($chunk = $this->getChunk($X, $Z)) !== null ? $chunk->getTiles() : [];
	}

	/**
	 * Gets the raw block id.
	 *
	 * @return int 0-255
	 */
	public function getBlockIdAt(int $x, int $y, int $z) : int{
		return $this->getChunk($x >> 4, $z >> 4, true)->getBlockId($x & 0x0f, $y, $z & 0x0f);
	}

	/**
	 * Sets the raw block id.
	 *
	 * @param int $id 0-255
	 *
	 * @return void
	 */
	public function setBlockIdAt(int $x, int $y, int $z, int $id){
		if(!$this->isInWorld($x, $y, $z)){ //TODO: bad hack but fixing this requires BC breaks to do properly :(
			return;
		}
		$chunkHash = ((($x >> 4) & 0xFFFFFFFF) << 32) | (( $z >> 4) & 0xFFFFFFFF);
		$relativeBlockHash = Level::chunkBlockHash($x, $y, $z);
		unset($this->blockCache[$chunkHash][$relativeBlockHash]);
		$this->getChunk($x >> 4, $z >> 4, true)->setBlockId($x & 0x0f, $y, $z & 0x0f, $id & 0xff);

		if(!isset($this->changedBlocks[$chunkHash])){
			$this->changedBlocks[$chunkHash] = [];
		}
		$this->changedBlocks[$chunkHash][$relativeBlockHash] = $v = new Vector3($x, $y, $z);
		foreach($this->getChunkLoaders($x >> 4, $z >> 4) as $loader){
			$loader->onBlockChanged($v);
		}
	}

	/**
	 * Gets the raw block metadata
	 *
	 * @return int 0-15
	 */
	public function getBlockDataAt(int $x, int $y, int $z) : int{
		return $this->getChunk($x >> 4, $z >> 4, true)->getBlockData($x & 0x0f, $y, $z & 0x0f);
	}

	/**
	 * Sets the raw block metadata.
	 *
	 * @param int $data 0-15
	 *
	 * @return void
	 */
	public function setBlockDataAt(int $x, int $y, int $z, int $data){
		if(!$this->isInWorld($x, $y, $z)){ //TODO: bad hack but fixing this requires BC breaks to do properly :(
			return;
		}
		$chunkHash = ((($x >> 4) & 0xFFFFFFFF) << 32) | (( $z >> 4) & 0xFFFFFFFF);
		$relativeBlockHash = Level::chunkBlockHash($x, $y, $z);
		unset($this->blockCache[$chunkHash][$relativeBlockHash]);

		$this->getChunk($x >> 4, $z >> 4, true)->setBlockData($x & 0x0f, $y, $z & 0x0f, $data & 0x0f);

		if(!isset($this->changedBlocks[$chunkHash])){
			$this->changedBlocks[$chunkHash] = [];
		}
		$this->changedBlocks[$chunkHash][$relativeBlockHash] = $v = new Vector3($x, $y, $z);
		foreach($this->getChunkLoaders($x >> 4, $z >> 4) as $loader){
			$loader->onBlockChanged($v);
		}
	}

	/**
	 * Gets the raw block skylight level
	 *
	 * @return int 0-15
	 */
	public function getBlockSkyLightAt(int $x, int $y, int $z) : int{
		return $this->getChunk($x >> 4, $z >> 4, true)->getBlockSkyLight($x & 0x0f, $y, $z & 0x0f);
	}

	/**
	 * Sets the raw block skylight level.
	 *
	 * @param int $level 0-15
	 *
	 * @return void
	 */
	public function setBlockSkyLightAt(int $x, int $y, int $z, int $level){
		$this->getChunk($x >> 4, $z >> 4, true)->setBlockSkyLight($x & 0x0f, $y, $z & 0x0f, $level & 0x0f);
	}

	/**
	 * Gets the raw block light level
	 *
	 * @return int 0-15
	 */
	public function getBlockLightAt(int $x, int $y, int $z) : int{
		return $this->getChunk($x >> 4, $z >> 4, true)->getBlockLight($x & 0x0f, $y, $z & 0x0f);
	}

	/**
	 * Sets the raw block light level.
	 *
	 * @param int $level 0-15
	 *
	 * @return void
	 */
	public function setBlockLightAt(int $x, int $y, int $z, int $level){
		$this->getChunk($x >> 4, $z >> 4, true)->setBlockLight($x & 0x0f, $y, $z & 0x0f, $level & 0x0f);
	}

	public function getBiomeId(int $x, int $z) : int{
		return $this->getChunk($x >> 4, $z >> 4, true)->getBiomeId($x & 0x0f, $z & 0x0f);
	}

	public function getBiome(int $x, int $z) : Biome{
		return Biome::getBiome($this->getBiomeId($x, $z));
	}

	/**
	 * @return void
	 */
	public function setBiomeId(int $x, int $z, int $biomeId){
		$this->getChunk($x >> 4, $z >> 4, true)->setBiomeId($x & 0x0f, $z & 0x0f, $biomeId);
	}

	public function getHeightMap(int $x, int $z) : int{
		return $this->getChunk($x >> 4, $z >> 4, true)->getHeightMap($x & 0x0f, $z & 0x0f);
	}

	/**
	 * @return void
	 */
	public function setHeightMap(int $x, int $z, int $value){
		$this->getChunk($x >> 4, $z >> 4, true)->setHeightMap($x & 0x0f, $z & 0x0f, $value);
	}

	/**
	 * @return Chunk[]
	 */
	public function getChunks() : array{
		return $this->chunks;
	}

	/**
	 * Returns the chunk at the specified X/Z coordinates. If the chunk is not loaded, attempts to (synchronously!!!)
	 * load it.
	 *
	 * @param bool $create Whether to create an empty chunk as a placeholder if the chunk does not exist
	 *
	 * @return Chunk|null
	 */
	public function getChunk(int $x, int $z, bool $create = false){
		if(isset($this->chunks[$index = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)])){
			return $this->chunks[$index];
		}elseif($this->loadChunk($x, $z, $create)){
			return $this->chunks[$index];
		}

		return null;
	}

	/**
	 * Returns the chunk containing the given Vector3 position.
	 */
	public function getChunkAtPosition(Vector3 $pos, bool $create = false) : ?Chunk{
		return $this->getChunk($pos->getFloorX() >> 4, $pos->getFloorZ() >> 4, $create);
	}

	/**
	 * Returns the chunks adjacent to the specified chunk.
	 *
	 * @return (Chunk|null)[]
	 */
	public function getAdjacentChunks(int $x, int $z) : array{
		$result = [];
		for($xx = 0; $xx <= 2; ++$xx){
			for($zz = 0; $zz <= 2; ++$zz){
				$i = $zz * 3 + $xx;
				if($i === 4){
					continue; //center chunk
				}
				$result[$i] = $this->getChunk($x + $xx - 1, $z + $zz - 1, false);
			}
		}

		return $result;
	}

	/**
	 * @return void
	 */
	public function generateChunkCallback(int $x, int $z, ?Chunk $chunk){
		Timings::$generationCallbackTimer->startTiming();
		if(isset($this->chunkPopulationQueue[$index = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)])){
			for($xx = -1; $xx <= 1; ++$xx){
				for($zz = -1; $zz <= 1; ++$zz){
					unset($this->chunkPopulationLock[((($x + $xx) & 0xFFFFFFFF) << 32) | (( $z + $zz) & 0xFFFFFFFF)]);
				}
			}
			unset($this->chunkPopulationQueue[$index]);

			if($chunk !== null){
				$oldChunk = $this->getChunk($x, $z, false);
				$this->setChunk($x, $z, $chunk, false);
				if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){
					(new ChunkPopulateEvent($this, $chunk))->call();

					foreach($this->getChunkLoaders($x, $z) as $loader){
						$loader->onChunkPopulated($chunk);
					}
				}
			}
		}elseif(isset($this->chunkPopulationLock[$index])){
			unset($this->chunkPopulationLock[$index]);
			if($chunk !== null){
				$this->setChunk($x, $z, $chunk, false);
			}
		}elseif($chunk !== null){
			$this->setChunk($x, $z, $chunk, false);
		}
		Timings::$generationCallbackTimer->stopTiming();
	}

	/**
	 * @param bool       $deleteEntitiesAndTiles Whether to delete entities and tiles on the old chunk, or transfer them to the new one
	 *
	 * @return void
	 */
	public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null, bool $deleteEntitiesAndTiles = true){
		if($chunk === null){
			return;
		}

		$chunk->setX($chunkX);
		$chunk->setZ($chunkZ);

		$chunkHash = ((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF);
		$oldChunk = $this->getChunk($chunkX, $chunkZ, false);
		if($oldChunk !== null and $oldChunk !== $chunk){
			if($deleteEntitiesAndTiles){
				foreach($oldChunk->getEntities() as $player){
					if(!($player instanceof Player)){
						continue;
					}
					$chunk->addEntity($player);
					$oldChunk->removeEntity($player);
					$player->chunk = $chunk;
				}
				//TODO: this causes chunkloaders to receive false "unloaded" notifications
				$this->unloadChunk($chunkX, $chunkZ, false, false);
			}else{
				foreach($oldChunk->getEntities() as $entity){
					$chunk->addEntity($entity);
					$oldChunk->removeEntity($entity);
					$entity->chunk = $chunk;
				}

				foreach($oldChunk->getTiles() as $tile){
					$chunk->addTile($tile);
					$oldChunk->removeTile($tile);
				}
			}
		}

		$this->chunks[$chunkHash] = $chunk;

		unset($this->blockCache[$chunkHash]);
		unset($this->chunkCache[$chunkHash]);
		unset($this->changedBlocks[$chunkHash]);
		if(isset($this->chunkSendTasks[$chunkHash])){ //invalidate pending caches
			$this->chunkSendTasks[$chunkHash]->cancelRun();
			unset($this->chunkSendTasks[$chunkHash]);
		}
		$chunk->setChanged();

		if(!$this->isChunkInUse($chunkX, $chunkZ)){
			$this->unloadChunkRequest($chunkX, $chunkZ);
		}else{
			foreach($this->getChunkLoaders($chunkX, $chunkZ) as $loader){
				$loader->onChunkChanged($chunk);
			}
		}
	}

	/**
	 * Gets the highest block Y value at a specific $x and $z
	 *
	 * @return int 0-255
	 */
	public function getHighestBlockAt(int $x, int $z) : int{
		return $this->getChunk($x >> 4, $z >> 4, true)->getHighestBlockAt($x & 0x0f, $z & 0x0f);
	}

	/**
	 * Returns whether the given position is in a loaded area of terrain.
	 */
	public function isInLoadedTerrain(Vector3 $pos) : bool{
		return (isset($this->chunks[((($pos->getFloorX() >> 4) & 0xFFFFFFFF) << 32) | ((  $pos->getFloorZ() >> 4) & 0xFFFFFFFF)]));
	}

	public function isChunkLoaded(int $x, int $z) : bool{
		return isset($this->chunks[((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)]);
	}

	public function isChunkGenerated(int $x, int $z) : bool{
		$chunk = $this->getChunk($x, $z);
		return $chunk !== null ? $chunk->isGenerated() : false;
	}

	public function isChunkPopulated(int $x, int $z) : bool{
		$chunk = $this->getChunk($x, $z);
		return $chunk !== null ? $chunk->isPopulated() : false;
	}

	/**
	 * Returns a Position pointing to the spawn
	 */
	public function getSpawnLocation() : Position{
		return Position::fromObject($this->provider->getSpawn(), $this);
	}

	/**
	 * Sets the level spawn location
	 *
	 * @return void
	 */
	public function setSpawnLocation(Vector3 $pos){
		$previousSpawn = $this->getSpawnLocation();
		$this->provider->setSpawn($pos);
		(new SpawnChangeEvent($this, $previousSpawn))->call();
	}

	/**
	 * @return void
	 */
	public function requestChunk(int $x, int $z, Player $player){
		$index = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF);
		if(!isset($this->chunkSendQueue[$index])){
			$this->chunkSendQueue[$index] = [];
		}

		$this->chunkSendQueue[$index][$player->getLoaderId()] = $player;
	}

	private function sendChunkFromCache(int $x, int $z) : void{
		if(isset($this->chunkSendQueue[$index = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)])){
			foreach($this->chunkSendQueue[$index] as $player){
				/** @var Player $player */
				if($player->isConnected() and isset($player->usedChunks[$index])){
					$player->sendChunk($x, $z, $this->chunkCache[$index]);
				}
			}
			unset($this->chunkSendQueue[$index]);
		}
	}

	private function processChunkRequest() : void{
		if(count($this->chunkSendQueue) > 0){
			$this->timings->syncChunkSendTimer->startTiming();

			foreach($this->chunkSendQueue as $index => $players){
				 $x = ($index >> 32);  $z = ($index & 0xFFFFFFFF) << 32 >> 32;

				if(isset($this->chunkSendTasks[$index])){
					if($this->chunkSendTasks[$index]->isCrashed()){
						unset($this->chunkSendTasks[$index]);
						$this->server->getLogger()->error("Failed to prepare chunk $x $z for sending, retrying");
					}else{
						//Not ready for sending yet
						continue;
					}
				}
				if(isset($this->chunkCache[$index])){
					$this->sendChunkFromCache($x, $z);
					continue;
				}
				$this->timings->syncChunkSendPrepareTimer->startTiming();

				$chunk = $this->chunks[$index] ?? null;
				if(!($chunk instanceof Chunk)){
					throw new ChunkException("Invalid Chunk sent");
				}
				assert($chunk->getX() === $x and $chunk->getZ() === $z, "Chunk coordinate mismatch: expected $x $z, but chunk has coordinates " . $chunk->getX() . " " . $chunk->getZ() . ", did you forget to clone a chunk before setting?");

				$this->server->getAsyncPool()->submitTask($task = new ChunkRequestTask($this, $x, $z, $chunk));
				$this->chunkSendTasks[$index] = $task;

				$this->timings->syncChunkSendPrepareTimer->stopTiming();
			}

			$this->timings->syncChunkSendTimer->stopTiming();
		}
	}

	/**
	 * @return void
	 */
	public function chunkRequestCallback(int $x, int $z, BatchPacket $payload){
		$this->timings->syncChunkSendTimer->startTiming();

		$index = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF);
		unset($this->chunkSendTasks[$index]);

		$this->chunkCache[$index] = $payload;
		$this->sendChunkFromCache($x, $z);
		if(!$this->server->getMemoryManager()->canUseChunkCache()){
			unset($this->chunkCache[$index]);
		}

		$this->timings->syncChunkSendTimer->stopTiming();
	}

	/**
	 * @return void
	 * @throws LevelException
	 */
	public function addEntity(Entity $entity){
		if($entity->isClosed()){
			throw new \InvalidArgumentException("Attempted to add a garbage closed Entity to world");
		}
		if($entity->getLevel() !== $this){
			throw new LevelException("Invalid Entity world");
		}

		if($entity instanceof Player){
			$this->players[$entity->getId()] = $entity;
		}
		$this->entities[$entity->getId()] = $entity;
	}

	/**
	 * Removes the entity from the level index
	 *
	 * @return void
	 * @throws LevelException
	 */
	public function removeEntity(Entity $entity){
		if($entity->getLevel() !== $this){
			throw new LevelException("Invalid Entity world");
		}

		if($entity instanceof Player){
			unset($this->players[$entity->getId()]);
			$this->checkSleep();
		}

		unset($this->entities[$entity->getId()]);
		unset($this->updateEntities[$entity->getId()]);
	}

	/**
	 * @return void
	 * @throws LevelException
	 */
	public function addTile(Tile $tile){
		if($tile->isClosed()){
			throw new \InvalidArgumentException("Attempted to add a garbage closed Tile to world");
		}
		if($tile->getLevel() !== $this){
			throw new LevelException("Invalid Tile world");
		}

		$chunkX = $tile->getFloorX() >> 4;
		$chunkZ = $tile->getFloorZ() >> 4;

		if(isset($this->chunks[$hash = ((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)])){
			$this->chunks[$hash]->addTile($tile);
		}else{
			throw new \InvalidStateException("Attempted to create tile " . get_class($tile) . " in unloaded chunk $chunkX $chunkZ");
		}

		$this->tiles[$tile->getId()] = $tile;
		$this->clearChunkCache($chunkX, $chunkZ);
	}

	/**
	 * @return void
	 * @throws LevelException
	 */
	public function removeTile(Tile $tile){
		if($tile->getLevel() !== $this){
			throw new LevelException("Invalid Tile world");
		}

		unset($this->tiles[$tile->getId()], $this->updateTiles[$tile->getId()]);

		$chunkX = $tile->getFloorX() >> 4;
		$chunkZ = $tile->getFloorZ() >> 4;

		if(isset($this->chunks[$hash = ((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)])){
			$this->chunks[$hash]->removeTile($tile);
		}
		$this->clearChunkCache($chunkX, $chunkZ);
	}

	public function isChunkInUse(int $x, int $z) : bool{
		return isset($this->chunkLoaders[$index = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)]) and count($this->chunkLoaders[$index]) > 0;
	}

	/**
	 * Attempts to load a chunk from the level provider (if not already loaded).
	 *
	 * @param bool $create Whether to create an empty chunk to load if the chunk cannot be loaded from disk.
	 *
	 * @return bool if loading the chunk was successful
	 *
	 * @throws \InvalidStateException
	 */
	public function loadChunk(int $x, int $z, bool $create = true) : bool{
		if(isset($this->chunks[$chunkHash = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)])){
			return true;
		}

		$this->timings->syncChunkLoadTimer->startTiming();

		$this->cancelUnloadChunkRequest($x, $z);

		$this->timings->syncChunkLoadDataTimer->startTiming();

		$chunk = null;

		try{
			$chunk = $this->provider->loadChunk($x, $z);
		}catch(CorruptedChunkException | UnsupportedChunkFormatException $e){
			$logger = $this->server->getLogger();
			$logger->critical("Failed to load chunk x=$x z=$z: " . $e->getMessage());
		}

		if($chunk === null and $create){
			$chunk = new Chunk($x, $z);
		}

		$this->timings->syncChunkLoadDataTimer->stopTiming();

		if($chunk === null){
			$this->timings->syncChunkLoadTimer->stopTiming();
			return false;
		}

		$this->chunks[$chunkHash] = $chunk;
		unset($this->blockCache[$chunkHash]);

		$chunk->initChunk($this);

		(new ChunkLoadEvent($this, $chunk, !$chunk->isGenerated()))->call();

		if(!$chunk->isLightPopulated() and $chunk->isPopulated() and $this->getServer()->getProperty("chunk-ticking.light-updates", false)){
			$this->getServer()->getAsyncPool()->submitTask(new LightPopulationTask($this, $chunk));
		}

		if($this->isChunkInUse($x, $z)){
			foreach($this->getChunkLoaders($x, $z) as $loader){
				$loader->onChunkLoaded($chunk);
			}
		}else{
			$this->server->getLogger()->debug("Newly loaded chunk $x $z has no loaders registered, will be unloaded at next available opportunity");
			$this->unloadChunkRequest($x, $z);
		}

		$this->timings->syncChunkLoadTimer->stopTiming();

		return true;
	}

	private function queueUnloadChunk(int $x, int $z) : void{
		$this->unloadQueue[$index = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)] = microtime(true);
		unset($this->chunkTickList[$index]);
	}

	/**
	 * @return bool
	 */
	public function unloadChunkRequest(int $x, int $z, bool $safe = true){
		if(($safe and $this->isChunkInUse($x, $z)) or $this->isSpawnChunk($x, $z)){
			return false;
		}

		$this->queueUnloadChunk($x, $z);

		return true;
	}

	/**
	 * @return void
	 */
	public function cancelUnloadChunkRequest(int $x, int $z){
		unset($this->unloadQueue[((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)]);
	}

	public function unloadChunk(int $x, int $z, bool $safe = true, bool $trySave = true) : bool{
		if($safe and $this->isChunkInUse($x, $z)){
			return false;
		}

		if(!(isset($this->chunks[((($x) & 0xFFFFFFFF) << 32) | ((  $z) & 0xFFFFFFFF)]))){
			return true;
		}

		$this->timings->doChunkUnload->startTiming();

		$chunkHash = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF);

		$chunk = $this->chunks[$chunkHash] ?? null;

		if($chunk !== null){
			$ev = new ChunkUnloadEvent($this, $chunk);
			$ev->call();
			if($ev->isCancelled()){
				$this->timings->doChunkUnload->stopTiming();

				return false;
			}

			if($trySave and $this->getAutoSave() and $chunk->isGenerated()){
				if($chunk->hasChanged() or count($chunk->getTiles()) > 0 or count($chunk->getSavableEntities()) > 0){
					$this->timings->syncChunkSaveTimer->startTiming();
					try{
						$this->provider->saveChunk($chunk);
					}finally{
						$this->timings->syncChunkSaveTimer->stopTiming();
					}
				}
			}

			foreach($this->getChunkLoaders($x, $z) as $loader){
				$loader->onChunkUnloaded($chunk);
			}

			$chunk->onUnload();
		}

		unset($this->chunks[$chunkHash]);
		unset($this->chunkTickList[$chunkHash]);
		unset($this->chunkCache[$chunkHash]);
		unset($this->blockCache[$chunkHash]);
		unset($this->changedBlocks[$chunkHash]);
		unset($this->chunkSendQueue[$chunkHash]);
		unset($this->chunkSendTasks[$chunkHash]);

		$this->timings->doChunkUnload->stopTiming();

		return true;
	}

	/**
	 * Returns whether the chunk at the specified coordinates is a spawn chunk
	 */
	public function isSpawnChunk(int $X, int $Z) : bool{
		$spawn = $this->provider->getSpawn();
		$spawnX = $spawn->x >> 4;
		$spawnZ = $spawn->z >> 4;

		return abs($X - $spawnX) <= 1 and abs($Z - $spawnZ) <= 1;
	}

	public function getSafeSpawn(?Vector3 $spawn = null) : Position{
		if(!($spawn instanceof Vector3) or $spawn->y < 1){
			$spawn = $this->getSpawnLocation();
		}

		$max = $this->worldHeight;
		$v = $spawn->floor();
		$chunk = $this->getChunkAtPosition($v, false);
		$x = (int) $v->x;
		$z = (int) $v->z;
		if($chunk !== null and $chunk->isGenerated()){
			$y = (int) min($max - 2, $v->y);
			$wasAir = ($chunk->getBlockId($x & 0x0f, $y - 1, $z & 0x0f) === 0);
			for(; $y > 0; --$y){
				if($this->isFullBlock($this->getBlockAt($x, $y, $z))){
					if($wasAir){
						$y++;
						break;
					}
				}else{
					$wasAir = true;
				}
			}

			for(; $y >= 0 and $y < $max; ++$y){
				if(!$this->isFullBlock($this->getBlockAt($x, $y + 1, $z))){
					if(!$this->isFullBlock($this->getBlockAt($x, $y, $z))){
						return new Position($spawn->x, $y === (int) $spawn->y ? $spawn->y : $y, $spawn->z, $this);
					}
				}else{
					++$y;
				}
			}

			$v->y = $y;
		}

		return new Position($spawn->x, $v->y, $spawn->z, $this);
	}

	/**
	 * Gets the current time
	 */
	public function getTime() : int{
		return $this->time;
	}

	/**
	 * Returns the Level name
	 */
	public function getName() : string{
		return $this->displayName;
	}

	/**
	 * Returns the Level folder name
	 */
	public function getFolderName() : string{
		return $this->folderName;
	}

	/**
	 * Sets the current time on the level
	 *
	 * @return void
	 */
	public function setTime(int $time){
		$this->time = $time;
		$this->sendTime();
	}

	/**
	 * Stops the time for the level, will not save the lock state to disk
	 *
	 * @return void
	 */
	public function stopTime(){
		$this->stopTime = true;
		$this->sendTime();
	}

	/**
	 * Start the time again, if it was stopped
	 *
	 * @return void
	 */
	public function startTime(){
		$this->stopTime = false;
		$this->sendTime();
	}

	/**
	 * Gets the level seed
	 */
	public function getSeed() : int{
		return $this->provider->getSeed();
	}

	/**
	 * Sets the seed for the level
	 *
	 * @return void
	 */
	public function setSeed(int $seed){
		$this->provider->setSeed($seed);
	}

	public function getWorldHeight() : int{
		return $this->worldHeight;
	}

	public function getDifficulty() : int{
		return $this->provider->getDifficulty();
	}

	/**
	 * @return void
	 */
	public function setDifficulty(int $difficulty){
		if($difficulty < 0 or $difficulty > 3){
			throw new \InvalidArgumentException("Invalid difficulty level $difficulty");
		}
		$this->provider->setDifficulty($difficulty);

		$this->sendDifficulty();
	}

	/**
	 * @param Player ...$targets
	 *
	 * @return void
	 */
	public function sendDifficulty(Player ...$targets){
		if(count($targets) === 0){
			$targets = $this->getPlayers();
		}

		$pk = new SetDifficultyPacket();
		$pk->difficulty = $this->getDifficulty();
		$this->server->broadcastPacket($targets, $pk);
	}

	public function populateChunk(int $x, int $z, bool $force = false) : bool{
		if(isset($this->chunkPopulationQueue[$index = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)]) or (count($this->chunkPopulationQueue) >= $this->chunkPopulationQueueSize and !$force)){
			return false;
		}
		for($xx = -1; $xx <= 1; ++$xx){
			for($zz = -1; $zz <= 1; ++$zz){
				if(isset($this->chunkPopulationLock[((($x + $xx) & 0xFFFFFFFF) << 32) | (( $z + $zz) & 0xFFFFFFFF)])){
					return false;
				}
			}
		}

		$chunk = $this->getChunk($x, $z, true);
		if(!$chunk->isPopulated()){
			Timings::$populationTimer->startTiming();

			$this->chunkPopulationQueue[$index] = true;
			for($xx = -1; $xx <= 1; ++$xx){
				for($zz = -1; $zz <= 1; ++$zz){
					$this->chunkPopulationLock[((($x + $xx) & 0xFFFFFFFF) << 32) | (( $z + $zz) & 0xFFFFFFFF)] = true;
				}
			}

			$task = new PopulationTask($this, $chunk);
			$workerId = $this->server->getAsyncPool()->selectWorker();
			if(!isset($this->generatorRegisteredWorkers[$workerId])){
				$this->registerGeneratorToWorker($workerId);
			}
			$this->server->getAsyncPool()->submitTaskToWorker($task, $workerId);

			Timings::$populationTimer->stopTiming();
			return false;
		}

		return true;
	}

	/**
	 * @return void
	 */
	public function doChunkGarbageCollection(){
		$this->timings->doChunkGC->startTiming();

		foreach($this->chunks as $index => $chunk){
			if(!isset($this->unloadQueue[$index])){
				 $X = ($index >> 32);  $Z = ($index & 0xFFFFFFFF) << 32 >> 32;
				if(!$this->isSpawnChunk($X, $Z)){
					$this->unloadChunkRequest($X, $Z, true);
				}
			}
			$chunk->collectGarbage();
		}

		$this->provider->doGarbageCollection();

		$this->timings->doChunkGC->stopTiming();
	}

	/**
	 * @return void
	 */
	public function unloadChunks(bool $force = false){
		if(count($this->unloadQueue) > 0){
			$maxUnload = 96;
			$now = microtime(true);
			foreach($this->unloadQueue as $index => $time){
				 $X = ($index >> 32);  $Z = ($index & 0xFFFFFFFF) << 32 >> 32;

				if(!$force){
					if($maxUnload <= 0){
						break;
					}elseif($time > ($now - 30)){
						continue;
					}
				}

				//If the chunk can't be unloaded, it stays on the queue
				if($this->unloadChunk($X, $Z, true)){
					unset($this->unloadQueue[$index]);
					--$maxUnload;
				}
			}
		}
	}

	public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
		$this->server->getLevelMetadata()->setMetadata($this, $metadataKey, $newMetadataValue);
	}

	public function getMetadata(string $metadataKey){
		return $this->server->getLevelMetadata()->getMetadata($this, $metadataKey);
	}

	public function hasMetadata(string $metadataKey) : bool{
		return $this->server->getLevelMetadata()->hasMetadata($this, $metadataKey);
	}

	public function removeMetadata(string $metadataKey, Plugin $owningPlugin){
		$this->server->getLevelMetadata()->removeMetadata($this, $metadataKey, $owningPlugin);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level;

use pocketmine\level\format\Chunk;

interface ChunkManager{
	/**
	 * Gets the raw block id.
	 *
	 * @return int 0-255
	 */
	public function getBlockIdAt(int $x, int $y, int $z) : int;

	/**
	 * Sets the raw block id.
	 *
	 * @param int $id 0-255
	 *
	 * @return void
	 */
	public function setBlockIdAt(int $x, int $y, int $z, int $id);

	/**
	 * Gets the raw block metadata
	 *
	 * @return int 0-15
	 */
	public function getBlockDataAt(int $x, int $y, int $z) : int;

	/**
	 * Sets the raw block metadata.
	 *
	 * @param int $data 0-15
	 *
	 * @return void
	 */
	public function setBlockDataAt(int $x, int $y, int $z, int $data);

	/**
	 * Returns the raw block light level
	 */
	public function getBlockLightAt(int $x, int $y, int $z) : int;

	/**
	 * Sets the raw block light level
	 *
	 * @return void
	 */
	public function setBlockLightAt(int $x, int $y, int $z, int $level);

	/**
	 * Returns the highest amount of sky light can reach the specified coordinates.
	 */
	public function getBlockSkyLightAt(int $x, int $y, int $z) : int;

	/**
	 * Sets the raw block sky light level.
	 *
	 * @return void
	 */
	public function setBlockSkyLightAt(int $x, int $y, int $z, int $level);

	/**
	 * @return Chunk|null
	 */
	public function getChunk(int $chunkX, int $chunkZ);

	/**
	 * @return void
	 */
	public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null);

	/**
	 * Gets the level seed
	 */
	public function getSeed() : int;

	/**
	 * Returns the height of the world
	 */
	public function getWorldHeight() : int;

	/**
	 * Returns whether the specified coordinates are within the valid world boundaries, taking world format limitations
	 * into account.
	 */
	public function isInWorld(int $x, int $y, int $z) : bool;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\metadata;

use pocketmine\plugin\Plugin;

interface Metadatable{

	/**
	 * Sets a metadata value in the implementing object's metadata store.
	 *
	 * @return void
	 */
	public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue);

	/**
	 * Returns a list of previously set metadata values from the implementing
	 * object's metadata store.
	 *
	 * @return MetadataValue[]
	 */
	public function getMetadata(string $metadataKey);

	/**
	 * Tests to see whether the implementing object contains the given
	 * metadata value in its metadata store.
	 */
	public function hasMetadata(string $metadataKey) : bool;

	/**
	 * Removes the given metadata value from the implementing object's
	 * metadata store.
	 *
	 * @return void
	 */
	public function removeMetadata(string $metadataKey, Plugin $owningPlugin);

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\lang;

use pocketmine\utils\MainLogger;
use function array_filter;
use function array_map;
use function file_exists;
use function is_dir;
use function ord;
use function parse_ini_file;
use function scandir;
use function str_replace;
use function strlen;
use function strpos;
use function strtolower;
use function substr;
use const INI_SCANNER_RAW;
use const SCANDIR_SORT_NONE;

class BaseLang{

	public const FALLBACK_LANGUAGE = "eng";

	/**
	 * @return string[]
	 * @phpstan-return array<string, string>
	 */
	public static function getLanguageList(string $path = "") : array{
		if($path === ""){
			$path = \pocketmine\PATH . "src/pocketmine/lang/locale/";
		}

		if(is_dir($path)){
			$allFiles = scandir($path, SCANDIR_SORT_NONE);

			if($allFiles !== false){
				$files = array_filter($allFiles, function(string $filename) : bool{
					return substr($filename, -4) === ".ini";
				});

				$result = [];

				foreach($files as $file){
					$strings = [];
					self::loadLang($path . $file, $strings);
					if(isset($strings["language.name"])){
						$result[substr($file, 0, -4)] = $strings["language.name"];
					}
				}

				return $result;
			}
		}

		return [];
	}

	/** @var string */
	protected $langName;

	/** @var string[] */
	protected $lang = [];
	/** @var string[] */
	protected $fallbackLang = [];

	public function __construct(string $lang, string $path = null, string $fallback = self::FALLBACK_LANGUAGE){

		$this->langName = strtolower($lang);

		if($path === null){
			$path = \pocketmine\PATH . "src/pocketmine/lang/locale/";
		}

		if(!self::loadLang($file = $path . $this->langName . ".ini", $this->lang)){
			MainLogger::getLogger()->error("Missing required language file $file");
		}
		if(!self::loadLang($file = $path . $fallback . ".ini", $this->fallbackLang)){
			MainLogger::getLogger()->error("Missing required language file $file");
		}
	}

	public function getName() : string{
		return $this->get("language.name");
	}

	public function getLang() : string{
		return $this->langName;
	}

	/**
	 * @param string[] $d reference parameter
	 *
	 * @return bool
	 */
	protected static function loadLang(string $path, array &$d){
		if(file_exists($path)){
			$d = array_map('\stripcslashes', parse_ini_file($path, false, INI_SCANNER_RAW));
			return true;
		}else{
			return false;
		}
	}

	/**
	 * @param (float|int|string)[] $params
	 */
	public function translateString(string $str, array $params = [], string $onlyPrefix = null) : string{
		$baseText = $this->get($str);
		$baseText = $this->parseTranslation(($onlyPrefix === null or strpos($str, $onlyPrefix) === 0) ? $baseText : $str, $onlyPrefix);

		foreach($params as $i => $p){
			$baseText = str_replace("{%$i}", $this->parseTranslation((string) $p), $baseText, $onlyPrefix);
		}

		return $baseText;
	}

	/**
	 * @return string
	 */
	public function translate(TextContainer $c){
		if($c instanceof TranslationContainer){
			$baseText = $this->internalGet($c->getText());
			$baseText = $this->parseTranslation($baseText ?? $c->getText());

			foreach($c->getParameters() as $i => $p){
				$baseText = str_replace("{%$i}", $this->parseTranslation($p), $baseText);
			}
		}else{
			$baseText = $this->parseTranslation($c->getText());
		}

		return $baseText;
	}

	/**
	 * @return string|null
	 */
	public function internalGet(string $id){
		if(isset($this->lang[$id])){
			return $this->lang[$id];
		}elseif(isset($this->fallbackLang[$id])){
			return $this->fallbackLang[$id];
		}

		return null;
	}

	public function get(string $id) : string{
		if(isset($this->lang[$id])){
			return $this->lang[$id];
		}elseif(isset($this->fallbackLang[$id])){
			return $this->fallbackLang[$id];
		}

		return $id;
	}

	protected function parseTranslation(string $text, string $onlyPrefix = null) : string{
		$newString = "";

		$replaceString = null;

		$len = strlen($text);
		for($i = 0; $i < $len; ++$i){
			$c = $text[$i];
			if($replaceString !== null){
				$ord = ord($c);
				if(
					($ord >= 0x30 and $ord <= 0x39) // 0-9
					or ($ord >= 0x41 and $ord <= 0x5a) // A-Z
					or ($ord >= 0x61 and $ord <= 0x7a) or // a-z
					$c === "." or $c === "-"
				){
					$replaceString .= $c;
				}else{
					if(($t = $this->internalGet(substr($replaceString, 1))) !== null and ($onlyPrefix === null or strpos($replaceString, $onlyPrefix) === 1)){
						$newString .= $t;
					}else{
						$newString .= $replaceString;
					}
					$replaceString = null;

					if($c === "%"){
						$replaceString = $c;
					}else{
						$newString .= $c;
					}
				}
			}elseif($c === "%"){
				$replaceString = $c;
			}else{
				$newString .= $c;
			}
		}

		if($replaceString !== null){
			if(($t = $this->internalGet(substr($replaceString, 1))) !== null and ($onlyPrefix === null or strpos($replaceString, $onlyPrefix) === 1)){
				$newString .= $t;
			}else{
				$newString .= $replaceString;
			}
		}

		return $newString;
	}
}
﻿; Language file compatible with Minecraft: Bedrock Edition identifiers
;
; A message doesn't need to be there to be shown correctly on the client.
; Only messages shown in PocketMine itself need to be here

language.name=English
language.selected=Selected {%0} ({%1}) as the base language

ability.flight=Flying
ability.noclip=No-clip
chat.type.achievement={%0} has just earned the achievement {%1}
chat.type.admin=[{%0}: {%1}]
chat.type.announcement=[{%0}] {%1}
chat.type.emote=* {%0} {%1}
chat.type.text=<{%0}> {%1}
commands.ban.success=Banned player {%0}
commands.ban.usage=/ban <name> [reason ...]
commands.banip.invalid=You have entered an invalid IP address or a player that is not online
commands.banip.success.players=Banned IP address {%0} belonging to {%1}
commands.banip.success=Banned IP address {%0}
commands.banip.usage=/ban-ip <address|name> [reason ...]
commands.banlist.ips=There are {%0} total banned IP addresses:
commands.banlist.players=There are {%0} total banned players:
commands.banlist.usage=/banlist [ips|players]
commands.defaultgamemode.success=The world's default game mode is now {%0}
commands.defaultgamemode.usage=/defaultgamemode <mode>
commands.deop.success=De-opped {%0}
commands.deop.usage=/deop <player>
commands.difficulty.success=Set game difficulty to {%0}
commands.difficulty.usage=/difficulty <new difficulty>
commands.effect.failure.notActive.all=Couldn't take any effects from {%0} as they do not have any
commands.effect.failure.notActive=Couldn't take {%0} from {%1} as they do not have the effect
commands.effect.notFound=There is no such mob effect with ID {%0}
commands.effect.success.removed.all=Took all effects from {%0}
commands.effect.success.removed=Took {%0} from {%1}
commands.effect.success=Given {%0} (ID {%4}) * {%1} to {%2} for {%3} seconds
commands.effect.usage=/effect <player> <effect> [seconds] [amplifier] [hideParticles] OR /effect <player> clear
commands.enchant.noItem=The target does not hold an item
commands.enchant.notFound=There is no such enchantment with ID {%0}
commands.enchant.success=Enchanting succeeded
commands.enchant.usage=/enchant <player> <enchantment ID> [level]
commands.gamemode.success.other=Set {%1}'s game mode to {%0}
commands.gamemode.success.self=Set own game mode to {%0}
commands.gamemode.usage=/gamemode <mode> [player]
commands.generic.notFound=Unknown command. Try /help for a list of commands
commands.generic.num.tooBig=The number you have entered ({%0}) is too big, it must be at most {%1}
commands.generic.num.tooSmall=The number you have entered ({%0}) is too small, it must be at least {%1}
commands.generic.permission=You do not have permission to use this command
commands.generic.player.notFound=That player cannot be found
commands.generic.usage=Usage: {%0}
commands.give.item.notFound=There is no such item with name {%0}
commands.give.success=Given {%0} * {%1} to {%2}
commands.give.tagError=Data tag parsing failed: {%0}
commands.help.header=--- Showing help page {%0} of {%1} (/help <page>) ---
commands.help.usage=/help [page|command name]
commands.kick.success.reason=Kicked {%0} from the game: '{%1}'
commands.kick.success=Kicked {%0} from the game
commands.kick.usage=/kick <player> [reason ...]
commands.kill.successful=Killed {%0}
commands.me.usage=/me <action ...>
commands.message.sameTarget=You can't send a private message to yourself!
commands.message.usage=/tell <player> <private message ...>
commands.op.success=Opped {%0}
commands.op.usage=/op <player>
commands.particle.notFound=Unknown effect name {%0}
commands.particle.success=Playing effect {%0} for {%1} times
commands.players.list=There are {%0}/{%1} players online:
commands.players.usage=/list
commands.save-off.usage=/save-off
commands.save-on.usage=/save-on
commands.save.disabled=Turned off world auto-saving
commands.save.enabled=Turned on world auto-saving
commands.save.start=Saving...
commands.save.success=Saved the world
commands.save.usage=/save-all
commands.say.usage=/say <message ...>
commands.seed.success=Seed: {%0}
commands.seed.usage=/seed
commands.setworldspawn.success=Set the world spawn point to ({%0}, {%1}, {%2})
commands.setworldspawn.usage=/setworldspawn [<x> <y> <z>]
commands.spawnpoint.success=Set {%0}'s spawn point to ({%1}, {%2}, {%3})
commands.spawnpoint.usage=/spawnpoint [player] [<x> <y> <z>]
commands.stop.start=Stopping the server
commands.stop.usage=/stop
commands.time.added=Added {%0} to the time
commands.time.query=Time is {%0}
commands.time.set=Set the time to {%0}
commands.title.success=Title command successfully executed
commands.title.usage=/title <player> <clear|reset|title|subtitle|actionbar|times> ...
commands.tp.success.coordinates=Teleported {%0} to {%1}, {%2}, {%3}
commands.tp.success=Teleported {%0} to {%1}
commands.tp.usage=/tp [target player] <destination player> OR /tp [target player] <x> <y> <z> [<y-rot> <x-rot>]
commands.unban.success=Unbanned player {%0}
commands.unban.usage=/pardon <name>
commands.unbanip.invalid=You have entered an invalid IP address
commands.unbanip.success=Unbanned IP address {%0}
commands.unbanip.usage=/pardon-ip <address>
commands.whitelist.add.success=Added {%0} to the whitelist
commands.whitelist.add.usage=/whitelist add <player>
commands.whitelist.disabled=Turned off the whitelist
commands.whitelist.enabled=Turned on the whitelist
commands.whitelist.list=There are {%0} (out of {%1} seen) whitelisted players:
commands.whitelist.reloaded=Reloaded the whitelist
commands.whitelist.remove.success=Removed {%0} from the whitelist
commands.whitelist.remove.usage=/whitelist remove <player>
commands.whitelist.usage=/whitelist <on|off|list|add|remove|reload>
death.attack.arrow.item={%0} was shot by {%1} using {%2}
death.attack.arrow={%0} was shot by {%1}
death.attack.cactus={%0} was pricked to death
death.attack.drown={%0} drowned
death.attack.explosion.player={%0} was blown up by {%1}
death.attack.explosion={%0} blew up
death.attack.fall={%0} hit the ground too hard
death.attack.generic={%0} died
death.attack.inFire={%0} went up in flames
death.attack.inWall={%0} suffocated in a wall
death.attack.lava={%0} tried to swim in lava
death.attack.magic={%0} was killed by magic
death.attack.mob={%0} was slain by {%1}
death.attack.onFire={%0} burned to death
death.attack.outOfWorld={%0} fell out of the world
death.attack.player.item={%0} was slain by {%1} using {%2}
death.attack.player={%0} was slain by {%1}
death.attack.wither={%0} withered away
death.fell.accident.generic={%0} fell from a high place
disconnectionScreen.invalidName=Invalid name!
disconnectionScreen.invalidSkin=Invalid skin!
disconnectionScreen.noReason=Disconnected from server
disconnectionScreen.notAuthenticated=You need to authenticate to Xbox Live.
disconnectionScreen.outdatedClient=Outdated client!
disconnectionScreen.outdatedServer=Outdated server!
disconnectionScreen.resourcePack=Encountered a problem while downloading or applying resource pack.
disconnectionScreen.serverFull=Server is full!
gameMode.adventure=Adventure Mode
gameMode.changed=Your game mode has been updated
gameMode.creative=Creative Mode
gameMode.spectator=Spectator Mode
gameMode.survival=Survival Mode
kick.admin.reason=%kick.admin Reason: {%0}
kick.admin=Kicked by admin.
kick.reason.cheat={%0} is not enabled on this server
multiplayer.player.joined={%0} joined the game
multiplayer.player.left={%0} left the game
pocketmine.disconnect.incompatibleProtocol=Incompatible protocol version ({%0})
pocketmine.disconnect.invalidSession.badSignature=Failed to verify keychain link signature.
pocketmine.disconnect.invalidSession.missingKey=Previous keychain link does not have expected public key.
pocketmine.disconnect.invalidSession.tooEarly=Token can't be used yet - check the server's date/time matches the client.
pocketmine.disconnect.invalidSession.tooLate=Token has expired - check the server's date/time matches the client.
pocketmine.disconnect.invalidSession=Invalid session. Reason: {%0}
potion.absorption=Absorption
potion.blindness=Blindness
potion.conduitPower=Conduit Power
potion.confusion=Nausea
potion.damageBoost=Strength
potion.digSlowDown=Mining Fatigue
potion.digSpeed=Haste
potion.fireResistance=Fire Resistance
potion.harm=Instant Damage
potion.heal=Instant Health
potion.healthBoost=Health Boost
potion.hunger=Hunger
potion.invisibility=Invisibility
potion.jump=Jump Boost
potion.levitation=Levitation
potion.moveSlowdown=Slowness
potion.moveSpeed=Speed
potion.nightVision=Night Vision
potion.poison=Poison
potion.regeneration=Regeneration
potion.resistance=Resistance
potion.saturation=Saturation
potion.waterBreathing=Water Breathing
potion.weakness=Weakness
potion.wither=Wither
tile.bed.noSleep=You can only sleep at night
tile.bed.occupied=This bed is occupied
tile.bed.tooFar=Bed is too far away

; -------------------- PocketMine language strings, only for console --------------------
pocketmine.command.alias.illegal=Could not register alias '{%0}' because it contains illegal characters
pocketmine.command.alias.notFound=Could not register alias '{%0}' because it contains commands that do not exist: {%1}
pocketmine.command.alias.recursive=Could not register alias '{%0}' because it contains recursive commands: {%1}
pocketmine.command.ban.ip.description=Prevents the specified IP address from using this server
pocketmine.command.ban.player.description=Prevents the specified player from using this server
pocketmine.command.banlist.description=View all players banned from this server
pocketmine.command.defaultgamemode.description=Set the default gamemode
pocketmine.command.deop.description=Takes the specified player's operator status
pocketmine.command.difficulty.description=Sets the game difficulty
pocketmine.command.effect.description=Adds/Removes effects on players
pocketmine.command.enchant.description=Adds enchantments on items
pocketmine.command.exception=Unhandled exception executing command '{%0}' in {%1}: {%2}
pocketmine.command.gamemode.description=Changes the player to a specific game mode
pocketmine.command.gc.description=Fires garbage collection tasks
pocketmine.command.gc.usage=/gc
pocketmine.command.give.description=Gives the specified player a certain amount of items
pocketmine.command.give.usage=/give <player> <item[:damage]> [amount] [tags...]
pocketmine.command.help.description=Shows the help menu
pocketmine.command.kick.description=Removes the specified player from the server
pocketmine.command.kill.description=Commit suicide or kill other players
pocketmine.command.kill.usage=/kill [player]
pocketmine.command.list.description=Lists all online players
pocketmine.command.me.description=Performs the specified action in chat
pocketmine.command.op.description=Gives the specified player operator status
pocketmine.command.particle.description=Adds particles to a world
pocketmine.command.particle.usage=/particle <name> <x> <y> <z> <xd> <yd> <zd> [count] [data]
pocketmine.command.plugins.description=Gets a list of plugins running on the server
pocketmine.command.plugins.success=Plugins ({%0}): {%1}
pocketmine.command.plugins.usage=/plugins
pocketmine.command.reload.description=Reloads the server configuration and plugins
pocketmine.command.reload.reloaded=Reload complete.
pocketmine.command.reload.reloading=Reloading server...
pocketmine.command.reload.usage=/reload
pocketmine.command.save.description=Saves the server to disk
pocketmine.command.saveoff.description=Disables server autosaving
pocketmine.command.saveon.description=Enables server autosaving
pocketmine.command.say.description=Broadcasts the given message as the sender
pocketmine.command.seed.description=Shows the world seed
pocketmine.command.setworldspawn.description=Sets a worlds's spawn point. If no coordinates are specified, the player's coordinates will be used.
pocketmine.command.spawnpoint.description=Sets a player's spawn point
pocketmine.command.status.description=Reads back the server's performance.
pocketmine.command.status.usage=/status
pocketmine.command.stop.description=Stops the server
pocketmine.command.tell.description=Sends a private message to the given player
pocketmine.command.time.description=Changes the time on each world
pocketmine.command.time.usage=/time <set|add> <value> OR /time <start|stop|query>
pocketmine.command.timings.description=Records timings to see performance of the server.
pocketmine.command.timings.disable=Disabled Timings
pocketmine.command.timings.enable=Enabled Timings & Reset
pocketmine.command.timings.pasteError=An error happened while pasting the report
pocketmine.command.timings.reset=Timings reset
pocketmine.command.timings.timingsDisabled=Please enable timings by typing /timings on
pocketmine.command.timings.timingsRead=You can read the results at {%0}
pocketmine.command.timings.timingsUpload=Timings uploaded to {%0}
pocketmine.command.timings.timingsWrite=Timings written to {%0}
pocketmine.command.timings.usage=/timings <reset|report|on|off|paste>
pocketmine.command.title.description=Controls screen titles
pocketmine.command.tp.description=Teleports the given player (or yourself) to another player or coordinates
pocketmine.command.transferserver.description=Transfer yourself to another server
pocketmine.command.transferserver.usage=/transferserver <server> [port]
pocketmine.command.unban.ip.description=Allows the specified IP address to use this server
pocketmine.command.unban.player.description=Allows the specified player to use this server
pocketmine.command.version.description=Gets the version of this server including any plugins in use
pocketmine.command.version.noSuchPlugin=This server is not running any plugin by that name. Use /plugins to get a list of plugins.
pocketmine.command.version.usage=/version [plugin name]
pocketmine.command.whitelist.description=Manages the list of players allowed to use this server
pocketmine.crash.archive=The crash dump has been automatically submitted to the Crash Archive. You can view it on {%0} or use the ID #{%1}.
pocketmine.crash.create=An unrecoverable error has occurred and the server has crashed. Creating a crash dump
pocketmine.crash.error=Could not create crash dump: {%0}
pocketmine.crash.submit=Please upload the "{%0}" file to the Crash Archive and submit the link to the Bug Reporting page. Give as much info as you can.
pocketmine.data.playerCorrupted=Corrupted data found for "{%0}", creating new profile
pocketmine.data.playerNotFound=Player data not found for "{%0}", creating new profile
pocketmine.data.playerOld=Old Player data found for "{%0}", upgrading profile
pocketmine.data.saveError=Could not save player "{%0}": {%1}
pocketmine.debug.enable=LevelDB support enabled
pocketmine.level.ambiguousFormat=Cannot identify correct format - matched multiple formats ({%0})
pocketmine.level.backgroundGeneration=Spawn terrain for world "{%0}" is being generated in the background
pocketmine.level.badDefaultFormat=Selected default world format "{%0}" does not exist, using default
pocketmine.level.defaultError=No default world has been loaded
pocketmine.level.generationError=Could not generate world "{%0}": {%1}
pocketmine.level.loadError=Could not load world "{%0}": {%1}
pocketmine.level.notFound=World "{%0}" not found
pocketmine.level.preparing=Preparing world "{%0}"
pocketmine.level.unknownFormat=Unknown format
pocketmine.level.unloading=Unloading world "{%0}"
pocketmine.player.invalidEntity={%0} tried to attack an invalid entity
pocketmine.player.invalidMove={%0} moved wrongly!
pocketmine.player.logIn={%0}[/{%1}:{%2}] logged in with entity id {%3} at ({%4}, {%5}, {%6}, {%7})
pocketmine.player.logOut={%0}[/{%1}:{%2}] logged out due to {%3}
pocketmine.plugin.aliasError=Could not load alias {%0} for plugin {%1}
pocketmine.plugin.circularDependency=Circular dependency detected
pocketmine.plugin.commandError=Could not load command {%0} for plugin {%1}
pocketmine.plugin.deprecatedEvent=Plugin '{%0}' has registered a listener for '{%1}' on method '{%2}', but the event is Deprecated.
pocketmine.plugin.disable=Disabling {%0}
pocketmine.plugin.duplicateError=Could not load plugin '{%0}': plugin exists
pocketmine.plugin.enable=Enabling {%0}
pocketmine.plugin.fileError=Could not load '{%0}' in folder '{%1}': {%2}
pocketmine.plugin.genericLoadError=Could not load plugin '{%0}'
pocketmine.plugin.incompatibleAPI=Incompatible API version (plugin requires one of: {%0})
pocketmine.plugin.incompatibleProtocol=Incompatible network protocol version (plugin requires one of: {%0})
pocketmine.plugin.load=Loading {%0}
pocketmine.plugin.loadError=Could not load plugin '{%0}': {%1}
pocketmine.plugin.restrictedName=Restricted name
pocketmine.plugin.spacesDiscouraged=Plugin '{%0}' uses spaces in its name, this is discouraged
pocketmine.plugin.unknownDependency=Unknown dependency: {%0}
pocketmine.save.start=Saving server data...
pocketmine.save.success=Save completed in {%0} seconds
pocketmine.server.auth.disabled=Online mode is disabled. The server will not verify that players are authenticated to Xbox Live.
pocketmine.server.auth.enabled=Online mode is enabled. The server will verify that players are authenticated to Xbox Live.
pocketmine.server.authProperty.disabled=To enable authentication, set "xbox-auth" to "true" in server.properties.
pocketmine.server.authProperty.enabled=To disable authentication, set "xbox-auth" to "false" in server.properties.
pocketmine.server.authWarning=While this makes it possible to connect without internet access, it also allows hackers to connect with any username they choose.
pocketmine.server.defaultGameMode=Default game type: {%0}
pocketmine.server.devBuild.error1=You are running a {%0} DEVELOPMENT build, but your configuration does not permit running development builds.
pocketmine.server.devBuild.error2=Development builds might have unexpected bugs, crash, break your plugins, corrupt all your data and more.
pocketmine.server.devBuild.error3=Unless you're a developer and know what you're doing, please AVOID using development builds.
pocketmine.server.devBuild.error4=To use this build anyway, set "{%0}" to "true" in your pocketmine.yml.
pocketmine.server.devBuild.error5=To download a stable build instead, visit {%0}.
pocketmine.server.devBuild.warning1=You are running a {%0} DEVELOPMENT build.
pocketmine.server.devBuild.warning2=The API for this version may not be finalized. Plugins which run on this build may not work on other builds with the same API version.
pocketmine.server.devBuild.warning3=The build may have bugs, crash, corrupt your data, or break your plugins.
pocketmine.server.info.extended=This server is running {%0} {%1} for Minecraft: Bedrock Edition {%2} (protocol version {%3})
pocketmine.server.donate=If you find this project useful, please consider donating to support development: {%0}
pocketmine.server.info=This server is running {%0} version {%1}
pocketmine.server.license={%0} is distributed under the LGPL License
pocketmine.server.networkError=[Network] Stopped interface {%0} due to {%1}
pocketmine.server.networkStart=Opening server on {%0}:{%1}
pocketmine.server.query.info=Setting query port to {%0}
pocketmine.server.query.running=Query running on {%0}:{%1}
pocketmine.server.query.start=Starting GS4 status listener
pocketmine.server.start=Starting Minecraft: Bedrock Edition server version {%0}
pocketmine.server.startFinished=Done ({%0}s)! For help, type "help" or "?"
pocketmine.server.tickOverload=Can't keep up! Is the server overloaded?

; -------------------- PocketMine setup-wizard strings, only for console --------------------

accept_license = Do you accept the License?
default_gamemode = Default Game mode
default_values_info = If you don't want to change the default value, just press Enter.
gamemode_info = Choose between Creative (1) or Survival (0)
invalid_port = Invalid server port
ip_confirm = Be sure to check it, if you have to forward and you skip that, no external players will be able to join. [Press Enter]
ip_get = Getting your external IP and internal IP
ip_warning = Your external IP is {%EXTERNAL_IP}. You may have to port-forward to your internal IP {%INTERNAL_IP}
language_has_been_selected = English has been correctly selected.
max_players = Max. online players
name_your_server = Give a name to your server
op_info = An OP is the player admin of the server. OPs can run more commands than normal players
op_warning = You will be able to add an OP user later using /op <player>
op_who = OP player name (example, your game name)
pocketmine_plugins = Check the Plugin Repository to add new features, minigames, or advanced protection to your server
pocketmine_will_start = {%0} will now start. Type /help to view the list of available commands.
port_warning = Do not change the default port value if this is your first server.
query_disable = Do you want to disable Query?
query_warning1 = Query is a protocol used by different tools to get information of your server and players logged in.
query_warning2 = If you disable it, you won't be able to use server lists.
rcon_enable = Do you want to enable RCON?
rcon_info = RCON is a protocol to remote connect with the server console using a password.
rcon_password = RCON password (you can change it later)
server_port = Server port
server_properties = You can edit them later on the server.properties file.
setting_up_server_now = You are going to set up your server now.
skip_installer = Do you want to skip the set-up wizard?
spawn_protection = Enable spawn protection?
spawn_protection_info = The spawn protection disallows placing/breaking blocks in the spawn zone except for OPs
welcome_to_pocketmine = Welcome to {%0}!\nBefore starting setting up your new server you have to accept the license.\n{%0} is licensed under the LGPL License,\nthat you can read opening the LICENSE file on this folder.
whitelist_enable = Do you want to enable the white-list?
whitelist_info = The white-list only allows players in it to join.
whitelist_warning = You will have to add the players to the white-list
you_have_finished = You have finished the set-up wizard correctly
you_have_to_accept_the_license = You have to accept the LGPL license to continue using {%0}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine;

use pocketmine\event\server\LowMemoryEvent;
use pocketmine\scheduler\DumpWorkerMemoryTask;
use pocketmine\scheduler\GarbageCollectionTask;
use pocketmine\timings\Timings;
use pocketmine\utils\Utils;
use function arsort;
use function count;
use function fclose;
use function file_exists;
use function file_put_contents;
use function fopen;
use function fwrite;
use function gc_collect_cycles;
use function gc_disable;
use function gc_enable;
use function get_class;
use function get_declared_classes;
use function implode;
use function ini_get;
use function ini_set;
use function is_array;
use function is_object;
use function is_resource;
use function is_string;
use function json_encode;
use function min;
use function mkdir;
use function preg_match;
use function print_r;
use function round;
use function spl_object_hash;
use function sprintf;
use function strlen;
use function strtoupper;
use function substr;
use const JSON_PRETTY_PRINT;
use const JSON_UNESCAPED_SLASHES;
use const SORT_NUMERIC;

class MemoryManager{

	/** @var Server */
	private $server;

	/** @var int */
	private $memoryLimit;
	/** @var int */
	private $globalMemoryLimit;
	/** @var int */
	private $checkRate;
	/** @var int */
	private $checkTicker = 0;
	/** @var bool */
	private $lowMemory = false;

	/** @var bool */
	private $continuousTrigger = true;
	/** @var int */
	private $continuousTriggerRate;
	/** @var int */
	private $continuousTriggerCount = 0;
	/** @var int */
	private $continuousTriggerTicker = 0;

	/** @var int */
	private $garbageCollectionPeriod;
	/** @var int */
	private $garbageCollectionTicker = 0;
	/** @var bool */
	private $garbageCollectionTrigger;
	/** @var bool */
	private $garbageCollectionAsync;

	/** @var int */
	private $lowMemChunkRadiusOverride;
	/** @var bool */
	private $lowMemChunkGC;

	/** @var bool */
	private $lowMemDisableChunkCache;
	/** @var bool */
	private $lowMemClearWorldCache;

	/** @var bool */
	private $dumpWorkers = true;

	public function __construct(Server $server){
		$this->server = $server;

		$this->init();
	}

	private function init() : void{
		$this->memoryLimit = ((int) $this->server->getProperty("memory.main-limit", 0)) * 1024 * 1024;

		$defaultMemory = 1024;

		if(preg_match("/([0-9]+)([KMGkmg])/", $this->server->getConfigString("memory-limit", ""), $matches) > 0){
			$m = (int) $matches[1];
			if($m <= 0){
				$defaultMemory = 0;
			}else{
				switch(strtoupper($matches[2])){
					case "K":
						$defaultMemory = $m / 1024;
						break;
					case "M":
						$defaultMemory = $m;
						break;
					case "G":
						$defaultMemory = $m * 1024;
						break;
					default:
						$defaultMemory = $m;
						break;
				}
			}
		}

		$hardLimit = ((int) $this->server->getProperty("memory.main-hard-limit", $defaultMemory));

		if($hardLimit <= 0){
			ini_set("memory_limit", '-1');
		}else{
			ini_set("memory_limit", $hardLimit . "M");
		}

		$this->globalMemoryLimit = ((int) $this->server->getProperty("memory.global-limit", 0)) * 1024 * 1024;
		$this->checkRate = (int) $this->server->getProperty("memory.check-rate", 20);
		$this->continuousTrigger = (bool) $this->server->getProperty("memory.continuous-trigger", true);
		$this->continuousTriggerRate = (int) $this->server->getProperty("memory.continuous-trigger-rate", 30);

		$this->garbageCollectionPeriod = (int) $this->server->getProperty("memory.garbage-collection.period", 36000);
		$this->garbageCollectionTrigger = (bool) $this->server->getProperty("memory.garbage-collection.low-memory-trigger", true);
		$this->garbageCollectionAsync = (bool) $this->server->getProperty("memory.garbage-collection.collect-async-worker", true);

		$this->lowMemChunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
		$this->lowMemChunkGC = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);

		$this->lowMemDisableChunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
		$this->lowMemClearWorldCache = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);

		$this->dumpWorkers = (bool) $this->server->getProperty("memory.memory-dump.dump-async-worker", true);
		gc_enable();
	}

	public function isLowMemory() : bool{
		return $this->lowMemory;
	}

	public function canUseChunkCache() : bool{
		return !$this->lowMemory or !$this->lowMemDisableChunkCache;
	}

	/**
	 * Returns the allowed chunk radius based on the current memory usage.
	 */
	public function getViewDistance(int $distance) : int{
		return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? min($this->lowMemChunkRadiusOverride, $distance) : $distance;
	}

	/**
	 * Triggers garbage collection and cache cleanup to try and free memory.
	 *
	 * @return void
	 */
	public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0){
		$this->server->getLogger()->debug(sprintf("[Memory Manager] %sLow memory triggered, limit %gMB, using %gMB",
			$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
		if($this->lowMemClearWorldCache){
			foreach($this->server->getLevels() as $level){
				$level->clearCache(true);
			}
		}

		if($this->lowMemChunkGC){
			foreach($this->server->getLevels() as $level){
				$level->doChunkGarbageCollection();
			}
		}

		$ev = new LowMemoryEvent($memory, $limit, $global, $triggerCount);
		$ev->call();

		$cycles = 0;
		if($this->garbageCollectionTrigger){
			$cycles = $this->triggerGarbageCollector();
		}

		$this->server->getLogger()->debug(sprintf("[Memory Manager] Freed %gMB, $cycles cycles", round(($ev->getMemoryFreed() / 1024) / 1024, 2)));
	}

	/**
	 * Called every tick to update the memory manager state.
	 *
	 * @return void
	 */
	public function check(){
		Timings::$memoryManagerTimer->startTiming();

		if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){
			$this->checkTicker = 0;
			$memory = Utils::getMemoryUsage(true);
			$trigger = false;
			if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){
				$trigger = 0;
			}elseif($this->globalMemoryLimit > 0 and $memory[1] > $this->globalMemoryLimit){
				$trigger = 1;
			}

			if($trigger !== false){
				if($this->lowMemory and $this->continuousTrigger){
					if(++$this->continuousTriggerTicker >= $this->continuousTriggerRate){
						$this->continuousTriggerTicker = 0;
						$this->trigger($memory[$trigger], $this->memoryLimit, $trigger > 0, ++$this->continuousTriggerCount);
					}
				}else{
					$this->lowMemory = true;
					$this->continuousTriggerCount = 0;
					$this->trigger($memory[$trigger], $this->memoryLimit, $trigger > 0);
				}
			}else{
				$this->lowMemory = false;
			}
		}

		if($this->garbageCollectionPeriod > 0 and ++$this->garbageCollectionTicker >= $this->garbageCollectionPeriod){
			$this->garbageCollectionTicker = 0;
			$this->triggerGarbageCollector();
		}

		Timings::$memoryManagerTimer->stopTiming();
	}

	public function triggerGarbageCollector() : int{
		Timings::$garbageCollectorTimer->startTiming();

		if($this->garbageCollectionAsync){
			$pool = $this->server->getAsyncPool();
			if(($w = $pool->shutdownUnusedWorkers()) > 0){
				$this->server->getLogger()->debug("Shut down $w idle async pool workers");
			}
			foreach($pool->getRunningWorkers() as $i){
				$pool->submitTaskToWorker(new GarbageCollectionTask(), $i);
			}
		}

		$cycles = gc_collect_cycles();

		Timings::$garbageCollectorTimer->stopTiming();

		return $cycles;
	}

	/**
	 * Dumps the server memory into the specified output folder.
	 *
	 * @return void
	 */
	public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
		$this->server->getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
		self::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize, $this->server->getLogger());

		if($this->dumpWorkers){
			$pool = $this->server->getAsyncPool();
			foreach($pool->getRunningWorkers() as $i){
				$pool->submitTaskToWorker(new DumpWorkerMemoryTask($outputFolder, $maxNesting, $maxStringSize), $i);
			}
		}
	}

	/**
	 * Static memory dumper accessible from any thread.
	 *
	 * @param mixed   $startingObject
	 *
	 * @return void
	 * @throws \ReflectionException
	 */
	public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger){
		$hardLimit = ini_get('memory_limit');
		ini_set('memory_limit', '-1');
		gc_disable();

		if(!file_exists($outputFolder)){
			mkdir($outputFolder, 0777, true);
		}

		$obData = fopen($outputFolder . "/objects.js", "wb+");

		$data = [];

		$objects = [];

		$refCounts = [];

		$instanceCounts = [];

		$staticProperties = [];
		$staticCount = 0;

		foreach(get_declared_classes() as $className){
			$reflection = new \ReflectionClass($className);
			$staticProperties[$className] = [];
			foreach($reflection->getProperties() as $property){
				if(!$property->isStatic() or $property->getDeclaringClass()->getName() !== $className){
					continue;
				}

				if(!$property->isPublic()){
					$property->setAccessible(true);
				}

				$staticCount++;
				$staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
			}

			if(count($staticProperties[$className]) === 0){
				unset($staticProperties[$className]);
			}
		}

		file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
		$logger->info("[Dump] Wrote $staticCount static properties");

		if(isset($GLOBALS)){ //This might be null if we're on a different thread
			$globalVariables = [];
			$globalCount = 0;

			$ignoredGlobals = [
				'GLOBALS' => true,
				'_SERVER' => true,
				'_REQUEST' => true,
				'_POST' => true,
				'_GET' => true,
				'_FILES' => true,
				'_ENV' => true,
				'_COOKIE' => true,
				'_SESSION' => true
			];

			foreach($GLOBALS as $varName => $value){
				if(isset($ignoredGlobals[$varName])){
					continue;
				}

				$globalCount++;
				$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
			}

			file_put_contents($outputFolder . "/globalVariables.js", json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
			$logger->info("[Dump] Wrote $globalCount global variables");
		}

		$data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);

		do{
			$continue = false;
			foreach($objects as $hash => $object){
				if(!is_object($object)){
					continue;
				}
				$continue = true;

				$className = get_class($object);
				if(!isset($instanceCounts[$className])){
					$instanceCounts[$className] = 1;
				}else{
					$instanceCounts[$className]++;
				}

				$objects[$hash] = true;

				$reflection = new \ReflectionObject($object);

				$info = [
					"information" => "$hash@$className",
					"properties" => []
				];

				if($reflection->getParentClass()){
					$info["parent"] = $reflection->getParentClass()->getName();
				}

				if(count($reflection->getInterfaceNames()) > 0){
					$info["implements"] = implode(", ", $reflection->getInterfaceNames());
				}

				for($original = $reflection; $reflection !== false; $reflection = $reflection->getParentClass()){
					foreach($reflection->getProperties() as $property){
						if($property->isStatic()){
							continue;
						}

						$name = $property->getName();
						if($reflection !== $original and !$property->isPublic()){
							$name = $reflection->getName() . ":" . $name;
						}
						if(!$property->isPublic()){
							$property->setAccessible(true);
						}

						$info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
					}
				}

				fwrite($obData, "$hash@$className: " . json_encode($info, JSON_UNESCAPED_SLASHES) . "\n");
			}

		}while($continue);

		$logger->info("[Dump] Wrote " . count($objects) . " objects");

		fclose($obData);

		file_put_contents($outputFolder . "/serverEntry.js", json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
		file_put_contents($outputFolder . "/referenceCounts.js", json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));

		arsort($instanceCounts, SORT_NUMERIC);
		file_put_contents($outputFolder . "/instanceCounts.js", json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));

		$logger->info("[Dump] Finished!");

		ini_set('memory_limit', $hardLimit);
		gc_enable();
	}

	/**
	 * @param mixed    $from
	 * @param object[] $objects reference parameter
	 * @param int[]    $refCounts reference parameter
	 *
	 * @return mixed
	 */
	private static function continueDump($from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
		if($maxNesting <= 0){
			return "(error) NESTING LIMIT REACHED";
		}

		--$maxNesting;

		if(is_object($from)){
			if(!isset($objects[$hash = spl_object_hash($from)])){
				$objects[$hash] = $from;
				$refCounts[$hash] = 0;
			}

			++$refCounts[$hash];

			$data = "(object) $hash@" . get_class($from);
		}elseif(is_array($from)){
			if($recursion >= 5){
				return "(error) ARRAY RECURSION LIMIT REACHED";
			}
			$data = [];
			foreach($from as $key => $value){
				$data[$key] = self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
			}
		}elseif(is_string($from)){
			$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
		}elseif(is_resource($from)){
			$data = "(resource) " . print_r($from, true);
		}else{
			$data = $from;
		}

		return $data;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

/**
 * Version numbers and packet IDs for the current Minecraft PE protocol
 */
interface ProtocolInfo{

	/**
	 * NOTE TO DEVELOPERS
	 * Do not waste your time or ours submitting pull requests changing game and/or protocol version numbers.
	 * Pull requests changing game and/or protocol version numbers will be closed.
	 *
	 * This file is generated automatically, do not edit it manually.
	 */

	/**
	 * Actual Minecraft: PE protocol version
	 */
	public const CURRENT_PROTOCOL = 389;
	/**
	 * Current Minecraft PE version reported by the server. This is usually the earliest currently supported version.
	 */
	public const MINECRAFT_VERSION = 'v1.14.0';
	/**
	 * Version number sent to clients in ping responses.
	 */
	public const MINECRAFT_VERSION_NETWORK = '1.14.0';

	public const LOGIN_PACKET = 0x01;
	public const PLAY_STATUS_PACKET = 0x02;
	public const SERVER_TO_CLIENT_HANDSHAKE_PACKET = 0x03;
	public const CLIENT_TO_SERVER_HANDSHAKE_PACKET = 0x04;
	public const DISCONNECT_PACKET = 0x05;
	public const RESOURCE_PACKS_INFO_PACKET = 0x06;
	public const RESOURCE_PACK_STACK_PACKET = 0x07;
	public const RESOURCE_PACK_CLIENT_RESPONSE_PACKET = 0x08;
	public const TEXT_PACKET = 0x09;
	public const SET_TIME_PACKET = 0x0a;
	public const START_GAME_PACKET = 0x0b;
	public const ADD_PLAYER_PACKET = 0x0c;
	public const ADD_ACTOR_PACKET = 0x0d;
	public const REMOVE_ACTOR_PACKET = 0x0e;
	public const ADD_ITEM_ACTOR_PACKET = 0x0f;

	public const TAKE_ITEM_ACTOR_PACKET = 0x11;
	public const MOVE_ACTOR_ABSOLUTE_PACKET = 0x12;
	public const MOVE_PLAYER_PACKET = 0x13;
	public const RIDER_JUMP_PACKET = 0x14;
	public const UPDATE_BLOCK_PACKET = 0x15;
	public const ADD_PAINTING_PACKET = 0x16;
	public const TICK_SYNC_PACKET = 0x17;
	public const LEVEL_SOUND_EVENT_PACKET_V1 = 0x18;
	public const LEVEL_EVENT_PACKET = 0x19;
	public const BLOCK_EVENT_PACKET = 0x1a;
	public const ACTOR_EVENT_PACKET = 0x1b;
	public const MOB_EFFECT_PACKET = 0x1c;
	public const UPDATE_ATTRIBUTES_PACKET = 0x1d;
	public const INVENTORY_TRANSACTION_PACKET = 0x1e;
	public const MOB_EQUIPMENT_PACKET = 0x1f;
	public const MOB_ARMOR_EQUIPMENT_PACKET = 0x20;
	public const INTERACT_PACKET = 0x21;
	public const BLOCK_PICK_REQUEST_PACKET = 0x22;
	public const ACTOR_PICK_REQUEST_PACKET = 0x23;
	public const PLAYER_ACTION_PACKET = 0x24;
	public const ACTOR_FALL_PACKET = 0x25;
	public const HURT_ARMOR_PACKET = 0x26;
	public const SET_ACTOR_DATA_PACKET = 0x27;
	public const SET_ACTOR_MOTION_PACKET = 0x28;
	public const SET_ACTOR_LINK_PACKET = 0x29;
	public const SET_HEALTH_PACKET = 0x2a;
	public const SET_SPAWN_POSITION_PACKET = 0x2b;
	public const ANIMATE_PACKET = 0x2c;
	public const RESPAWN_PACKET = 0x2d;
	public const CONTAINER_OPEN_PACKET = 0x2e;
	public const CONTAINER_CLOSE_PACKET = 0x2f;
	public const PLAYER_HOTBAR_PACKET = 0x30;
	public const INVENTORY_CONTENT_PACKET = 0x31;
	public const INVENTORY_SLOT_PACKET = 0x32;
	public const CONTAINER_SET_DATA_PACKET = 0x33;
	public const CRAFTING_DATA_PACKET = 0x34;
	public const CRAFTING_EVENT_PACKET = 0x35;
	public const GUI_DATA_PICK_ITEM_PACKET = 0x36;
	public const ADVENTURE_SETTINGS_PACKET = 0x37;
	public const BLOCK_ACTOR_DATA_PACKET = 0x38;
	public const PLAYER_INPUT_PACKET = 0x39;
	public const LEVEL_CHUNK_PACKET = 0x3a;
	public const SET_COMMANDS_ENABLED_PACKET = 0x3b;
	public const SET_DIFFICULTY_PACKET = 0x3c;
	public const CHANGE_DIMENSION_PACKET = 0x3d;
	public const SET_PLAYER_GAME_TYPE_PACKET = 0x3e;
	public const PLAYER_LIST_PACKET = 0x3f;
	public const SIMPLE_EVENT_PACKET = 0x40;
	public const EVENT_PACKET = 0x41;
	public const SPAWN_EXPERIENCE_ORB_PACKET = 0x42;
	public const CLIENTBOUND_MAP_ITEM_DATA_PACKET = 0x43;
	public const MAP_INFO_REQUEST_PACKET = 0x44;
	public const REQUEST_CHUNK_RADIUS_PACKET = 0x45;
	public const CHUNK_RADIUS_UPDATED_PACKET = 0x46;
	public const ITEM_FRAME_DROP_ITEM_PACKET = 0x47;
	public const GAME_RULES_CHANGED_PACKET = 0x48;
	public const CAMERA_PACKET = 0x49;
	public const BOSS_EVENT_PACKET = 0x4a;
	public const SHOW_CREDITS_PACKET = 0x4b;
	public const AVAILABLE_COMMANDS_PACKET = 0x4c;
	public const COMMAND_REQUEST_PACKET = 0x4d;
	public const COMMAND_BLOCK_UPDATE_PACKET = 0x4e;
	public const COMMAND_OUTPUT_PACKET = 0x4f;
	public const UPDATE_TRADE_PACKET = 0x50;
	public const UPDATE_EQUIP_PACKET = 0x51;
	public const RESOURCE_PACK_DATA_INFO_PACKET = 0x52;
	public const RESOURCE_PACK_CHUNK_DATA_PACKET = 0x53;
	public const RESOURCE_PACK_CHUNK_REQUEST_PACKET = 0x54;
	public const TRANSFER_PACKET = 0x55;
	public const PLAY_SOUND_PACKET = 0x56;
	public const STOP_SOUND_PACKET = 0x57;
	public const SET_TITLE_PACKET = 0x58;
	public const ADD_BEHAVIOR_TREE_PACKET = 0x59;
	public const STRUCTURE_BLOCK_UPDATE_PACKET = 0x5a;
	public const SHOW_STORE_OFFER_PACKET = 0x5b;
	public const PURCHASE_RECEIPT_PACKET = 0x5c;
	public const PLAYER_SKIN_PACKET = 0x5d;
	public const SUB_CLIENT_LOGIN_PACKET = 0x5e;
	public const AUTOMATION_CLIENT_CONNECT_PACKET = 0x5f;
	public const SET_LAST_HURT_BY_PACKET = 0x60;
	public const BOOK_EDIT_PACKET = 0x61;
	public const NPC_REQUEST_PACKET = 0x62;
	public const PHOTO_TRANSFER_PACKET = 0x63;
	public const MODAL_FORM_REQUEST_PACKET = 0x64;
	public const MODAL_FORM_RESPONSE_PACKET = 0x65;
	public const SERVER_SETTINGS_REQUEST_PACKET = 0x66;
	public const SERVER_SETTINGS_RESPONSE_PACKET = 0x67;
	public const SHOW_PROFILE_PACKET = 0x68;
	public const SET_DEFAULT_GAME_TYPE_PACKET = 0x69;
	public const REMOVE_OBJECTIVE_PACKET = 0x6a;
	public const SET_DISPLAY_OBJECTIVE_PACKET = 0x6b;
	public const SET_SCORE_PACKET = 0x6c;
	public const LAB_TABLE_PACKET = 0x6d;
	public const UPDATE_BLOCK_SYNCED_PACKET = 0x6e;
	public const MOVE_ACTOR_DELTA_PACKET = 0x6f;
	public const SET_SCOREBOARD_IDENTITY_PACKET = 0x70;
	public const SET_LOCAL_PLAYER_AS_INITIALIZED_PACKET = 0x71;
	public const UPDATE_SOFT_ENUM_PACKET = 0x72;
	public const NETWORK_STACK_LATENCY_PACKET = 0x73;

	public const SCRIPT_CUSTOM_EVENT_PACKET = 0x75;
	public const SPAWN_PARTICLE_EFFECT_PACKET = 0x76;
	public const AVAILABLE_ACTOR_IDENTIFIERS_PACKET = 0x77;
	public const LEVEL_SOUND_EVENT_PACKET_V2 = 0x78;
	public const NETWORK_CHUNK_PUBLISHER_UPDATE_PACKET = 0x79;
	public const BIOME_DEFINITION_LIST_PACKET = 0x7a;
	public const LEVEL_SOUND_EVENT_PACKET = 0x7b;
	public const LEVEL_EVENT_GENERIC_PACKET = 0x7c;
	public const LECTERN_UPDATE_PACKET = 0x7d;
	public const VIDEO_STREAM_CONNECT_PACKET = 0x7e;
	public const ADD_ENTITY_PACKET = 0x7f;
	public const REMOVE_ENTITY_PACKET = 0x80;
	public const CLIENT_CACHE_STATUS_PACKET = 0x81;
	public const ON_SCREEN_TEXTURE_ANIMATION_PACKET = 0x82;
	public const MAP_CREATE_LOCKED_COPY_PACKET = 0x83;
	public const STRUCTURE_TEMPLATE_DATA_REQUEST_PACKET = 0x84;
	public const STRUCTURE_TEMPLATE_DATA_RESPONSE_PACKET = 0x85;
	public const UPDATE_BLOCK_PROPERTIES_PACKET = 0x86;
	public const CLIENT_CACHE_BLOB_STATUS_PACKET = 0x87;
	public const CLIENT_CACHE_MISS_RESPONSE_PACKET = 0x88;
	public const EDUCATION_SETTINGS_PACKET = 0x89;
	public const EMOTE_PACKET = 0x8a;
	public const MULTIPLAYER_SETTINGS_PACKET = 0x8b;
	public const SETTINGS_COMMAND_PACKET = 0x8c;
	public const ANVIL_DAMAGE_PACKET = 0x8d;
	public const COMPLETED_USING_ITEM_PACKET = 0x8e;
	public const NETWORK_SETTINGS_PACKET = 0x8f;
	public const PLAYER_AUTH_INPUT_PACKET = 0x90;

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\scheduler;

use pocketmine\Server;
use pocketmine\utils\Utils;
use function array_keys;
use function assert;
use function count;
use function get_class;
use function spl_object_hash;
use function time;
use const PHP_INT_MAX;
use const PTHREADS_INHERIT_CONSTANTS;
use const PTHREADS_INHERIT_INI;

/**
 * Manages general-purpose worker threads used for processing asynchronous tasks, and the tasks submitted to those
 * workers.
 */
class AsyncPool{
	private const WORKER_START_OPTIONS = PTHREADS_INHERIT_INI | PTHREADS_INHERIT_CONSTANTS;

	/** @var Server */
	private $server;

	/** @var \ClassLoader */
	private $classLoader;
	/** @var \ThreadedLogger */
	private $logger;
	/** @var int */
	protected $size;
	/** @var int */
	private $workerMemoryLimit;

	/** @var AsyncTask[] */
	private $tasks = [];
	/** @var int[] */
	private $taskWorkers = [];
	/** @var int */
	private $nextTaskId = 1;

	/** @var AsyncWorker[] */
	private $workers = [];
	/** @var int[] */
	private $workerUsage = [];
	/** @var int[] */
	private $workerLastUsed = [];

	/**
	 * @var \Closure[]
	 * @phpstan-var (\Closure(int $workerId) : void)[]
	 */
	private $workerStartHooks = [];

	public function __construct(Server $server, int $size, int $workerMemoryLimit, \ClassLoader $classLoader, \ThreadedLogger $logger){
		$this->server = $server;
		$this->size = $size;
		$this->workerMemoryLimit = $workerMemoryLimit;
		$this->classLoader = $classLoader;
		$this->logger = $logger;
	}

	/**
	 * Returns the maximum size of the pool. Note that there may be less active workers than this number.
	 */
	public function getSize() : int{
		return $this->size;
	}

	/**
	 * Increases the maximum size of the pool to the specified amount. This does not immediately start new workers.
	 */
	public function increaseSize(int $newSize) : void{
		if($newSize > $this->size){
			$this->size = $newSize;
		}
	}

	/**
	 * Registers a Closure callback to be fired whenever a new worker is started by the pool.
	 * The signature should be `function(int $worker) : void`
	 *
	 * This function will call the hook for every already-running worker.
	 *
	 * @phpstan-param \Closure(int $workerId) : void $hook
	 */
	public function addWorkerStartHook(\Closure $hook) : void{
		Utils::validateCallableSignature(function(int $worker) : void{}, $hook);
		$this->workerStartHooks[spl_object_hash($hook)] = $hook;
		foreach($this->workers as $i => $worker){
			$hook($i);
		}
	}

	/**
	 * Removes a previously-registered callback listening for workers being started.
	 *
	 * @phpstan-param \Closure(int $workerId) : void $hook
	 */
	public function removeWorkerStartHook(\Closure $hook) : void{
		unset($this->workerStartHooks[spl_object_hash($hook)]);
	}

	/**
	 * Returns an array of IDs of currently running workers.
	 *
	 * @return int[]
	 */
	public function getRunningWorkers() : array{
		return array_keys($this->workers);
	}

	/**
	 * Fetches the worker with the specified ID, starting it if it does not exist, and firing any registered worker
	 * start hooks.
	 */
	private function getWorker(int $worker) : AsyncWorker{
		if(!isset($this->workers[$worker])){
			$this->workerUsage[$worker] = 0;
			$this->workers[$worker] = new AsyncWorker($this->logger, $worker, $this->workerMemoryLimit);
			$this->workers[$worker]->setClassLoader($this->classLoader);
			$this->workers[$worker]->start(self::WORKER_START_OPTIONS);

			foreach($this->workerStartHooks as $hook){
				$hook($worker);
			}
		}

		return $this->workers[$worker];
	}

	/**
	 * Submits an AsyncTask to an arbitrary worker.
	 */
	public function submitTaskToWorker(AsyncTask $task, int $worker) : void{
		if($worker < 0 or $worker >= $this->size){
			throw new \InvalidArgumentException("Invalid worker $worker");
		}
		if($task->getTaskId() !== null){
			throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once");
		}

		$task->progressUpdates = new \Threaded;
		$task->setTaskId($this->nextTaskId++);

		$this->tasks[$task->getTaskId()] = $task;

		$this->getWorker($worker)->stack($task);
		$this->workerUsage[$worker]++;
		$this->taskWorkers[$task->getTaskId()] = $worker;
		$this->workerLastUsed[$worker] = time();
	}

	/**
	 * Selects a worker ID to run a task.
	 *
	 * - if an idle worker is found, it will be selected
	 * - else, if the worker pool is not full, a new worker will be selected
	 * - else, the worker with the smallest backlog is chosen.
	 */
	public function selectWorker() : int{
		$worker = null;
		$minUsage = PHP_INT_MAX;
		foreach($this->workerUsage as $i => $usage){
			if($usage < $minUsage){
				$worker = $i;
				$minUsage = $usage;
				if($usage === 0){
					break;
				}
			}
		}
		if($worker === null or ($minUsage > 0 and count($this->workers) < $this->size)){
			//select a worker to start on the fly
			for($i = 0; $i < $this->size; ++$i){
				if(!isset($this->workers[$i])){
					$worker = $i;
					break;
				}
			}
		}

		assert($worker !== null);
		return $worker;
	}

	/**
	 * Submits an AsyncTask to the worker with the least load. If all workers are busy and the pool is not full, a new
	 * worker may be started.
	 */
	public function submitTask(AsyncTask $task) : int{
		if($task->getTaskId() !== null){
			throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once");
		}

		$worker = $this->selectWorker();
		$this->submitTaskToWorker($task, $worker);
		return $worker;
	}

	/**
	 * Removes a completed or crashed task from the pool.
	 */
	private function removeTask(AsyncTask $task, bool $force = false) : void{
		if(isset($this->taskWorkers[$task->getTaskId()])){
			if(!$force and ($task->isRunning() or !$task->isGarbage())){
				return;
			}
			$this->workerUsage[$this->taskWorkers[$task->getTaskId()]]--;
		}

		$task->removeDanglingStoredObjects();
		unset($this->tasks[$task->getTaskId()]);
		unset($this->taskWorkers[$task->getTaskId()]);
	}

	/**
	 * Removes all tasks from the pool, cancelling where possible. This will block until all tasks have been
	 * successfully deleted.
	 */
	public function removeTasks() : void{
		foreach($this->workers as $worker){
			/** @var AsyncTask $task */
			while(($task = $worker->unstack()) !== null){
				//cancelRun() is not strictly necessary here, but it might be used to inform plugins of the task state
				//(i.e. it never executed).
				assert($task instanceof AsyncTask);
				$task->cancelRun();
				$this->removeTask($task, true);
			}
		}
		do{
			foreach($this->tasks as $task){
				$task->cancelRun();
				$this->removeTask($task);
			}

			if(count($this->tasks) > 0){
				Server::microSleep(25000);
			}
		}while(count($this->tasks) > 0);

		for($i = 0; $i < $this->size; ++$i){
			$this->workerUsage[$i] = 0;
		}

		$this->taskWorkers = [];
		$this->tasks = [];

		$this->collectWorkers();
	}

	/**
	 * Collects garbage from running workers.
	 */
	private function collectWorkers() : void{
		foreach($this->workers as $worker){
			$worker->collect();
		}
	}

	/**
	 * Collects finished and/or crashed tasks from the workers, firing their on-completion hooks where appropriate.
	 *
	 * @throws \ReflectionException
	 */
	public function collectTasks() : void{
		foreach($this->tasks as $task){
			$task->checkProgressUpdates($this->server);
			if($task->isGarbage() and !$task->isRunning() and !$task->isCrashed()){
				if(!$task->hasCancelledRun()){
					/*
					 * It's possible for a task to submit a progress update and then finish before the progress
					 * update is detected by the parent thread, so here we consume any missed updates.
					 *
					 * When this happens, it's possible for a progress update to arrive between the previous
					 * checkProgressUpdates() call and the next isGarbage() call, causing progress updates to be
					 * lost. Thus, it's necessary to do one last check here to make sure all progress updates have
					 * been consumed before completing.
					 */
					$task->checkProgressUpdates($this->server);
					$task->onCompletion($this->server);
					if($task->removeDanglingStoredObjects()){
						$this->logger->notice("AsyncTask " . get_class($task) . " stored local complex data but did not remove them after completion");
					}
				}

				$this->removeTask($task);
			}elseif($task->isCrashed()){
				$this->logger->critical("Could not execute asynchronous task " . (new \ReflectionClass($task))->getShortName() . ": Task crashed");
				$this->removeTask($task, true);
			}
		}

		$this->collectWorkers();
	}

	public function shutdownUnusedWorkers() : int{
		$ret = 0;
		$time = time();
		foreach($this->workerUsage as $i => $usage){
			if($usage === 0 and (!isset($this->workerLastUsed[$i]) or $this->workerLastUsed[$i] + 300 < $time)){
				$this->workers[$i]->quit();
				unset($this->workers[$i], $this->workerUsage[$i], $this->workerLastUsed[$i]);
				$ret++;
			}
		}

		return $ret;
	}

	/**
	 * Cancels all pending tasks and shuts down all the workers in the pool.
	 */
	public function shutdown() : void{
		$this->collectTasks();
		$this->removeTasks();
		foreach($this->workers as $worker){
			$worker->quit();
		}
		$this->workers = [];
		$this->workerLastUsed = [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Network-related classes
 */
namespace pocketmine\network;

use pocketmine\event\server\NetworkInterfaceRegisterEvent;
use pocketmine\event\server\NetworkInterfaceUnregisterEvent;
use pocketmine\network\mcpe\protocol\PacketPool;
use pocketmine\Server;
use function spl_object_hash;

class Network{

	/** @var int */
	public static $BATCH_THRESHOLD = 512;

	/** @var Server */
	private $server;

	/** @var SourceInterface[] */
	private $interfaces = [];

	/** @var AdvancedSourceInterface[] */
	private $advancedInterfaces = [];

	/** @var float */
	private $upload = 0;
	/** @var float */
	private $download = 0;

	/** @var string */
	private $name;

	public function __construct(Server $server){
		PacketPool::init();

		$this->server = $server;

	}

	/**
	 * @param float $upload
	 * @param float $download
	 *
	 * @return void
	 */
	public function addStatistics($upload, $download){
		$this->upload += $upload;
		$this->download += $download;
	}

	/**
	 * @return float
	 */
	public function getUpload(){
		return $this->upload;
	}

	/**
	 * @return float
	 */
	public function getDownload(){
		return $this->download;
	}

	/**
	 * @return void
	 */
	public function resetStatistics(){
		$this->upload = 0;
		$this->download = 0;
	}

	/**
	 * @return SourceInterface[]
	 */
	public function getInterfaces() : array{
		return $this->interfaces;
	}

	/**
	 * @return void
	 */
	public function processInterfaces(){
		foreach($this->interfaces as $interface){
			$interface->process();
		}
	}

	/**
	 * @deprecated
	 */
	public function processInterface(SourceInterface $interface) : void{
		$interface->process();
	}

	/**
	 * @return void
	 */
	public function registerInterface(SourceInterface $interface){
		$ev = new NetworkInterfaceRegisterEvent($interface);
		$ev->call();
		if(!$ev->isCancelled()){
			$interface->start();
			$this->interfaces[$hash = spl_object_hash($interface)] = $interface;
			if($interface instanceof AdvancedSourceInterface){
				$this->advancedInterfaces[$hash] = $interface;
				$interface->setNetwork($this);
			}
			$interface->setName($this->name);
		}
	}

	/**
	 * @return void
	 */
	public function unregisterInterface(SourceInterface $interface){
		(new NetworkInterfaceUnregisterEvent($interface))->call();
		unset($this->interfaces[$hash = spl_object_hash($interface)], $this->advancedInterfaces[$hash]);
	}

	/**
	 * Sets the server name shown on each interface Query
	 *
	 * @return void
	 */
	public function setName(string $name){
		$this->name = $name;
		foreach($this->interfaces as $interface){
			$interface->setName($this->name);
		}
	}

	public function getName() : string{
		return $this->name;
	}

	/**
	 * @return void
	 */
	public function updateName(){
		foreach($this->interfaces as $interface){
			$interface->setName($this->name);
		}
	}

	public function getServer() : Server{
		return $this->server;
	}

	/**
	 * @return void
	 */
	public function sendPacket(string $address, int $port, string $payload){
		foreach($this->advancedInterfaces as $interface){
			$interface->sendRawPacket($address, $port, $payload);
		}
	}

	/**
	 * Blocks an IP address from the main interface. Setting timeout to -1 will block it forever
	 *
	 * @return void
	 */
	public function blockAddress(string $address, int $timeout = 300){
		foreach($this->advancedInterfaces as $interface){
			$interface->blockAddress($address, $timeout);
		}
	}

	/**
	 * @return void
	 */
	public function unblockAddress(string $address){
		foreach($this->advancedInterfaces as $interface){
			$interface->unblockAddress($address);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command;

use pocketmine\lang\TextContainer;
use pocketmine\permission\PermissibleBase;
use pocketmine\permission\Permission;
use pocketmine\permission\PermissionAttachment;
use pocketmine\permission\PermissionAttachmentInfo;
use pocketmine\plugin\Plugin;
use pocketmine\Server;
use pocketmine\utils\MainLogger;
use function explode;
use function trim;
use const PHP_INT_MAX;

class ConsoleCommandSender implements CommandSender{

	/** @var PermissibleBase */
	private $perm;

	/** @var int|null */
	protected $lineHeight = null;

	public function __construct(){
		$this->perm = new PermissibleBase($this);
	}

	/**
	 * @param Permission|string $name
	 */
	public function isPermissionSet($name) : bool{
		return $this->perm->isPermissionSet($name);
	}

	/**
	 * @param Permission|string $name
	 */
	public function hasPermission($name) : bool{
		return $this->perm->hasPermission($name);
	}

	public function addAttachment(Plugin $plugin, string $name = null, bool $value = null) : PermissionAttachment{
		return $this->perm->addAttachment($plugin, $name, $value);
	}

	/**
	 * @return void
	 */
	public function removeAttachment(PermissionAttachment $attachment){
		$this->perm->removeAttachment($attachment);
	}

	public function recalculatePermissions(){
		$this->perm->recalculatePermissions();
	}

	/**
	 * @return PermissionAttachmentInfo[]
	 */
	public function getEffectivePermissions() : array{
		return $this->perm->getEffectivePermissions();
	}

	/**
	 * @return Server
	 */
	public function getServer(){
		return Server::getInstance();
	}

	/**
	 * @param TextContainer|string $message
	 *
	 * @return void
	 */
	public function sendMessage($message){
		if($message instanceof TextContainer){
			$message = $this->getServer()->getLanguage()->translate($message);
		}else{
			$message = $this->getServer()->getLanguage()->translateString($message);
		}

		foreach(explode("\n", trim($message)) as $line){
			MainLogger::getLogger()->info($line);
		}
	}

	public function getName() : string{
		return "CONSOLE";
	}

	public function isOp() : bool{
		return true;
	}

	/**
	 * @return void
	 */
	public function setOp(bool $value){

	}

	public function getScreenLineHeight() : int{
		return $this->lineHeight ?? PHP_INT_MAX;
	}

	public function setScreenLineHeight(int $height = null){
		if($height !== null and $height < 1){
			throw new \InvalidArgumentException("Line height must be at least 1");
		}
		$this->lineHeight = $height;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command;

use pocketmine\lang\TextContainer;
use pocketmine\permission\Permissible;
use pocketmine\Server;

interface CommandSender extends Permissible{

	/**
	 * @param TextContainer|string $message
	 *
	 * @return void
	 */
	public function sendMessage($message);

	/**
	 * @return Server
	 */
	public function getServer();

	public function getName() : string;

	/**
	 * Returns the line height of the command-sender's screen. Used for determining sizes for command output pagination
	 * such as in the /help command.
	 */
	public function getScreenLineHeight() : int;

	/**
	 * Sets the line height used for command output pagination for this command sender. `null` will reset it to default.
	 *
	 * @return void
	 */
	public function setScreenLineHeight(int $height = null);
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\permission;

use pocketmine\plugin\Plugin;

interface Permissible extends ServerOperator{

	/**
	 * Checks if this instance has a permission overridden
	 *
	 * @param string|Permission $name
	 */
	public function isPermissionSet($name) : bool;

	/**
	 * Returns the permission value if overridden, or the default value if not
	 *
	 * @param string|Permission $name
	 */
	public function hasPermission($name) : bool;

	public function addAttachment(Plugin $plugin, string $name = null, bool $value = null) : PermissionAttachment;

	/**
	 * @return void
	 */
	public function removeAttachment(PermissionAttachment $attachment);

	/**
	 * @return void
	 */
	public function recalculatePermissions();

	/**
	 * @return PermissionAttachmentInfo[]
	 */
	public function getEffectivePermissions() : array;

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\permission;

interface ServerOperator{
	/**
	 * Checks if the current object has operator permissions
	 */
	public function isOp() : bool;

	/**
	 * Sets the operator permission for the current object
	 *
	 * @return void
	 */
	public function setOp(bool $value);
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\permission;

use pocketmine\plugin\Plugin;
use pocketmine\plugin\PluginException;
use pocketmine\timings\Timings;
use function spl_object_hash;

class PermissibleBase implements Permissible{
	/** @var ServerOperator */
	private $opable;

	/** @var Permissible|null */
	private $parent = null;

	/** @var PermissionAttachment[] */
	private $attachments = [];

	/** @var PermissionAttachmentInfo[] */
	private $permissions = [];

	public function __construct(ServerOperator $opable){
		$this->opable = $opable;
		if($opable instanceof Permissible){
			$this->parent = $opable;
		}
	}

	public function isOp() : bool{
		return $this->opable->isOp();
	}

	public function setOp(bool $value){
		$this->opable->setOp($value);
	}

	public function isPermissionSet($name) : bool{
		return isset($this->permissions[$name instanceof Permission ? $name->getName() : $name]);
	}

	public function hasPermission($name) : bool{
		if($name instanceof Permission){
			$name = $name->getName();
		}

		if($this->isPermissionSet($name)){
			return $this->permissions[$name]->getValue();
		}

		if(($perm = PermissionManager::getInstance()->getPermission($name)) !== null){
			$perm = $perm->getDefault();

			return $perm === Permission::DEFAULT_TRUE or ($this->isOp() and $perm === Permission::DEFAULT_OP) or (!$this->isOp() and $perm === Permission::DEFAULT_NOT_OP);
		}else{
			return Permission::$DEFAULT_PERMISSION === Permission::DEFAULT_TRUE or ($this->isOp() and Permission::$DEFAULT_PERMISSION === Permission::DEFAULT_OP) or (!$this->isOp() and Permission::$DEFAULT_PERMISSION === Permission::DEFAULT_NOT_OP);
		}

	}

	/**
	 * //TODO: tick scheduled attachments
	 */
	public function addAttachment(Plugin $plugin, string $name = null, bool $value = null) : PermissionAttachment{
		if(!$plugin->isEnabled()){
			throw new PluginException("Plugin " . $plugin->getDescription()->getName() . " is disabled");
		}

		$result = new PermissionAttachment($plugin, $this->parent ?? $this);
		$this->attachments[spl_object_hash($result)] = $result;
		if($name !== null and $value !== null){
			$result->setPermission($name, $value);
		}

		$this->recalculatePermissions();

		return $result;
	}

	public function removeAttachment(PermissionAttachment $attachment){
		if(isset($this->attachments[spl_object_hash($attachment)])){
			unset($this->attachments[spl_object_hash($attachment)]);
			if(($ex = $attachment->getRemovalCallback()) !== null){
				$ex->attachmentRemoved($attachment);
			}

			$this->recalculatePermissions();

		}

	}

	public function recalculatePermissions(){
		Timings::$permissibleCalculationTimer->startTiming();

		$this->clearPermissions();
		$permManager = PermissionManager::getInstance();
		$defaults = $permManager->getDefaultPermissions($this->isOp());
		$permManager->subscribeToDefaultPerms($this->isOp(), $this->parent ?? $this);

		foreach($defaults as $perm){
			$name = $perm->getName();
			$this->permissions[$name] = new PermissionAttachmentInfo($this->parent ?? $this, $name, null, true);
			$permManager->subscribeToPermission($name, $this->parent ?? $this);
			$this->calculateChildPermissions($perm->getChildren(), false, null);
		}

		foreach($this->attachments as $attachment){
			$this->calculateChildPermissions($attachment->getPermissions(), false, $attachment);
		}

		Timings::$permissibleCalculationTimer->stopTiming();
	}

	/**
	 * @return void
	 */
	public function clearPermissions(){
		$permManager = PermissionManager::getInstance();
		$permManager->unsubscribeFromAllPermissions($this->parent ?? $this);

		$permManager->unsubscribeFromDefaultPerms(false, $this->parent ?? $this);
		$permManager->unsubscribeFromDefaultPerms(true, $this->parent ?? $this);

		$this->permissions = [];
	}

	/**
	 * @param bool[]                    $children
	 */
	private function calculateChildPermissions(array $children, bool $invert, ?PermissionAttachment $attachment) : void{
		$permManager = PermissionManager::getInstance();
		foreach($children as $name => $v){
			$perm = $permManager->getPermission($name);
			$value = ($v xor $invert);
			$this->permissions[$name] = new PermissionAttachmentInfo($this->parent ?? $this, $name, $attachment, $value);
			$permManager->subscribeToPermission($name, $this->parent ?? $this);

			if($perm instanceof Permission){
				$this->calculateChildPermissions($perm->getChildren(), !$value, $attachment);
			}
		}
	}

	/**
	 * @return PermissionAttachmentInfo[]
	 */
	public function getEffectivePermissions() : array{
		return $this->permissions;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\permission;

use pocketmine\timings\Timings;
use function count;
use function spl_object_hash;

class PermissionManager{
	/** @var PermissionManager|null */
	private static $instance = null;

	public static function getInstance() : PermissionManager{
		if(self::$instance === null){
			self::$instance = new self;
		}

		return self::$instance;
	}

	/** @var Permission[] */
	protected $permissions = [];
	/** @var Permission[] */
	protected $defaultPerms = [];
	/** @var Permission[] */
	protected $defaultPermsOp = [];
	/** @var Permissible[][] */
	protected $permSubs = [];
	/** @var Permissible[] */
	protected $defSubs = [];
	/** @var Permissible[] */
	protected $defSubsOp = [];

	/**
	 * @return null|Permission
	 */
	public function getPermission(string $name){
		return $this->permissions[$name] ?? null;
	}

	public function addPermission(Permission $permission) : bool{
		if(!isset($this->permissions[$permission->getName()])){
			$this->permissions[$permission->getName()] = $permission;
			$this->calculatePermissionDefault($permission);

			return true;
		}

		return false;
	}

	/**
	 * @param string|Permission $permission
	 *
	 * @return void
	 */
	public function removePermission($permission){
		if($permission instanceof Permission){
			unset($this->permissions[$permission->getName()]);
		}else{
			unset($this->permissions[$permission]);
		}
	}

	/**
	 * @return Permission[]
	 */
	public function getDefaultPermissions(bool $op) : array{
		if($op){
			return $this->defaultPermsOp;
		}else{
			return $this->defaultPerms;
		}
	}

	/**
	 * @return void
	 */
	public function recalculatePermissionDefaults(Permission $permission){
		if(isset($this->permissions[$permission->getName()])){
			unset($this->defaultPermsOp[$permission->getName()]);
			unset($this->defaultPerms[$permission->getName()]);
			$this->calculatePermissionDefault($permission);
		}
	}

	private function calculatePermissionDefault(Permission $permission) : void{
		Timings::$permissionDefaultTimer->startTiming();
		if($permission->getDefault() === Permission::DEFAULT_OP or $permission->getDefault() === Permission::DEFAULT_TRUE){
			$this->defaultPermsOp[$permission->getName()] = $permission;
			$this->dirtyPermissibles(true);
		}

		if($permission->getDefault() === Permission::DEFAULT_NOT_OP or $permission->getDefault() === Permission::DEFAULT_TRUE){
			$this->defaultPerms[$permission->getName()] = $permission;
			$this->dirtyPermissibles(false);
		}
		Timings::$permissionDefaultTimer->startTiming();
	}

	private function dirtyPermissibles(bool $op) : void{
		foreach($this->getDefaultPermSubscriptions($op) as $p){
			$p->recalculatePermissions();
		}
	}

	/**
	 * @return void
	 */
	public function subscribeToPermission(string $permission, Permissible $permissible){
		if(!isset($this->permSubs[$permission])){
			$this->permSubs[$permission] = [];
		}
		$this->permSubs[$permission][spl_object_hash($permissible)] = $permissible;
	}

	/**
	 * @return void
	 */
	public function unsubscribeFromPermission(string $permission, Permissible $permissible){
		if(isset($this->permSubs[$permission])){
			unset($this->permSubs[$permission][spl_object_hash($permissible)]);
			if(count($this->permSubs[$permission]) === 0){
				unset($this->permSubs[$permission]);
			}
		}
	}

	public function unsubscribeFromAllPermissions(Permissible $permissible) : void{
		foreach($this->permSubs as $permission => &$subs){
			unset($subs[spl_object_hash($permissible)]);
			if(count($subs) === 0){
				unset($this->permSubs[$permission]);
			}
		}
	}

	/**
	 * @return array|Permissible[]
	 */
	public function getPermissionSubscriptions(string $permission) : array{
		return $this->permSubs[$permission] ?? [];
	}

	/**
	 * @return void
	 */
	public function subscribeToDefaultPerms(bool $op, Permissible $permissible){
		if($op){
			$this->defSubsOp[spl_object_hash($permissible)] = $permissible;
		}else{
			$this->defSubs[spl_object_hash($permissible)] = $permissible;
		}
	}

	/**
	 * @return void
	 */
	public function unsubscribeFromDefaultPerms(bool $op, Permissible $permissible){
		if($op){
			unset($this->defSubsOp[spl_object_hash($permissible)]);
		}else{
			unset($this->defSubs[spl_object_hash($permissible)]);
		}
	}

	/**
	 * @return Permissible[]
	 */
	public function getDefaultPermSubscriptions(bool $op) : array{
		if($op){
			return $this->defSubsOp;
		}

		return $this->defSubs;
	}

	/**
	 * @return Permission[]
	 */
	public function getPermissions() : array{
		return $this->permissions;
	}

	public function clearPermissions() : void{
		$this->permissions = [];
		$this->defaultPerms = [];
		$this->defaultPermsOp = [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\snooze;

use function assert;

/**
 * Notifiers are Threaded objects which can be attached to threaded sleepers in order to wake them up. They also record
 * state so that the main thread handler can determine which notifier woke up the sleeper.
 */
class SleeperNotifier extends \Threaded{
	/** @var ThreadedSleeper */
	private $threadedSleeper;

	/** @var int */
	private $sleeperId;

	/** @var bool */
	private $notification = false;

	final public function attachSleeper(ThreadedSleeper $sleeper, int $id) : void{
		$this->threadedSleeper = $sleeper;
		$this->sleeperId = $id;
	}

	final public function getSleeperId() : int{
		return $this->sleeperId;
	}

	/**
	 * Call this method from other threads to wake up the main server thread.
	 */
	final public function wakeupSleeper() : void{
		assert($this->threadedSleeper !== null);

		$this->synchronized(function() : void{
			if(!$this->notification){
				$this->notification = true;

				$this->threadedSleeper->wakeup();
			}
		});
	}

	final public function hasNotification() : bool{
		return $this->notification;
	}

	final public function clearNotification() : void{
		$this->synchronized(function() : void{
			//this has to be synchronized to avoid races with waking up
			$this->notification = false;
		});
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command;

use pocketmine\snooze\SleeperNotifier;
use pocketmine\Thread;
use pocketmine\utils\Utils;
use function extension_loaded;
use function fclose;
use function fgets;
use function fopen;
use function fstat;
use function getopt;
use function is_resource;
use function microtime;
use function preg_replace;
use function readline;
use function readline_add_history;
use function stream_isatty;
use function stream_select;
use function trim;
use function usleep;
use const STDIN;

class CommandReader extends Thread{

	public const TYPE_READLINE = 0;
	public const TYPE_STREAM = 1;
	public const TYPE_PIPED = 2;

	/** @var resource */
	private static $stdin;

	/** @var \Threaded */
	protected $buffer;
	/** @var bool */
	private $shutdown = false;
	/** @var int */
	private $type = self::TYPE_STREAM;

	/** @var SleeperNotifier|null */
	private $notifier;

	public function __construct(?SleeperNotifier $notifier = null){
		$this->buffer = new \Threaded;
		$this->notifier = $notifier;

		$opts = getopt("", ["disable-readline", "enable-readline"]);

		if(extension_loaded("readline") and (Utils::getOS() === "win" ? isset($opts["enable-readline"]) : !isset($opts["disable-readline"])) and !$this->isPipe(STDIN)){
			$this->type = self::TYPE_READLINE;
		}
	}

	/**
	 * @return void
	 */
	public function shutdown(){
		$this->shutdown = true;
	}

	public function quit(){
		$wait = microtime(true) + 0.5;
		while(microtime(true) < $wait){
			if($this->isRunning()){
				usleep(100000);
			}else{
				parent::quit();
				return;
			}
		}

		$message = "Thread blocked for unknown reason";
		if($this->type === self::TYPE_PIPED){
			$message = "STDIN is being piped from another location and the pipe is blocked, cannot stop safely";
		}

		throw new \ThreadException($message);
	}

	private function initStdin() : void{
		if(is_resource(self::$stdin)){
			fclose(self::$stdin);
		}

		self::$stdin = fopen("php://stdin", "r");
		if($this->isPipe(self::$stdin)){
			$this->type = self::TYPE_PIPED;
		}else{
			$this->type = self::TYPE_STREAM;
		}
	}

	/**
	 * Checks if the specified stream is a FIFO pipe.
	 *
	 * @param resource $stream
	 */
	private function isPipe($stream) : bool{
		return is_resource($stream) and (!stream_isatty($stream) or ((fstat($stream)["mode"] & 0170000) === 0010000));
	}

	/**
	 * Reads a line from the console and adds it to the buffer. This method may block the thread.
	 *
	 * @return bool if the main execution should continue reading lines
	 */
	private function readLine() : bool{
		$line = "";
		if($this->type === self::TYPE_READLINE){
			if(($raw = readline("> ")) !== false and ($line = trim($raw)) !== ""){
				readline_add_history($line);
			}else{
				return true;
			}
		}else{
			if(!is_resource(self::$stdin)){
				$this->initStdin();
			}

			switch($this->type){
				/** @noinspection PhpMissingBreakStatementInspection */
				case self::TYPE_STREAM:
					//stream_select doesn't work on piped streams for some reason
					$r = [self::$stdin];
					$w = $e = null;
					if(($count = stream_select($r, $w, $e, 0, 200000)) === 0){ //nothing changed in 200000 microseconds
						return true;
					}elseif($count === false){ //stream error
						$this->initStdin();
					}

				case self::TYPE_PIPED:
					if(($raw = fgets(self::$stdin)) === false){ //broken pipe or EOF
						$this->initStdin();
						$this->synchronized(function() : void{
							$this->wait(200000);
						}); //prevent CPU waste if it's end of pipe
						return true; //loop back round
					}

					$line = trim($raw);
					break;
			}
		}

		if($line !== ""){
			$this->buffer[] = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", $line);
			if($this->notifier !== null){
				$this->notifier->wakeupSleeper();
			}
		}

		return true;
	}

	/**
	 * Reads a line from console, if available. Returns null if not available
	 *
	 * @return string|null
	 */
	public function getLine(){
		if($this->buffer->count() !== 0){
			return (string) $this->buffer->shift();
		}

		return null;
	}

	/**
	 * @return void
	 */
	public function run(){
		$this->registerClassLoader();

		if($this->type !== self::TYPE_READLINE){
			$this->initStdin();
		}

		while(!$this->shutdown and $this->readLine());

		if($this->type !== self::TYPE_READLINE){
			fclose(self::$stdin);
		}

	}

	public function getThreadName() : string{
		return "Console";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine;

/**
 * This class must be extended by all custom threading classes
 */
abstract class Thread extends \Thread{

	/** @var \ClassLoader|null */
	protected $classLoader;
	/** @var string|null */
	protected $composerAutoloaderPath;

	/** @var bool */
	protected $isKilled = false;

	/**
	 * @return \ClassLoader|null
	 */
	public function getClassLoader(){
		return $this->classLoader;
	}

	/**
	 * @return void
	 */
	public function setClassLoader(\ClassLoader $loader = null){
		$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;

		if($loader === null){
			$loader = Server::getInstance()->getLoader();
		}
		$this->classLoader = $loader;
	}

	/**
	 * Registers the class loader for this thread.
	 *
	 * WARNING: This method MUST be called from any descendent threads' run() method to make autoloading usable.
	 * If you do not do this, you will not be able to use new classes that were not loaded when the thread was started
	 * (unless you are using a custom autoloader).
	 *
	 * @return void
	 */
	public function registerClassLoader(){
		if($this->composerAutoloaderPath !== null){
			require $this->composerAutoloaderPath;
		}
		if($this->classLoader !== null){
			$this->classLoader->register(false);
		}
	}

	/**
	 * @param int|null $options TODO: pthreads bug
	 *
	 * @return bool
	 */
	public function start(?int $options = \PTHREADS_INHERIT_ALL){
		ThreadManager::getInstance()->add($this);

		if($this->getClassLoader() === null){
			$this->setClassLoader();
		}
		return parent::start($options);
	}

	/**
	 * Stops the thread using the best way possible. Try to stop it yourself before calling this.
	 *
	 * @return void
	 */
	public function quit(){
		$this->isKilled = true;

		if(!$this->isJoined()){
			$this->notify();
			$this->join();
		}

		ThreadManager::getInstance()->remove($this);
	}

	public function getThreadName() : string{
		return (new \ReflectionClass($this))->getShortName();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine;

use pocketmine\utils\MainLogger;
use function spl_object_hash;

class ThreadManager extends \Volatile{

	/** @var ThreadManager|null */
	private static $instance = null;

	/**
	 * @deprecated
	 * @return void
	 */
	public static function init(){
		self::$instance = new ThreadManager();
	}

	/**
	 * @return ThreadManager
	 */
	public static function getInstance(){
		if(self::$instance === null){
			self::$instance = new ThreadManager();
		}
		return self::$instance;
	}

	/**
	 * @param Worker|Thread $thread
	 *
	 * @return void
	 */
	public function add($thread){
		if($thread instanceof Thread or $thread instanceof Worker){
			$this[spl_object_hash($thread)] = $thread;
		}
	}

	/**
	 * @param Worker|Thread $thread
	 *
	 * @return void
	 */
	public function remove($thread){
		if($thread instanceof Thread or $thread instanceof Worker){
			unset($this[spl_object_hash($thread)]);
		}
	}

	/**
	 * @return Worker[]|Thread[]
	 */
	public function getAll() : array{
		$array = [];
		foreach($this as $key => $thread){
			$array[$key] = $thread;
		}

		return $array;
	}

	public function stopAll() : int{
		$logger = MainLogger::getLogger();

		$erroredThreads = 0;

		foreach($this->getAll() as $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());
			}
		}

		return $erroredThreads;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\metadata;

use pocketmine\entity\Entity;
use pocketmine\plugin\Plugin;

class EntityMetadataStore extends MetadataStore{

	private function disambiguate(Entity $entity, string $metadataKey) : string{
		return $entity->getId() . ":" . $metadataKey;
	}

	/**
	 * @return MetadataValue[]
	 */
	public function getMetadata(Entity $subject, string $metadataKey){
		return $this->getMetadataInternal($this->disambiguate($subject, $metadataKey));
	}

	public function hasMetadata(Entity $subject, string $metadataKey) : bool{
		return $this->hasMetadataInternal($this->disambiguate($subject, $metadataKey));
	}

	/**
	 * @return void
	 */
	public function removeMetadata(Entity $subject, string $metadataKey, Plugin $owningPlugin){
		$this->removeMetadataInternal($this->disambiguate($subject, $metadataKey), $owningPlugin);
	}

	/**
	 * @return void
	 */
	public function setMetadata(Entity $subject, string $metadataKey, MetadataValue $newMetadataValue){
		$this->setMetadataInternal($this->disambiguate($subject, $metadataKey), $newMetadataValue);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Saves extra data on runtime for different items
 */
namespace pocketmine\metadata;

use pocketmine\plugin\Plugin;

abstract class MetadataStore{
	/** @var \SplObjectStorage[]|MetadataValue[][] */
	private $metadataMap;

	/**
	 * Adds a metadata value to an object.
	 *
	 * @return void
	 */
	protected function setMetadataInternal(string $key, MetadataValue $newMetadataValue){
		$owningPlugin = $newMetadataValue->getOwningPlugin();

		if(!isset($this->metadataMap[$key])){
			$entry = new \SplObjectStorage();
			$this->metadataMap[$key] = $entry;
		}else{
			$entry = $this->metadataMap[$key];
		}
		$entry[$owningPlugin] = $newMetadataValue;
	}

	/**
	 * Returns all metadata values attached to an object. If multiple
	 * have attached metadata, each will value will be included.
	 *
	 * @return MetadataValue[]
	 */
	protected function getMetadataInternal(string $key){
		if(isset($this->metadataMap[$key])){
			return $this->metadataMap[$key];
		}else{
			return [];
		}
	}

	/**
	 * Tests to see if a metadata attribute has been set on an object.
	 */
	protected function hasMetadataInternal(string $key) : bool{
		return isset($this->metadataMap[$key]);
	}

	/**
	 * Removes a metadata item owned by a plugin from a subject.
	 *
	 * @return void
	 */
	protected function removeMetadataInternal(string $key, Plugin $owningPlugin){
		if(isset($this->metadataMap[$key])){
			unset($this->metadataMap[$key][$owningPlugin]);
			if($this->metadataMap[$key]->count() === 0){
				unset($this->metadataMap[$key]);
			}
		}
	}

	/**
	 * Invalidates all metadata in the metadata store that originates from the
	 * given plugin. Doing this will force each invalidated metadata item to
	 * be recalculated the next time it is accessed.
	 *
	 * @return void
	 */
	public function invalidateAll(Plugin $owningPlugin){
		/** @var \SplObjectStorage|MetadataValue[] $values */
		foreach($this->metadataMap as $values){
			if(isset($values[$owningPlugin])){
				$values[$owningPlugin]->invalidate();
			}
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\metadata;

use pocketmine\IPlayer;
use pocketmine\plugin\Plugin;
use function strtolower;

class PlayerMetadataStore extends MetadataStore{

	private function disambiguate(IPlayer $player, string $metadataKey) : string{
		return strtolower($player->getName()) . ":" . $metadataKey;
	}

	/**
	 * @return MetadataValue[]
	 */
	public function getMetadata(IPlayer $subject, string $metadataKey){
		return $this->getMetadataInternal($this->disambiguate($subject, $metadataKey));
	}

	public function hasMetadata(IPlayer $subject, string $metadataKey) : bool{
		return $this->hasMetadataInternal($this->disambiguate($subject, $metadataKey));
	}

	/**
	 * @return void
	 */
	public function removeMetadata(IPlayer $subject, string $metadataKey, Plugin $owningPlugin){
		$this->removeMetadataInternal($this->disambiguate($subject, $metadataKey), $owningPlugin);
	}

	/**
	 * @return void
	 */
	public function setMetadata(IPlayer $subject, string $metadataKey, MetadataValue $newMetadataValue){
		$this->setMetadataInternal($this->disambiguate($subject, $metadataKey), $newMetadataValue);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\metadata;

use pocketmine\level\Level;
use pocketmine\plugin\Plugin;
use function strtolower;

class LevelMetadataStore extends MetadataStore{

	private function disambiguate(Level $level, string $metadataKey) : string{
		return strtolower($level->getName()) . ":" . $metadataKey;
	}

	/**
	 * @return MetadataValue[]
	 */
	public function getMetadata(Level $subject, string $metadataKey){
		return $this->getMetadataInternal($this->disambiguate($subject, $metadataKey));
	}

	public function hasMetadata(Level $subject, string $metadataKey) : bool{
		return $this->hasMetadataInternal($this->disambiguate($subject, $metadataKey));
	}

	/**
	 * @return void
	 */
	public function removeMetadata(Level $subject, string $metadataKey, Plugin $owningPlugin){
		$this->removeMetadataInternal($this->disambiguate($subject, $metadataKey), $owningPlugin);
	}

	/**
	 * @return void
	 */
	public function setMetadata(Level $subject, string $metadataKey, MetadataValue $newMetadataValue){
		$this->setMetadataInternal($this->disambiguate($subject, $metadataKey), $newMetadataValue);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\permission;

use pocketmine\Server;
use pocketmine\utils\MainLogger;
use function fclose;
use function fgets;
use function fopen;
use function fwrite;
use function is_resource;
use function strftime;
use function strtolower;
use function time;

class BanList{

	/** @var BanEntry[] */
	private $list = [];

	/** @var string */
	private $file;

	/** @var bool */
	private $enabled = true;

	public function __construct(string $file){
		$this->file = $file;
	}

	public function isEnabled() : bool{
		return $this->enabled;
	}

	/**
	 * @return void
	 */
	public function setEnabled(bool $flag){
		$this->enabled = $flag;
	}

	public function getEntry(string $name) : ?BanEntry{
		$this->removeExpired();

		return $this->list[strtolower($name)] ?? null;
	}

	/**
	 * @return BanEntry[]
	 */
	public function getEntries() : array{
		$this->removeExpired();

		return $this->list;
	}

	public function isBanned(string $name) : bool{
		$name = strtolower($name);
		if(!$this->isEnabled()){
			return false;
		}else{
			$this->removeExpired();

			return isset($this->list[$name]);
		}
	}

	/**
	 * @return void
	 */
	public function add(BanEntry $entry){
		$this->list[$entry->getName()] = $entry;
		$this->save();
	}

	public function addBan(string $target, string $reason = null, \DateTime $expires = null, string $source = null) : BanEntry{
		$entry = new BanEntry($target);
		$entry->setSource($source ?? $entry->getSource());
		$entry->setExpires($expires);
		$entry->setReason($reason ?? $entry->getReason());

		$this->list[$entry->getName()] = $entry;
		$this->save();

		return $entry;
	}

	/**
	 * @return void
	 */
	public function remove(string $name){
		$name = strtolower($name);
		if(isset($this->list[$name])){
			unset($this->list[$name]);
			$this->save();
		}
	}

	/**
	 * @return void
	 */
	public function removeExpired(){
		foreach($this->list as $name => $entry){
			if($entry->hasExpired()){
				unset($this->list[$name]);
			}
		}
	}

	/**
	 * @return void
	 */
	public function load(){
		$this->list = [];
		$fp = @fopen($this->file, "r");
		if(is_resource($fp)){
			while(($line = fgets($fp)) !== false){
				if($line[0] !== "#"){
					try{
						$entry = BanEntry::fromString($line);
						if($entry instanceof BanEntry){
							$this->list[$entry->getName()] = $entry;
						}
					}catch(\Throwable $e){
						$logger = MainLogger::getLogger();
						$logger->critical("Failed to parse ban entry from string \"$line\": " . $e->getMessage());
						$logger->logException($e);
					}
				}
			}
			fclose($fp);
		}else{
			MainLogger::getLogger()->error("Could not load ban list");
		}
	}

	/**
	 * @return void
	 */
	public function save(bool $writeHeader = true){
		$this->removeExpired();
		$fp = @fopen($this->file, "w");
		if(is_resource($fp)){
			if($writeHeader){
				fwrite($fp, "# Updated " . strftime("%x %H:%M", time()) . " by " . Server::getInstance()->getName() . " " . Server::getInstance()->getPocketMineVersion() . "\n");
				fwrite($fp, "# victim name | ban date | banned by | banned until | reason\n\n");
			}

			foreach($this->list as $entry){
				fwrite($fp, $entry->getString() . "\n");
			}
			fclose($fp);
		}else{
			MainLogger::getLogger()->error("Could not save ban list");
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;

use function bin2hex;
use function getmypid;
use function getmyuid;
use function hash;
use function hex2bin;
use function implode;
use function mt_rand;
use function str_replace;
use function strlen;
use function substr;
use function time;
use function trim;

class UUID{

	/** @var int[] */
	private $parts;
	/** @var int */
	private $version;

	public function __construct(int $part1 = 0, int $part2 = 0, int $part3 = 0, int $part4 = 0, int $version = null){
		$this->parts = [$part1, $part2, $part3, $part4];

		$this->version = $version ?? ($this->parts[1] & 0xf000) >> 12;
	}

	public function getVersion() : int{
		return $this->version;
	}

	public function equals(UUID $uuid) : bool{
		return $uuid->parts === $this->parts;
	}

	/**
	 * Creates an UUID from an hexadecimal representation
	 */
	public static function fromString(string $uuid, int $version = null) : UUID{
		return self::fromBinary(hex2bin(str_replace("-", "", trim($uuid))), $version);
	}

	/**
	 * Creates an UUID from a binary representation
	 *
	 * @throws \InvalidArgumentException
	 */
	public static function fromBinary(string $uuid, int $version = null) : UUID{
		if(strlen($uuid) !== 16){
			throw new \InvalidArgumentException("Must have exactly 16 bytes");
		}

		return new UUID((\unpack("N", substr($uuid, 0, 4))[1] << 32 >> 32), (\unpack("N", substr($uuid, 4, 4))[1] << 32 >> 32), (\unpack("N", substr($uuid, 8, 4))[1] << 32 >> 32), (\unpack("N", substr($uuid, 12, 4))[1] << 32 >> 32), $version);
	}

	/**
	 * Creates an UUIDv3 from binary data or list of binary data
	 *
	 * @param string ...$data
	 */
	public static function fromData(string ...$data) : UUID{
		$hash = hash("md5", implode($data), true);

		return self::fromBinary($hash, 3);
	}

	public static function fromRandom() : UUID{
		return self::fromData((\pack("N", time())), (\pack("n", getmypid())), (\pack("n", getmyuid())), (\pack("N", mt_rand(-0x7fffffff, 0x7fffffff))), (\pack("N", mt_rand(-0x7fffffff, 0x7fffffff))));
	}

	public function toBinary() : string{
		return (\pack("N", $this->parts[0])) . (\pack("N", $this->parts[1])) . (\pack("N", $this->parts[2])) . (\pack("N", $this->parts[3]));
	}

	public function toString() : string{
		$hex = bin2hex($this->toBinary());

		//xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx 8-4-4-4-12
		return substr($hex, 0, 8) . "-" . substr($hex, 8, 4) . "-" . substr($hex, 12, 4) . "-" . substr($hex, 16, 4) . "-" . substr($hex, 20, 12);
	}

	public function __toString() : string{
		return $this->toString();
	}

	/**
	 * @return int
	 * @throws \InvalidArgumentException
	 */
	public function getPart(int $partNumber){
		if($partNumber < 0 or $partNumber > 3){
			throw new \InvalidArgumentException("Invalid UUID part index $partNumber");
		}
		return $this->parts[$partNumber];
	}

	/**
	 * @return int[]
	 */
	public function getParts() : array{
		return $this->parts;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;
use pocketmine\utils\BinaryDataException;

class PacketPool{
	/** @var \SplFixedArray<DataPacket> */
	protected static $pool;

	/**
	 * @return void
	 */
	public static function init(){
		static::$pool = new \SplFixedArray(256);

		static::registerPacket(new LoginPacket());
		static::registerPacket(new PlayStatusPacket());
		static::registerPacket(new ServerToClientHandshakePacket());
		static::registerPacket(new ClientToServerHandshakePacket());
		static::registerPacket(new DisconnectPacket());
		static::registerPacket(new ResourcePacksInfoPacket());
		static::registerPacket(new ResourcePackStackPacket());
		static::registerPacket(new ResourcePackClientResponsePacket());
		static::registerPacket(new TextPacket());
		static::registerPacket(new SetTimePacket());
		static::registerPacket(new StartGamePacket());
		static::registerPacket(new AddPlayerPacket());
		static::registerPacket(new AddActorPacket());
		static::registerPacket(new RemoveActorPacket());
		static::registerPacket(new AddItemActorPacket());
		static::registerPacket(new TakeItemActorPacket());
		static::registerPacket(new MoveActorAbsolutePacket());
		static::registerPacket(new MovePlayerPacket());
		static::registerPacket(new RiderJumpPacket());
		static::registerPacket(new UpdateBlockPacket());
		static::registerPacket(new AddPaintingPacket());
		static::registerPacket(new TickSyncPacket());
		static::registerPacket(new LevelSoundEventPacketV1());
		static::registerPacket(new LevelEventPacket());
		static::registerPacket(new BlockEventPacket());
		static::registerPacket(new ActorEventPacket());
		static::registerPacket(new MobEffectPacket());
		static::registerPacket(new UpdateAttributesPacket());
		static::registerPacket(new InventoryTransactionPacket());
		static::registerPacket(new MobEquipmentPacket());
		static::registerPacket(new MobArmorEquipmentPacket());
		static::registerPacket(new InteractPacket());
		static::registerPacket(new BlockPickRequestPacket());
		static::registerPacket(new ActorPickRequestPacket());
		static::registerPacket(new PlayerActionPacket());
		static::registerPacket(new ActorFallPacket());
		static::registerPacket(new HurtArmorPacket());
		static::registerPacket(new SetActorDataPacket());
		static::registerPacket(new SetActorMotionPacket());
		static::registerPacket(new SetActorLinkPacket());
		static::registerPacket(new SetHealthPacket());
		static::registerPacket(new SetSpawnPositionPacket());
		static::registerPacket(new AnimatePacket());
		static::registerPacket(new RespawnPacket());
		static::registerPacket(new ContainerOpenPacket());
		static::registerPacket(new ContainerClosePacket());
		static::registerPacket(new PlayerHotbarPacket());
		static::registerPacket(new InventoryContentPacket());
		static::registerPacket(new InventorySlotPacket());
		static::registerPacket(new ContainerSetDataPacket());
		static::registerPacket(new CraftingDataPacket());
		static::registerPacket(new CraftingEventPacket());
		static::registerPacket(new GuiDataPickItemPacket());
		static::registerPacket(new AdventureSettingsPacket());
		static::registerPacket(new BlockActorDataPacket());
		static::registerPacket(new PlayerInputPacket());
		static::registerPacket(new LevelChunkPacket());
		static::registerPacket(new SetCommandsEnabledPacket());
		static::registerPacket(new SetDifficultyPacket());
		static::registerPacket(new ChangeDimensionPacket());
		static::registerPacket(new SetPlayerGameTypePacket());
		static::registerPacket(new PlayerListPacket());
		static::registerPacket(new SimpleEventPacket());
		static::registerPacket(new EventPacket());
		static::registerPacket(new SpawnExperienceOrbPacket());
		static::registerPacket(new ClientboundMapItemDataPacket());
		static::registerPacket(new MapInfoRequestPacket());
		static::registerPacket(new RequestChunkRadiusPacket());
		static::registerPacket(new ChunkRadiusUpdatedPacket());
		static::registerPacket(new ItemFrameDropItemPacket());
		static::registerPacket(new GameRulesChangedPacket());
		static::registerPacket(new CameraPacket());
		static::registerPacket(new BossEventPacket());
		static::registerPacket(new ShowCreditsPacket());
		static::registerPacket(new AvailableCommandsPacket());
		static::registerPacket(new CommandRequestPacket());
		static::registerPacket(new CommandBlockUpdatePacket());
		static::registerPacket(new CommandOutputPacket());
		static::registerPacket(new UpdateTradePacket());
		static::registerPacket(new UpdateEquipPacket());
		static::registerPacket(new ResourcePackDataInfoPacket());
		static::registerPacket(new ResourcePackChunkDataPacket());
		static::registerPacket(new ResourcePackChunkRequestPacket());
		static::registerPacket(new TransferPacket());
		static::registerPacket(new PlaySoundPacket());
		static::registerPacket(new StopSoundPacket());
		static::registerPacket(new SetTitlePacket());
		static::registerPacket(new AddBehaviorTreePacket());
		static::registerPacket(new StructureBlockUpdatePacket());
		static::registerPacket(new ShowStoreOfferPacket());
		static::registerPacket(new PurchaseReceiptPacket());
		static::registerPacket(new PlayerSkinPacket());
		static::registerPacket(new SubClientLoginPacket());
		static::registerPacket(new AutomationClientConnectPacket());
		static::registerPacket(new SetLastHurtByPacket());
		static::registerPacket(new BookEditPacket());
		static::registerPacket(new NpcRequestPacket());
		static::registerPacket(new PhotoTransferPacket());
		static::registerPacket(new ModalFormRequestPacket());
		static::registerPacket(new ModalFormResponsePacket());
		static::registerPacket(new ServerSettingsRequestPacket());
		static::registerPacket(new ServerSettingsResponsePacket());
		static::registerPacket(new ShowProfilePacket());
		static::registerPacket(new SetDefaultGameTypePacket());
		static::registerPacket(new RemoveObjectivePacket());
		static::registerPacket(new SetDisplayObjectivePacket());
		static::registerPacket(new SetScorePacket());
		static::registerPacket(new LabTablePacket());
		static::registerPacket(new UpdateBlockSyncedPacket());
		static::registerPacket(new MoveActorDeltaPacket());
		static::registerPacket(new SetScoreboardIdentityPacket());
		static::registerPacket(new SetLocalPlayerAsInitializedPacket());
		static::registerPacket(new UpdateSoftEnumPacket());
		static::registerPacket(new NetworkStackLatencyPacket());
		static::registerPacket(new ScriptCustomEventPacket());
		static::registerPacket(new SpawnParticleEffectPacket());
		static::registerPacket(new AvailableActorIdentifiersPacket());
		static::registerPacket(new LevelSoundEventPacketV2());
		static::registerPacket(new NetworkChunkPublisherUpdatePacket());
		static::registerPacket(new BiomeDefinitionListPacket());
		static::registerPacket(new LevelSoundEventPacket());
		static::registerPacket(new LevelEventGenericPacket());
		static::registerPacket(new LecternUpdatePacket());
		static::registerPacket(new VideoStreamConnectPacket());
		static::registerPacket(new AddEntityPacket());
		static::registerPacket(new RemoveEntityPacket());
		static::registerPacket(new ClientCacheStatusPacket());
		static::registerPacket(new OnScreenTextureAnimationPacket());
		static::registerPacket(new MapCreateLockedCopyPacket());
		static::registerPacket(new StructureTemplateDataRequestPacket());
		static::registerPacket(new StructureTemplateDataResponsePacket());
		static::registerPacket(new UpdateBlockPropertiesPacket());
		static::registerPacket(new ClientCacheBlobStatusPacket());
		static::registerPacket(new ClientCacheMissResponsePacket());
		static::registerPacket(new EducationSettingsPacket());
		static::registerPacket(new EmotePacket());
		static::registerPacket(new MultiplayerSettingsPacket());
		static::registerPacket(new SettingsCommandPacket());
		static::registerPacket(new AnvilDamagePacket());
		static::registerPacket(new CompletedUsingItemPacket());
		static::registerPacket(new NetworkSettingsPacket());
		static::registerPacket(new PlayerAuthInputPacket());
	}

	/**
	 * @return void
	 */
	public static function registerPacket(DataPacket $packet){
		static::$pool[$packet->pid()] = clone $packet;
	}

	public static function getPacketById(int $pid) : DataPacket{
		return isset(static::$pool[$pid]) ? clone static::$pool[$pid] : new UnknownPacket();
	}

	/**
	 * @throws BinaryDataException
	 */
	public static function getPacket(string $buffer) : DataPacket{
		$offset = 0;
		$pk = static::getPacketById(Binary::readUnsignedVarInt($buffer, $offset));
		$pk->setBuffer($buffer, $offset);

		return $pk;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\utils\BinaryStream;
use pocketmine\utils\MainLogger;
use pocketmine\utils\Utils;
use function get_class;
use function json_decode;

class LoginPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::LOGIN_PACKET;

	public const EDITION_POCKET = 0;

	/** @var string */
	public $username;
	/** @var int */
	public $protocol;
	/** @var string */
	public $clientUUID;
	/** @var int */
	public $clientId;
	/** @var string|null */
	public $xuid = null;
	/** @var string */
	public $identityPublicKey;
	/** @var string */
	public $serverAddress;
	/** @var string */
	public $locale;

	/**
	 * @var string[][] (the "chain" index contains one or more JWTs)
	 * @phpstan-var array{chain?: list<string>}
	 */
	public $chainData = [];
	/** @var string */
	public $clientDataJwt;
	/**
	 * @var mixed[] decoded payload of the clientData JWT
	 * @phpstan-var array<string, mixed>
	 */
	public $clientData = [];

	/**
	 * This field may be used by plugins to bypass keychain verification. It should only be used for plugins such as
	 * Specter where passing verification would take too much time and not be worth it.
	 *
	 * @var bool
	 */
	public $skipVerification = false;

	public function canBeSentBeforeLogin() : bool{
		return true;
	}

	public function mayHaveUnreadBytes() : bool{
		return $this->protocol !== null and $this->protocol !== ProtocolInfo::CURRENT_PROTOCOL;
	}

	protected function decodePayload(){
		$this->protocol = ((\unpack("N", $this->get(4))[1] << 32 >> 32));

		try{
			$this->decodeConnectionRequest();
		}catch(\Throwable $e){
			if($this->protocol === ProtocolInfo::CURRENT_PROTOCOL){
				throw $e;
			}

			$logger = MainLogger::getLogger();
			$logger->debug(get_class($e) . " was thrown while decoding connection request in login (protocol version " . ($this->protocol ?? "unknown") . "): " . $e->getMessage());
			foreach(Utils::printableTrace($e->getTrace()) as $line){
				$logger->debug($line);
			}
		}
	}

	protected function decodeConnectionRequest() : void{
		$buffer = new BinaryStream($this->getString());

		$this->chainData = json_decode($buffer->get($buffer->getLInt()), true);

		$hasExtraData = false;
		foreach($this->chainData["chain"] as $chain){
			$webtoken = Utils::decodeJWT($chain);
			if(isset($webtoken["extraData"])){
				if($hasExtraData){
					throw new \RuntimeException("Found 'extraData' multiple times in key chain");
				}
				$hasExtraData = true;
				if(isset($webtoken["extraData"]["displayName"])){
					$this->username = $webtoken["extraData"]["displayName"];
				}
				if(isset($webtoken["extraData"]["identity"])){
					$this->clientUUID = $webtoken["extraData"]["identity"];
				}
				if(isset($webtoken["extraData"]["XUID"])){
					$this->xuid = $webtoken["extraData"]["XUID"];
				}
			}

			if(isset($webtoken["identityPublicKey"])){
				$this->identityPublicKey = $webtoken["identityPublicKey"];
			}
		}

		$this->clientDataJwt = $buffer->get($buffer->getLInt());
		$this->clientData = Utils::decodeJWT($this->clientDataJwt);

		$this->clientId = $this->clientData["ClientRandomId"] ?? null;
		$this->serverAddress = $this->clientData["ServerAddress"] ?? null;

		$this->locale = $this->clientData["LanguageCode"] ?? null;
	}

	protected function encodePayload(){
		//TODO
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleLogin($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\CachedEncapsulatedPacket;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\utils\Utils;
use function bin2hex;
use function get_class;
use function is_object;
use function is_string;
use function method_exists;

abstract class DataPacket extends NetworkBinaryStream{

	public const NETWORK_ID = 0;

	/** @var bool */
	public $isEncoded = false;
	/** @var CachedEncapsulatedPacket|null */
	public $__encapsulatedPacket = null;

	/** @var int */
	public $senderSubId = 0;
	/** @var int */
	public $recipientSubId = 0;

	/**
	 * @return int
	 */
	public function pid(){
		return $this::NETWORK_ID;
	}

	public function getName() : string{
		return (new \ReflectionClass($this))->getShortName();
	}

	public function canBeBatched() : bool{
		return true;
	}

	public function canBeSentBeforeLogin() : bool{
		return false;
	}

	/**
	 * Returns whether the packet may legally have unread bytes left in the buffer.
	 */
	public function mayHaveUnreadBytes() : bool{
		return false;
	}

	/**
	 * @return void
	 * @throws \OutOfBoundsException
	 * @throws \UnexpectedValueException
	 */
	public function decode(){
		$this->offset = 0;
		$this->decodeHeader();
		$this->decodePayload();
	}

	/**
	 * @return void
	 * @throws \OutOfBoundsException
	 * @throws \UnexpectedValueException
	 */
	protected function decodeHeader(){
		$pid = $this->getUnsignedVarInt();
		if($pid !== static::NETWORK_ID){
			throw new \UnexpectedValueException("Expected " . static::NETWORK_ID . " for packet ID, got $pid");
		}
	}

	/**
	 * Note for plugin developers: If you're adding your own packets, you should perform decoding in here.
	 *
	 * @return void
	 * @throws \OutOfBoundsException
	 * @throws \UnexpectedValueException
	 */
	protected function decodePayload(){

	}

	/**
	 * @return void
	 */
	public function encode(){
		$this->reset();
		$this->encodeHeader();
		$this->encodePayload();
		$this->isEncoded = true;
	}

	/**
	 * @return void
	 */
	protected function encodeHeader(){
		$this->putUnsignedVarInt(static::NETWORK_ID);
	}

	/**
	 * Note for plugin developers: If you're adding your own packets, you should perform encoding in here.
	 *
	 * @return void
	 */
	protected function encodePayload(){

	}

	/**
	 * Performs handling for this packet. Usually you'll want an appropriately named method in the NetworkSession for this.
	 *
	 * This method returns a bool to indicate whether the packet was handled or not. If the packet was unhandled, a debug message will be logged with a hexdump of the packet.
	 * Typically this method returns the return value of the handler in the supplied NetworkSession. See other packets for examples how to implement this.
	 *
	 * @return bool true if the packet was handled successfully, false if not.
	 */
	abstract public function handle(NetworkSession $session) : bool;

	/**
	 * @return $this
	 */
	public function clean(){
		$this->buffer = "";
		$this->isEncoded = false;
		$this->offset = 0;
		return $this;
	}

	/**
	 * @return mixed[]
	 */
	public function __debugInfo(){
		$data = [];
		foreach((array) $this as $k => $v){
			if($k === "buffer" and is_string($v)){
				$data[$k] = bin2hex($v);
			}elseif(is_string($v) or (is_object($v) and method_exists($v, "__toString"))){
				$data[$k] = Utils::printable((string) $v);
			}else{
				$data[$k] = $v;
			}
		}

		return $data;
	}

	/**
	 * @param string $name
	 *
	 * @return mixed
	 */
	public function __get($name){
		throw new \Error("Undefined property: " . get_class($this) . "::\$" . $name);
	}

	/**
	 * @param string $name
	 * @param mixed  $value
	 *
	 * @return void
	 */
	public function __set($name, $value){
		throw new \Error("Undefined property: " . get_class($this) . "::\$" . $name);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe;

use pocketmine\utils\Binary;

use pocketmine\entity\Attribute;
use pocketmine\entity\Entity;
use pocketmine\entity\Skin;
use pocketmine\item\Durable;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\ItemIds;
use pocketmine\math\Vector3;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\SkinImage;
use pocketmine\network\mcpe\protocol\types\StructureSettings;
use pocketmine\utils\BinaryStream;
use pocketmine\utils\UUID;
use function count;
use function strlen;

class NetworkBinaryStream extends BinaryStream{

	private const DAMAGE_TAG = "Damage"; //TAG_Int
	private const DAMAGE_TAG_CONFLICT_RESOLUTION = "___Damage_ProtocolCollisionResolution___";

	public function getString() : string{
		return $this->get($this->getUnsignedVarInt());
	}

	public function putString(string $v) : void{
		$this->putUnsignedVarInt(strlen($v));
		($this->buffer .= $v);
	}

	public function getUUID() : UUID{
		//This is actually two little-endian longs: UUID Most followed by UUID Least
		$part1 = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$part0 = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$part3 = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$part2 = ((\unpack("V", $this->get(4))[1] << 32 >> 32));

		return new UUID($part0, $part1, $part2, $part3);
	}

	public function putUUID(UUID $uuid) : void{
		($this->buffer .= (\pack("V", $uuid->getPart(1))));
		($this->buffer .= (\pack("V", $uuid->getPart(0))));
		($this->buffer .= (\pack("V", $uuid->getPart(3))));
		($this->buffer .= (\pack("V", $uuid->getPart(2))));
	}

	public function getSkin() : SkinData{
		$skinId = $this->getString();
		$skinResourcePatch = $this->getString();
		$skinData = $this->getSkinImage();
		$animationCount = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$animations = [];
		for($i = 0; $i < $animationCount; ++$i){
			$animations[] = new SkinAnimation(
				$skinImage = $this->getSkinImage(),
				$animationType = ((\unpack("V", $this->get(4))[1] << 32 >> 32)),
				$animationFrames = ((\unpack("g", $this->get(4))[1]))
			);
		}
		$capeData = $this->getSkinImage();
		$geometryData = $this->getString();
		$animationData = $this->getString();
		$premium = (($this->get(1) !== "\x00"));
		$persona = (($this->get(1) !== "\x00"));
		$capeOnClassic = (($this->get(1) !== "\x00"));
		$capeId = $this->getString();
		$fullSkinId = $this->getString();

		return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId);
	}

	/**
	 * @return void
	 */
	public function putSkin(SkinData $skin){
		$this->putString($skin->getSkinId());
		$this->putString($skin->getResourcePatch());
		$this->putSkinImage($skin->getSkinImage());
		($this->buffer .= (\pack("V", count($skin->getAnimations()))));
		foreach($skin->getAnimations() as $animation){
			$this->putSkinImage($animation->getImage());
			($this->buffer .= (\pack("V", $animation->getType())));
			($this->buffer .= (\pack("g", $animation->getFrames())));
		}
		$this->putSkinImage($skin->getCapeImage());
		$this->putString($skin->getGeometryData());
		$this->putString($skin->getAnimationData());
		($this->buffer .= ($skin->isPremium() ? "\x01" : "\x00"));
		($this->buffer .= ($skin->isPersona() ? "\x01" : "\x00"));
		($this->buffer .= ($skin->isPersonaCapeOnClassic() ? "\x01" : "\x00"));
		$this->putString($skin->getCapeId());

		//this has to be unique or the client will do stupid things
		$this->putString(UUID::fromRandom()->toString()); //full skin ID
	}

	private function getSkinImage() : SkinImage{
		$width = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$height = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$data = $this->getString();
		return new SkinImage($height, $width, $data);
	}

	private function putSkinImage(SkinImage $image) : void{
		($this->buffer .= (\pack("V", $image->getWidth())));
		($this->buffer .= (\pack("V", $image->getHeight())));
		$this->putString($image->getData());
	}

	public function getSlot() : Item{
		$id = $this->getVarInt();
		if($id === 0){
			return ItemFactory::get(0, 0, 0);
		}

		$auxValue = $this->getVarInt();
		$data = $auxValue >> 8;
		$cnt = $auxValue & 0xff;

		$nbtLen = ((\unpack("v", $this->get(2))[1]));

		/** @var CompoundTag|null $nbt */
		$nbt = null;
		if($nbtLen === 0xffff){
			$c = (\ord($this->get(1)));
			if($c !== 1){
				throw new \UnexpectedValueException("Unexpected NBT count $c");
			}
			$decodedNBT = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
			if(!($decodedNBT instanceof CompoundTag)){
				throw new \UnexpectedValueException("Unexpected root tag type for itemstack");
			}
			$nbt = $decodedNBT;
		}elseif($nbtLen !== 0){
			throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen");
		}

		//TODO
		for($i = 0, $canPlaceOn = $this->getVarInt(); $i < $canPlaceOn; ++$i){
			$this->getString();
		}

		//TODO
		for($i = 0, $canDestroy = $this->getVarInt(); $i < $canDestroy; ++$i){
			$this->getString();
		}

		if($id === ItemIds::SHIELD){
			$this->getVarLong(); //"blocking tick" (ffs mojang)
		}
		if($nbt !== null){
			if($nbt->hasTag(self::DAMAGE_TAG, IntTag::class)){
				$data = $nbt->getInt(self::DAMAGE_TAG);
				$nbt->removeTag(self::DAMAGE_TAG);
				if($nbt->count() === 0){
					$nbt = null;
					goto end;
				}
			}
			if(($conflicted = $nbt->getTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION)) !== null){
				$nbt->removeTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
				$conflicted->setName(self::DAMAGE_TAG);
				$nbt->setTag($conflicted);
			}
		}
		end:
		return ItemFactory::get($id, $data, $cnt, $nbt);
	}

	public function putSlot(Item $item) : void{
		if($item->getId() === 0){
			$this->putVarInt(0);

			return;
		}

		$this->putVarInt($item->getId());
		$auxValue = (($item->getDamage() & 0x7fff) << 8) | $item->getCount();
		$this->putVarInt($auxValue);

		$nbt = null;
		if($item->hasCompoundTag()){
			$nbt = clone $item->getNamedTag();
		}
		if($item instanceof Durable and $item->getDamage() > 0){
			if($nbt !== null){
				if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){
					$nbt->removeTag(self::DAMAGE_TAG);
					$existing->setName(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
					$nbt->setTag($existing);
				}
			}else{
				$nbt = new CompoundTag();
			}
			$nbt->setInt(self::DAMAGE_TAG, $item->getDamage());
		}

		if($nbt !== null){
			($this->buffer .= (\pack("v", 0xffff)));
			($this->buffer .= \chr(1)); //TODO: some kind of count field? always 1 as of 1.9.0
			($this->buffer .= (new NetworkLittleEndianNBTStream())->write($nbt));
		}else{
			($this->buffer .= (\pack("v", 0)));
		}

		$this->putVarInt(0); //CanPlaceOn entry count (TODO)
		$this->putVarInt(0); //CanDestroy entry count (TODO)

		if($item->getId() === ItemIds::SHIELD){
			$this->putVarLong(0); //"blocking tick" (ffs mojang)
		}
	}

	public function getRecipeIngredient() : Item{
		$id = $this->getVarInt();
		if($id === 0){
			return ItemFactory::get(ItemIds::AIR, 0, 0);
		}
		$meta = $this->getVarInt();
		if($meta === 0x7fff){
			$meta = -1;
		}
		$count = $this->getVarInt();
		return ItemFactory::get($id, $meta, $count);
	}

	public function putRecipeIngredient(Item $item) : void{
		if($item->isNull()){
			$this->putVarInt(0);
		}else{
			$this->putVarInt($item->getId());
			$this->putVarInt($item->getDamage() & 0x7fff);
			$this->putVarInt($item->getCount());
		}
	}

	/**
	 * Decodes entity metadata from the stream.
	 *
	 * @param bool $types Whether to include metadata types along with values in the returned array
	 *
	 * @return mixed[]|mixed[][]
	 * @phpstan-return array<int, mixed>|array<int, array{0: int, 1: mixed}>
	 */
	public function getEntityMetadata(bool $types = true) : array{
		$count = $this->getUnsignedVarInt();
		$data = [];
		for($i = 0; $i < $count; ++$i){
			$key = $this->getUnsignedVarInt();
			$type = $this->getUnsignedVarInt();
			$value = null;
			switch($type){
				case Entity::DATA_TYPE_BYTE:
					$value = (\ord($this->get(1)));
					break;
				case Entity::DATA_TYPE_SHORT:
					$value = ((\unpack("v", $this->get(2))[1] << 48 >> 48));
					break;
				case Entity::DATA_TYPE_INT:
					$value = $this->getVarInt();
					break;
				case Entity::DATA_TYPE_FLOAT:
					$value = ((\unpack("g", $this->get(4))[1]));
					break;
				case Entity::DATA_TYPE_STRING:
					$value = $this->getString();
					break;
				case Entity::DATA_TYPE_COMPOUND_TAG:
					$value = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
					break;
				case Entity::DATA_TYPE_POS:
					$value = new Vector3();
					$this->getSignedBlockPosition($value->x, $value->y, $value->z);
					break;
				case Entity::DATA_TYPE_LONG:
					$value = $this->getVarLong();
					break;
				case Entity::DATA_TYPE_VECTOR3F:
					$value = $this->getVector3();
					break;
				default:
					throw new \UnexpectedValueException("Invalid data type " . $type);
			}
			if($types){
				$data[$key] = [$type, $value];
			}else{
				$data[$key] = $value;
			}
		}

		return $data;
	}

	/**
	 * Writes entity metadata to the packet buffer.
	 *
	 * @param mixed[][] $metadata
	 * @phpstan-param array<int, array{0: int, 1: mixed}> $metadata
	 */
	public function putEntityMetadata(array $metadata) : void{
		$this->putUnsignedVarInt(count($metadata));
		foreach($metadata as $key => $d){
			$this->putUnsignedVarInt($key); //data key
			$this->putUnsignedVarInt($d[0]); //data type
			switch($d[0]){
				case Entity::DATA_TYPE_BYTE:
					($this->buffer .= \chr($d[1]));
					break;
				case Entity::DATA_TYPE_SHORT:
					($this->buffer .= (\pack("v", $d[1]))); //SIGNED short!
					break;
				case Entity::DATA_TYPE_INT:
					$this->putVarInt($d[1]);
					break;
				case Entity::DATA_TYPE_FLOAT:
					($this->buffer .= (\pack("g", $d[1])));
					break;
				case Entity::DATA_TYPE_STRING:
					$this->putString($d[1]);
					break;
				case Entity::DATA_TYPE_COMPOUND_TAG:
					($this->buffer .= (new NetworkLittleEndianNBTStream())->write($d[1]));
					break;
				case Entity::DATA_TYPE_POS:
					$v = $d[1];
					if($v !== null){
						$this->putSignedBlockPosition($v->x, $v->y, $v->z);
					}else{
						$this->putSignedBlockPosition(0, 0, 0);
					}
					break;
				case Entity::DATA_TYPE_LONG:
					$this->putVarLong($d[1]);
					break;
				case Entity::DATA_TYPE_VECTOR3F:
					$this->putVector3Nullable($d[1]);
					break;
				default:
					throw new \UnexpectedValueException("Invalid data type " . $d[0]);
			}
		}
	}

	/**
	 * Reads a list of Attributes from the stream.
	 * @return Attribute[]
	 *
	 * @throws \UnexpectedValueException if reading an attribute with an unrecognized name
	 */
	public function getAttributeList() : array{
		$list = [];
		$count = $this->getUnsignedVarInt();

		for($i = 0; $i < $count; ++$i){
			$min = ((\unpack("g", $this->get(4))[1]));
			$max = ((\unpack("g", $this->get(4))[1]));
			$current = ((\unpack("g", $this->get(4))[1]));
			$default = ((\unpack("g", $this->get(4))[1]));
			$name = $this->getString();

			$attr = Attribute::getAttributeByName($name);
			if($attr !== null){
				$attr->setMinValue($min);
				$attr->setMaxValue($max);
				$attr->setValue($current);
				$attr->setDefaultValue($default);

				$list[] = $attr;
			}else{
				throw new \UnexpectedValueException("Unknown attribute type \"$name\"");
			}
		}

		return $list;
	}

	/**
	 * Writes a list of Attributes to the packet buffer using the standard format.
	 *
	 * @param Attribute ...$attributes
	 */
	public function putAttributeList(Attribute ...$attributes) : void{
		$this->putUnsignedVarInt(count($attributes));
		foreach($attributes as $attribute){
			($this->buffer .= (\pack("g", $attribute->getMinValue())));
			($this->buffer .= (\pack("g", $attribute->getMaxValue())));
			($this->buffer .= (\pack("g", $attribute->getValue())));
			($this->buffer .= (\pack("g", $attribute->getDefaultValue())));
			$this->putString($attribute->getName());
		}
	}

	/**
	 * Reads and returns an EntityUniqueID
	 */
	public function getEntityUniqueId() : int{
		return $this->getVarLong();
	}

	/**
	 * Writes an EntityUniqueID
	 */
	public function putEntityUniqueId(int $eid) : void{
		$this->putVarLong($eid);
	}

	/**
	 * Reads and returns an EntityRuntimeID
	 */
	public function getEntityRuntimeId() : int{
		return $this->getUnsignedVarLong();
	}

	/**
	 * Writes an EntityRuntimeID
	 */
	public function putEntityRuntimeId(int $eid) : void{
		$this->putUnsignedVarLong($eid);
	}

	/**
	 * Reads an block position with unsigned Y coordinate.
	 *
	 * @param int $x reference parameter
	 * @param int $y reference parameter
	 * @param int $z reference parameter
	 */
	public function getBlockPosition(&$x, &$y, &$z) : void{
		$x = $this->getVarInt();
		$y = $this->getUnsignedVarInt();
		$z = $this->getVarInt();
	}

	/**
	 * Writes a block position with unsigned Y coordinate.
	 */
	public function putBlockPosition(int $x, int $y, int $z) : void{
		$this->putVarInt($x);
		$this->putUnsignedVarInt($y);
		$this->putVarInt($z);
	}

	/**
	 * Reads a block position with a signed Y coordinate.
	 *
	 * @param int $x reference parameter
	 * @param int $y reference parameter
	 * @param int $z reference parameter
	 */
	public function getSignedBlockPosition(&$x, &$y, &$z) : void{
		$x = $this->getVarInt();
		$y = $this->getVarInt();
		$z = $this->getVarInt();
	}

	/**
	 * Writes a block position with a signed Y coordinate.
	 */
	public function putSignedBlockPosition(int $x, int $y, int $z) : void{
		$this->putVarInt($x);
		$this->putVarInt($y);
		$this->putVarInt($z);
	}

	/**
	 * Reads a floating-point Vector3 object with coordinates rounded to 4 decimal places.
	 */
	public function getVector3() : Vector3{
		return new Vector3(
			((\round((\unpack("g", $this->get(4))[1]),  4))),
			((\round((\unpack("g", $this->get(4))[1]),  4))),
			((\round((\unpack("g", $this->get(4))[1]),  4)))
		);
	}

	/**
	 * Writes a floating-point Vector3 object, or 3x zero if null is given.
	 *
	 * Note: ONLY use this where it is reasonable to allow not specifying the vector.
	 * For all other purposes, use the non-nullable version.
	 *
	 * @see NetworkBinaryStream::putVector3()
	 */
	public function putVector3Nullable(?Vector3 $vector) : void{
		if($vector !== null){
			$this->putVector3($vector);
		}else{
			($this->buffer .= (\pack("g", 0.0)));
			($this->buffer .= (\pack("g", 0.0)));
			($this->buffer .= (\pack("g", 0.0)));
		}
	}

	/**
	 * Writes a floating-point Vector3 object
	 */
	public function putVector3(Vector3 $vector) : void{
		($this->buffer .= (\pack("g", $vector->x)));
		($this->buffer .= (\pack("g", $vector->y)));
		($this->buffer .= (\pack("g", $vector->z)));
	}

	public function getByteRotation() : float{
		return ((\ord($this->get(1))) * (360 / 256));
	}

	public function putByteRotation(float $rotation) : void{
		($this->buffer .= \chr((int) ($rotation / (360 / 256))));
	}

	/**
	 * Reads gamerules
	 * TODO: implement this properly
	 *
	 * @return mixed[][], members are in the structure [name => [type, value]]
	 * @phpstan-return array<string, array{0: int, 1: bool|int|float}>
	 */
	public function getGameRules() : array{
		$count = $this->getUnsignedVarInt();
		$rules = [];
		for($i = 0; $i < $count; ++$i){
			$name = $this->getString();
			$type = $this->getUnsignedVarInt();
			$value = null;
			switch($type){
				case 1:
					$value = (($this->get(1) !== "\x00"));
					break;
				case 2:
					$value = $this->getUnsignedVarInt();
					break;
				case 3:
					$value = ((\unpack("g", $this->get(4))[1]));
					break;
			}

			$rules[$name] = [$type, $value];
		}

		return $rules;
	}

	/**
	 * Writes a gamerule array, members should be in the structure [name => [type, value]]
	 * TODO: implement this properly
	 *
	 * @param mixed[][] $rules
	 * @phpstan-param array<string, array{0: int, 1: bool|int|float}> $rules
	 */
	public function putGameRules(array $rules) : void{
		$this->putUnsignedVarInt(count($rules));
		foreach($rules as $name => $rule){
			$this->putString($name);
			$this->putUnsignedVarInt($rule[0]);
			switch($rule[0]){
				case 1:
					($this->buffer .= ($rule[1] ? "\x01" : "\x00"));
					break;
				case 2:
					$this->putUnsignedVarInt($rule[1]);
					break;
				case 3:
					($this->buffer .= (\pack("g", $rule[1])));
					break;
			}
		}
	}

	protected function getEntityLink() : EntityLink{
		$link = new EntityLink();

		$link->fromEntityUniqueId = $this->getEntityUniqueId();
		$link->toEntityUniqueId = $this->getEntityUniqueId();
		$link->type = (\ord($this->get(1)));
		$link->immediate = (($this->get(1) !== "\x00"));

		return $link;
	}

	protected function putEntityLink(EntityLink $link) : void{
		$this->putEntityUniqueId($link->fromEntityUniqueId);
		$this->putEntityUniqueId($link->toEntityUniqueId);
		($this->buffer .= \chr($link->type));
		($this->buffer .= ($link->immediate ? "\x01" : "\x00"));
	}

	protected function getCommandOriginData() : CommandOriginData{
		$result = new CommandOriginData();

		$result->type = $this->getUnsignedVarInt();
		$result->uuid = $this->getUUID();
		$result->requestId = $this->getString();

		if($result->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $result->type === CommandOriginData::ORIGIN_TEST){
			$result->varlong1 = $this->getVarLong();
		}

		return $result;
	}

	protected function putCommandOriginData(CommandOriginData $data) : void{
		$this->putUnsignedVarInt($data->type);
		$this->putUUID($data->uuid);
		$this->putString($data->requestId);

		if($data->type === CommandOriginData::ORIGIN_DEV_CONSOLE or $data->type === CommandOriginData::ORIGIN_TEST){
			$this->putVarLong($data->varlong1);
		}
	}

	protected function getStructureSettings() : StructureSettings{
		$result = new StructureSettings();

		$result->paletteName = $this->getString();

		$result->ignoreEntities = (($this->get(1) !== "\x00"));
		$result->ignoreBlocks = (($this->get(1) !== "\x00"));

		$this->getBlockPosition($result->structureSizeX, $result->structureSizeY, $result->structureSizeZ);
		$this->getBlockPosition($result->structureOffsetX, $result->structureOffsetY, $result->structureOffsetZ);

		$result->lastTouchedByPlayerID = $this->getEntityUniqueId();
		$result->rotation = (\ord($this->get(1)));
		$result->mirror = (\ord($this->get(1)));
		$result->integrityValue = ((\unpack("G", $this->get(4))[1]));
		$result->integritySeed = ((\unpack("N", $this->get(4))[1] << 32 >> 32));

		return $result;
	}

	protected function putStructureSettings(StructureSettings $structureSettings) : void{
		$this->putString($structureSettings->paletteName);

		($this->buffer .= ($structureSettings->ignoreEntities ? "\x01" : "\x00"));
		($this->buffer .= ($structureSettings->ignoreBlocks ? "\x01" : "\x00"));

		$this->putBlockPosition($structureSettings->structureSizeX, $structureSettings->structureSizeY, $structureSettings->structureSizeZ);
		$this->putBlockPosition($structureSettings->structureOffsetX, $structureSettings->structureOffsetY, $structureSettings->structureOffsetZ);

		$this->putEntityUniqueId($structureSettings->lastTouchedByPlayerID);
		($this->buffer .= \chr($structureSettings->rotation));
		($this->buffer .= \chr($structureSettings->mirror));
		($this->buffer .= (\pack("G", $structureSettings->integrityValue)));
		($this->buffer .= (\pack("N", $structureSettings->integritySeed)));
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;


use function chr;
use function ord;
use function strlen;
use function substr;

class BinaryStream{

	/** @var int */
	public $offset;
	/** @var string */
	public $buffer;

	public function __construct(string $buffer = "", int $offset = 0){
		$this->buffer = $buffer;
		$this->offset = $offset;
	}

	/**
	 * @return void
	 */
	public function reset(){
		$this->buffer = "";
		$this->offset = 0;
	}

	/**
	 * Rewinds the stream pointer to the start.
	 */
	public function rewind() : void{
		$this->offset = 0;
	}

	public function setOffset(int $offset) : void{
		$this->offset = $offset;
	}

	/**
	 * @return void
	 */
	public function setBuffer(string $buffer = "", int $offset = 0){
		$this->buffer = $buffer;
		$this->offset = $offset;
	}

	public function getOffset() : int{
		return $this->offset;
	}

	public function getBuffer() : string{
		return $this->buffer;
	}

	/**
	 * @param int|true $len
	 *
	 * @return string
	 *
	 * @throws BinaryDataException if there are not enough bytes left in the buffer
	 */
	public function get($len) : string{
		if($len === 0){
			return "";
		}

		$buflen = strlen($this->buffer);
		if($len === true){
			$str = substr($this->buffer, $this->offset);
			$this->offset = $buflen;
			return $str;
		}
		if($len < 0){
			$this->offset = $buflen - 1;
			return "";
		}
		$remaining = $buflen - $this->offset;
		if($remaining < $len){
			throw new BinaryDataException("Not enough bytes left in buffer: need $len, have $remaining");
		}

		return $len === 1 ? $this->buffer[$this->offset++] : substr($this->buffer, ($this->offset += $len) - $len, $len);
	}

	/**
	 * @return string
	 * @throws BinaryDataException
	 */
	public function getRemaining() : string{
		$buflen = strlen($this->buffer);
		if($this->offset >= $buflen){
			throw new BinaryDataException("No bytes left to read");
		}
		$str = substr($this->buffer, $this->offset);
		$this->offset = $buflen;
		return $str;
	}

	/**
	 * @return void
	 */
	public function put(string $str){
		$this->buffer .= $str;
	}


	public function getBool() : bool{
		return $this->get(1) !== "\x00";
	}

	/**
	 * @return void
	 */
	public function putBool(bool $v){
		$this->buffer .= ($v ? "\x01" : "\x00");
	}


	public function getByte() : int{
		return ord($this->get(1));
	}

	/**
	 * @return void
	 */
	public function putByte(int $v){
		$this->buffer .= chr($v);
	}


	public function getShort() : int{
		return (\unpack("n", $this->get(2))[1]);
	}

	public function getSignedShort() : int{
		return (\unpack("n", $this->get(2))[1] << 48 >> 48);
	}

	/**
	 * @return void
	 */
	public function putShort(int $v){
		$this->buffer .= (\pack("n", $v));
	}

	public function getLShort() : int{
		return (\unpack("v", $this->get(2))[1]);
	}

	public function getSignedLShort() : int{
		return (\unpack("v", $this->get(2))[1] << 48 >> 48);
	}

	/**
	 * @return void
	 */
	public function putLShort(int $v){
		$this->buffer .= (\pack("v", $v));
	}


	public function getTriad() : int{
		return (\unpack("N", "\x00" . $this->get(3))[1]);
	}

	/**
	 * @return void
	 */
	public function putTriad(int $v){
		$this->buffer .= (\substr(\pack("N", $v), 1));
	}

	public function getLTriad() : int{
		return (\unpack("V", $this->get(3) . "\x00")[1]);
	}

	/**
	 * @return void
	 */
	public function putLTriad(int $v){
		$this->buffer .= (\substr(\pack("V", $v), 0, -1));
	}


	public function getInt() : int{
		return (\unpack("N", $this->get(4))[1] << 32 >> 32);
	}

	/**
	 * @return void
	 */
	public function putInt(int $v){
		$this->buffer .= (\pack("N", $v));
	}

	public function getLInt() : int{
		return (\unpack("V", $this->get(4))[1] << 32 >> 32);
	}

	/**
	 * @return void
	 */
	public function putLInt(int $v){
		$this->buffer .= (\pack("V", $v));
	}


	public function getFloat() : float{
		return (\unpack("G", $this->get(4))[1]);
	}

	public function getRoundedFloat(int $accuracy) : float{
		return (\round((\unpack("G", $this->get(4))[1]),  $accuracy));
	}

	/**
	 * @return void
	 */
	public function putFloat(float $v){
		$this->buffer .= (\pack("G", $v));
	}

	public function getLFloat() : float{
		return (\unpack("g", $this->get(4))[1]);
	}

	public function getRoundedLFloat(int $accuracy) : float{
		return (\round((\unpack("g", $this->get(4))[1]),  $accuracy));
	}

	/**
	 * @return void
	 */
	public function putLFloat(float $v){
		$this->buffer .= (\pack("g", $v));
	}

	public function getDouble() : float{
		return (\unpack("E", $this->get(8))[1]);
	}

	public function putDouble(float $v) : void{
		$this->buffer .= (\pack("E", $v));
	}

	public function getLDouble() : float{
		return (\unpack("e", $this->get(8))[1]);
	}

	public function putLDouble(float $v) : void{
		$this->buffer .= (\pack("e", $v));
	}

	/**
	 * @return int
	 */
	public function getLong() : int{
		return Binary::readLong($this->get(8));
	}

	/**
	 * @param int $v
	 *
	 * @return void
	 */
	public function putLong(int $v){
		$this->buffer .= (\pack("NN", $v >> 32, $v & 0xFFFFFFFF));
	}

	/**
	 * @return int
	 */
	public function getLLong() : int{
		return Binary::readLLong($this->get(8));
	}

	/**
	 * @param int $v
	 *
	 * @return void
	 */
	public function putLLong(int $v){
		$this->buffer .= (\pack("VV", $v & 0xFFFFFFFF, $v >> 32));
	}

	/**
	 * Reads a 32-bit variable-length unsigned integer from the buffer and returns it.
	 * @return int
	 */
	public function getUnsignedVarInt() : int{
		return Binary::readUnsignedVarInt($this->buffer, $this->offset);
	}

	/**
	 * Writes a 32-bit variable-length unsigned integer to the end of the buffer.
	 * @param int $v
	 *
	 * @return void
	 */
	public function putUnsignedVarInt(int $v){
		($this->buffer .= Binary::writeUnsignedVarInt($v));
	}

	/**
	 * Reads a 32-bit zigzag-encoded variable-length integer from the buffer and returns it.
	 * @return int
	 */
	public function getVarInt() : int{
		return Binary::readVarInt($this->buffer, $this->offset);
	}

	/**
	 * Writes a 32-bit zigzag-encoded variable-length integer to the end of the buffer.
	 * @param int $v
	 *
	 * @return void
	 */
	public function putVarInt(int $v){
		($this->buffer .= Binary::writeVarInt($v));
	}

	/**
	 * Reads a 64-bit variable-length integer from the buffer and returns it.
	 * @return int
	 */
	public function getUnsignedVarLong() : int{
		return Binary::readUnsignedVarLong($this->buffer, $this->offset);
	}

	/**
	 * Writes a 64-bit variable-length integer to the end of the buffer.
	 * @param int $v
	 *
	 * @return void
	 */
	public function putUnsignedVarLong(int $v){
		$this->buffer .= Binary::writeUnsignedVarLong($v);
	}

	/**
	 * Reads a 64-bit zigzag-encoded variable-length integer from the buffer and returns it.
	 * @return int
	 */
	public function getVarLong() : int{
		return Binary::readVarLong($this->buffer, $this->offset);
	}

	/**
	 * Writes a 64-bit zigzag-encoded variable-length integer to the end of the buffer.
	 * @param int $v
	 *
	 * @return void
	 */
	public function putVarLong(int $v){
		$this->buffer .= Binary::writeVarLong($v);
	}

	/**
	 * Returns whether the offset has reached the end of the buffer.
	 * @return bool
	 */
	public function feof() : bool{
		return !isset($this->buffer[$this->offset]);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class PlayStatusPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::PLAY_STATUS_PACKET;

	public const LOGIN_SUCCESS = 0;
	public const LOGIN_FAILED_CLIENT = 1;
	public const LOGIN_FAILED_SERVER = 2;
	public const PLAYER_SPAWN = 3;
	public const LOGIN_FAILED_INVALID_TENANT = 4;
	public const LOGIN_FAILED_VANILLA_EDU = 5;
	public const LOGIN_FAILED_EDU_VANILLA = 6;
	public const LOGIN_FAILED_SERVER_FULL = 7;

	/** @var int */
	public $status;

	protected function decodePayload(){
		$this->status = ((\unpack("N", $this->get(4))[1] << 32 >> 32));
	}

	public function canBeSentBeforeLogin() : bool{
		return true;
	}

	protected function encodePayload(){
		($this->buffer .= (\pack("N", $this->status)));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handlePlayStatus($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ServerToClientHandshakePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SERVER_TO_CLIENT_HANDSHAKE_PACKET;

	/**
	 * @var string
	 * Server pubkey and token is contained in the JWT.
	 */
	public $jwt;

	public function canBeSentBeforeLogin() : bool{
		return true;
	}

	protected function decodePayload(){
		$this->jwt = $this->getString();
	}

	protected function encodePayload(){
		$this->putString($this->jwt);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleServerToClientHandshake($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ClientToServerHandshakePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CLIENT_TO_SERVER_HANDSHAKE_PACKET;

	public function canBeSentBeforeLogin() : bool{
		return true;
	}

	protected function decodePayload(){
		//No payload
	}

	protected function encodePayload(){
		//No payload
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleClientToServerHandshake($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class DisconnectPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::DISCONNECT_PACKET;

	/** @var bool */
	public $hideDisconnectionScreen = false;
	/** @var string */
	public $message = "";

	public function canBeSentBeforeLogin() : bool{
		return true;
	}

	protected function decodePayload(){
		$this->hideDisconnectionScreen = (($this->get(1) !== "\x00"));
		if(!$this->hideDisconnectionScreen){
			$this->message = $this->getString();
		}
	}

	protected function encodePayload(){
		($this->buffer .= ($this->hideDisconnectionScreen ? "\x01" : "\x00"));
		if(!$this->hideDisconnectionScreen){
			$this->putString($this->message);
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleDisconnect($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\resourcepacks\ResourcePack;
use function count;

class ResourcePacksInfoPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::RESOURCE_PACKS_INFO_PACKET;

	/** @var bool */
	public $mustAccept = false; //if true, forces client to use selected resource packs
	/** @var bool */
	public $hasScripts = false; //if true, causes disconnect for any platform that doesn't support scripts yet
	/** @var ResourcePack[] */
	public $behaviorPackEntries = [];
	/** @var ResourcePack[] */
	public $resourcePackEntries = [];

	protected function decodePayload(){
		$this->mustAccept = (($this->get(1) !== "\x00"));
		$this->hasScripts = (($this->get(1) !== "\x00"));
		$behaviorPackCount = ((\unpack("v", $this->get(2))[1]));
		while($behaviorPackCount-- > 0){
			$this->getString();
			$this->getString();
			(Binary::readLLong($this->get(8)));
			$this->getString();
			$this->getString();
			$this->getString();
			(($this->get(1) !== "\x00"));
		}

		$resourcePackCount = ((\unpack("v", $this->get(2))[1]));
		while($resourcePackCount-- > 0){
			$this->getString();
			$this->getString();
			(Binary::readLLong($this->get(8)));
			$this->getString();
			$this->getString();
			$this->getString();
			(($this->get(1) !== "\x00"));
		}
	}

	protected function encodePayload(){
		($this->buffer .= ($this->mustAccept ? "\x01" : "\x00"));
		($this->buffer .= ($this->hasScripts ? "\x01" : "\x00"));
		($this->buffer .= (\pack("v", count($this->behaviorPackEntries))));
		foreach($this->behaviorPackEntries as $entry){
			$this->putString($entry->getPackId());
			$this->putString($entry->getPackVersion());
			($this->buffer .= (\pack("VV", $entry->getPackSize() & 0xFFFFFFFF, $entry->getPackSize() >> 32)));
			$this->putString(""); //TODO: encryption key
			$this->putString(""); //TODO: subpack name
			$this->putString(""); //TODO: content identity
			($this->buffer .= (false ? "\x01" : "\x00")); //TODO: has scripts (?)
		}
		($this->buffer .= (\pack("v", count($this->resourcePackEntries))));
		foreach($this->resourcePackEntries as $entry){
			$this->putString($entry->getPackId());
			$this->putString($entry->getPackVersion());
			($this->buffer .= (\pack("VV", $entry->getPackSize() & 0xFFFFFFFF, $entry->getPackSize() >> 32)));
			$this->putString(""); //TODO: encryption key
			$this->putString(""); //TODO: subpack name
			$this->putString(""); //TODO: content identity
			($this->buffer .= (false ? "\x01" : "\x00")); //TODO: seems useless for resource packs
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleResourcePacksInfo($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\resourcepacks\ResourcePack;
use function count;

class ResourcePackStackPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::RESOURCE_PACK_STACK_PACKET;

	/** @var bool */
	public $mustAccept = false;

	/** @var ResourcePack[] */
	public $behaviorPackStack = [];
	/** @var ResourcePack[] */
	public $resourcePackStack = [];

	/** @var bool */
	public $isExperimental = false;
	/** @var string */
	public $baseGameVersion = ProtocolInfo::MINECRAFT_VERSION_NETWORK;

	protected function decodePayload(){
		$this->mustAccept = (($this->get(1) !== "\x00"));
		$behaviorPackCount = $this->getUnsignedVarInt();
		while($behaviorPackCount-- > 0){
			$this->getString();
			$this->getString();
			$this->getString();
		}

		$resourcePackCount = $this->getUnsignedVarInt();
		while($resourcePackCount-- > 0){
			$this->getString();
			$this->getString();
			$this->getString();
		}

		$this->isExperimental = (($this->get(1) !== "\x00"));
		$this->baseGameVersion = $this->getString();
	}

	protected function encodePayload(){
		($this->buffer .= ($this->mustAccept ? "\x01" : "\x00"));

		$this->putUnsignedVarInt(count($this->behaviorPackStack));
		foreach($this->behaviorPackStack as $entry){
			$this->putString($entry->getPackId());
			$this->putString($entry->getPackVersion());
			$this->putString(""); //TODO: subpack name
		}

		$this->putUnsignedVarInt(count($this->resourcePackStack));
		foreach($this->resourcePackStack as $entry){
			$this->putString($entry->getPackId());
			$this->putString($entry->getPackVersion());
			$this->putString(""); //TODO: subpack name
		}

		($this->buffer .= ($this->isExperimental ? "\x01" : "\x00"));
		$this->putString($this->baseGameVersion);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleResourcePackStack($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use function count;

class ResourcePackClientResponsePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::RESOURCE_PACK_CLIENT_RESPONSE_PACKET;

	public const STATUS_REFUSED = 1;
	public const STATUS_SEND_PACKS = 2;
	public const STATUS_HAVE_ALL_PACKS = 3;
	public const STATUS_COMPLETED = 4;

	/** @var int */
	public $status;
	/** @var string[] */
	public $packIds = [];

	protected function decodePayload(){
		$this->status = (\ord($this->get(1)));
		$entryCount = ((\unpack("v", $this->get(2))[1]));
		while($entryCount-- > 0){
			$this->packIds[] = $this->getString();
		}
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->status));
		($this->buffer .= (\pack("v", count($this->packIds))));
		foreach($this->packIds as $id){
			$this->putString($id);
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleResourcePackClientResponse($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use function count;

class TextPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::TEXT_PACKET;

	public const TYPE_RAW = 0;
	public const TYPE_CHAT = 1;
	public const TYPE_TRANSLATION = 2;
	public const TYPE_POPUP = 3;
	public const TYPE_JUKEBOX_POPUP = 4;
	public const TYPE_TIP = 5;
	public const TYPE_SYSTEM = 6;
	public const TYPE_WHISPER = 7;
	public const TYPE_ANNOUNCEMENT = 8;
	public const TYPE_JSON = 9;

	/** @var int */
	public $type;
	/** @var bool */
	public $needsTranslation = false;
	/** @var string */
	public $sourceName;
	/** @var string */
	public $message;
	/** @var string[] */
	public $parameters = [];
	/** @var string */
	public $xboxUserId = "";
	/** @var string */
	public $platformChatId = "";

	protected function decodePayload(){
		$this->type = (\ord($this->get(1)));
		$this->needsTranslation = (($this->get(1) !== "\x00"));
		switch($this->type){
			case self::TYPE_CHAT:
			case self::TYPE_WHISPER:
			/** @noinspection PhpMissingBreakStatementInspection */
			case self::TYPE_ANNOUNCEMENT:
				$this->sourceName = $this->getString();
			case self::TYPE_RAW:
			case self::TYPE_TIP:
			case self::TYPE_SYSTEM:
			case self::TYPE_JSON:
				$this->message = $this->getString();
				break;

			case self::TYPE_TRANSLATION:
			case self::TYPE_POPUP:
			case self::TYPE_JUKEBOX_POPUP:
				$this->message = $this->getString();
				$count = $this->getUnsignedVarInt();
				for($i = 0; $i < $count; ++$i){
					$this->parameters[] = $this->getString();
				}
				break;
		}

		$this->xboxUserId = $this->getString();
		$this->platformChatId = $this->getString();
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->type));
		($this->buffer .= ($this->needsTranslation ? "\x01" : "\x00"));
		switch($this->type){
			case self::TYPE_CHAT:
			case self::TYPE_WHISPER:
			/** @noinspection PhpMissingBreakStatementInspection */
			case self::TYPE_ANNOUNCEMENT:
				$this->putString($this->sourceName);
			case self::TYPE_RAW:
			case self::TYPE_TIP:
			case self::TYPE_SYSTEM:
			case self::TYPE_JSON:
				$this->putString($this->message);
				break;

			case self::TYPE_TRANSLATION:
			case self::TYPE_POPUP:
			case self::TYPE_JUKEBOX_POPUP:
				$this->putString($this->message);
				$this->putUnsignedVarInt(count($this->parameters));
				foreach($this->parameters as $p){
					$this->putString($p);
				}
				break;
		}

		$this->putString($this->xboxUserId);
		$this->putString($this->platformChatId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleText($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetTimePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_TIME_PACKET;

	/** @var int */
	public $time;

	protected function decodePayload(){
		$this->time = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->time);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetTime($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
use function count;
use function file_get_contents;
use function json_decode;
use const pocketmine\RESOURCE_PATH;

class StartGamePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::START_GAME_PACKET;

	/** @var string|null */
	private static $blockTableCache = null;
	/** @var string|null */
	private static $itemTableCache = null;

	/** @var int */
	public $entityUniqueId;
	/** @var int */
	public $entityRuntimeId;
	/** @var int */
	public $playerGamemode;

	/** @var Vector3 */
	public $playerPosition;

	/** @var float */
	public $pitch;
	/** @var float */
	public $yaw;

	/** @var int */
	public $seed;
	/** @var int */
	public $dimension;
	/** @var int */
	public $generator = 1; //default infinite - 0 old, 1 infinite, 2 flat
	/** @var int */
	public $worldGamemode;
	/** @var int */
	public $difficulty;
	/** @var int */
	public $spawnX;
	/** @var int */
	public $spawnY;
	/** @var int */
	public $spawnZ;
	/** @var bool */
	public $hasAchievementsDisabled = true;
	/** @var int */
	public $time = -1;
	/** @var int */
	public $eduEditionOffer = 0;
	/** @var bool */
	public $hasEduFeaturesEnabled = false;
	/** @var float */
	public $rainLevel;
	/** @var float */
	public $lightningLevel;
	/** @var bool */
	public $hasConfirmedPlatformLockedContent = false;
	/** @var bool */
	public $isMultiplayerGame = true;
	/** @var bool */
	public $hasLANBroadcast = true;
	/** @var int */
	public $xboxLiveBroadcastMode = 0; //TODO: find values
	/** @var int */
	public $platformBroadcastMode = 0;
	/** @var bool */
	public $commandsEnabled;
	/** @var bool */
	public $isTexturePacksRequired = true;
	/**
	 * @var mixed[][]
	 * @phpstan-var array<string, array{0: int, 1: bool|int|float}>
	 */
	public $gameRules = [ //TODO: implement this
		"naturalregeneration" => [1, false] //Hack for client side regeneration
	];
	/** @var bool */
	public $hasBonusChestEnabled = false;
	/** @var bool */
	public $hasStartWithMapEnabled = false;
	/** @var int */
	public $defaultPlayerPermission = PlayerPermissions::MEMBER; //TODO

	/** @var int */
	public $serverChunkTickRadius = 4; //TODO (leave as default for now)

	/** @var bool */
	public $hasLockedBehaviorPack = false;
	/** @var bool */
	public $hasLockedResourcePack = false;
	/** @var bool */
	public $isFromLockedWorldTemplate = false;
	/** @var bool */
	public $useMsaGamertagsOnly = false;
	/** @var bool */
	public $isFromWorldTemplate = false;
	/** @var bool */
	public $isWorldTemplateOptionLocked = false;
	/** @var bool */
	public $onlySpawnV1Villagers = false;

	/** @var string */
	public $vanillaVersion = ProtocolInfo::MINECRAFT_VERSION_NETWORK;
	/** @var string */
	public $levelId = ""; //base64 string, usually the same as world folder name in vanilla
	/** @var string */
	public $worldName;
	/** @var string */
	public $premiumWorldTemplateId = "";
	/** @var bool */
	public $isTrial = false;
	/** @var bool */
	public $isMovementServerAuthoritative = false;
	/** @var int */
	public $currentTick = 0; //only used if isTrial is true
	/** @var int */
	public $enchantmentSeed = 0;
	/** @var string */
	public $multiplayerCorrelationId = ""; //TODO: this should be filled with a UUID of some sort

	/** @var ListTag|null */
	public $blockTable = null;
	/**
	 * @var int[]|null string (name) => int16 (legacyID)
	 * @phpstan-var array<string, int>|null
	 */
	public $itemTable = null;

	protected function decodePayload(){
		$this->entityUniqueId = $this->getEntityUniqueId();
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->playerGamemode = $this->getVarInt();

		$this->playerPosition = $this->getVector3();

		$this->pitch = ((\unpack("g", $this->get(4))[1]));
		$this->yaw = ((\unpack("g", $this->get(4))[1]));

		//Level settings
		$this->seed = $this->getVarInt();
		$this->dimension = $this->getVarInt();
		$this->generator = $this->getVarInt();
		$this->worldGamemode = $this->getVarInt();
		$this->difficulty = $this->getVarInt();
		$this->getBlockPosition($this->spawnX, $this->spawnY, $this->spawnZ);
		$this->hasAchievementsDisabled = (($this->get(1) !== "\x00"));
		$this->time = $this->getVarInt();
		$this->eduEditionOffer = $this->getVarInt();
		$this->hasEduFeaturesEnabled = (($this->get(1) !== "\x00"));
		$this->rainLevel = ((\unpack("g", $this->get(4))[1]));
		$this->lightningLevel = ((\unpack("g", $this->get(4))[1]));
		$this->hasConfirmedPlatformLockedContent = (($this->get(1) !== "\x00"));
		$this->isMultiplayerGame = (($this->get(1) !== "\x00"));
		$this->hasLANBroadcast = (($this->get(1) !== "\x00"));
		$this->xboxLiveBroadcastMode = $this->getVarInt();
		$this->platformBroadcastMode = $this->getVarInt();
		$this->commandsEnabled = (($this->get(1) !== "\x00"));
		$this->isTexturePacksRequired = (($this->get(1) !== "\x00"));
		$this->gameRules = $this->getGameRules();
		$this->hasBonusChestEnabled = (($this->get(1) !== "\x00"));
		$this->hasStartWithMapEnabled = (($this->get(1) !== "\x00"));
		$this->defaultPlayerPermission = $this->getVarInt();
		$this->serverChunkTickRadius = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$this->hasLockedBehaviorPack = (($this->get(1) !== "\x00"));
		$this->hasLockedResourcePack = (($this->get(1) !== "\x00"));
		$this->isFromLockedWorldTemplate = (($this->get(1) !== "\x00"));
		$this->useMsaGamertagsOnly = (($this->get(1) !== "\x00"));
		$this->isFromWorldTemplate = (($this->get(1) !== "\x00"));
		$this->isWorldTemplateOptionLocked = (($this->get(1) !== "\x00"));
		$this->onlySpawnV1Villagers = (($this->get(1) !== "\x00"));

		$this->vanillaVersion = $this->getString();
		$this->levelId = $this->getString();
		$this->worldName = $this->getString();
		$this->premiumWorldTemplateId = $this->getString();
		$this->isTrial = (($this->get(1) !== "\x00"));
		$this->isMovementServerAuthoritative = (($this->get(1) !== "\x00"));
		$this->currentTick = (Binary::readLLong($this->get(8)));

		$this->enchantmentSeed = $this->getVarInt();

		$blockTable = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
		if(!($blockTable instanceof ListTag)){
			throw new \UnexpectedValueException("Wrong block table root NBT tag type");
		}
		$this->blockTable = $blockTable;

		$this->itemTable = [];
		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$id = $this->getString();
			$legacyId = ((\unpack("v", $this->get(2))[1] << 48 >> 48));

			$this->itemTable[$id] = $legacyId;
		}

		$this->multiplayerCorrelationId = $this->getString();
	}

	protected function encodePayload(){
		$this->putEntityUniqueId($this->entityUniqueId);
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putVarInt($this->playerGamemode);

		$this->putVector3($this->playerPosition);

		($this->buffer .= (\pack("g", $this->pitch)));
		($this->buffer .= (\pack("g", $this->yaw)));

		//Level settings
		$this->putVarInt($this->seed);
		$this->putVarInt($this->dimension);
		$this->putVarInt($this->generator);
		$this->putVarInt($this->worldGamemode);
		$this->putVarInt($this->difficulty);
		$this->putBlockPosition($this->spawnX, $this->spawnY, $this->spawnZ);
		($this->buffer .= ($this->hasAchievementsDisabled ? "\x01" : "\x00"));
		$this->putVarInt($this->time);
		$this->putVarInt($this->eduEditionOffer);
		($this->buffer .= ($this->hasEduFeaturesEnabled ? "\x01" : "\x00"));
		($this->buffer .= (\pack("g", $this->rainLevel)));
		($this->buffer .= (\pack("g", $this->lightningLevel)));
		($this->buffer .= ($this->hasConfirmedPlatformLockedContent ? "\x01" : "\x00"));
		($this->buffer .= ($this->isMultiplayerGame ? "\x01" : "\x00"));
		($this->buffer .= ($this->hasLANBroadcast ? "\x01" : "\x00"));
		$this->putVarInt($this->xboxLiveBroadcastMode);
		$this->putVarInt($this->platformBroadcastMode);
		($this->buffer .= ($this->commandsEnabled ? "\x01" : "\x00"));
		($this->buffer .= ($this->isTexturePacksRequired ? "\x01" : "\x00"));
		$this->putGameRules($this->gameRules);
		($this->buffer .= ($this->hasBonusChestEnabled ? "\x01" : "\x00"));
		($this->buffer .= ($this->hasStartWithMapEnabled ? "\x01" : "\x00"));
		$this->putVarInt($this->defaultPlayerPermission);
		($this->buffer .= (\pack("V", $this->serverChunkTickRadius)));
		($this->buffer .= ($this->hasLockedBehaviorPack ? "\x01" : "\x00"));
		($this->buffer .= ($this->hasLockedResourcePack ? "\x01" : "\x00"));
		($this->buffer .= ($this->isFromLockedWorldTemplate ? "\x01" : "\x00"));
		($this->buffer .= ($this->useMsaGamertagsOnly ? "\x01" : "\x00"));
		($this->buffer .= ($this->isFromWorldTemplate ? "\x01" : "\x00"));
		($this->buffer .= ($this->isWorldTemplateOptionLocked ? "\x01" : "\x00"));
		($this->buffer .= ($this->onlySpawnV1Villagers ? "\x01" : "\x00"));

		$this->putString($this->vanillaVersion);
		$this->putString($this->levelId);
		$this->putString($this->worldName);
		$this->putString($this->premiumWorldTemplateId);
		($this->buffer .= ($this->isTrial ? "\x01" : "\x00"));
		($this->buffer .= ($this->isMovementServerAuthoritative ? "\x01" : "\x00"));
		($this->buffer .= (\pack("VV", $this->currentTick & 0xFFFFFFFF, $this->currentTick >> 32)));

		$this->putVarInt($this->enchantmentSeed);

		if($this->blockTable === null){
			if(self::$blockTableCache === null){
				//this is a really nasty hack, but it'll do for now
				self::$blockTableCache = (new NetworkLittleEndianNBTStream())->write(new ListTag("", RuntimeBlockMapping::getBedrockKnownStates()));
			}
			($this->buffer .= self::$blockTableCache);
		}else{
			($this->buffer .= (new NetworkLittleEndianNBTStream())->write($this->blockTable));
		}
		if($this->itemTable === null){
			if(self::$itemTableCache === null){
				self::$itemTableCache = self::serializeItemTable(json_decode(file_get_contents(RESOURCE_PATH . '/vanilla/item_id_map.json'), true));
			}
			($this->buffer .= self::$itemTableCache);
		}else{
			($this->buffer .= self::serializeItemTable($this->itemTable));
		}

		$this->putString($this->multiplayerCorrelationId);
	}

	/**
	 * @param int[] $table
	 * @phpstan-param array<string, int> $table
	 */
	private static function serializeItemTable(array $table) : string{
		$stream = new NetworkBinaryStream();
		$stream->putUnsignedVarInt(count($table));
		foreach($table as $name => $legacyId){
			$stream->putString($name);
			$stream->putLShort($legacyId);
		}
		return $stream->getBuffer();
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleStartGame($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

interface PlayerPermissions{

	public const CUSTOM = 3;
	public const OPERATOR = 2;
	public const MEMBER = 1;
	public const VISITOR = 0;

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\utils\UUID;
use function count;

class AddPlayerPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ADD_PLAYER_PACKET;

	/** @var UUID */
	public $uuid;
	/** @var string */
	public $username;
	/** @var int|null */
	public $entityUniqueId = null; //TODO
	/** @var int */
	public $entityRuntimeId;
	/** @var string */
	public $platformChatId = "";
	/** @var Vector3 */
	public $position;
	/** @var Vector3|null */
	public $motion;
	/** @var float */
	public $pitch = 0.0;
	/** @var float */
	public $yaw = 0.0;
	/** @var float|null */
	public $headYaw = null; //TODO
	/** @var Item */
	public $item;
	/**
	 * @var mixed[][]
	 * @phpstan-var array<int, array{0: int, 1: mixed}>
	 */
	public $metadata = [];

	//TODO: adventure settings stuff
	/** @var int */
	public $uvarint1 = 0;
	/** @var int */
	public $uvarint2 = 0;
	/** @var int */
	public $uvarint3 = 0;
	/** @var int */
	public $uvarint4 = 0;
	/** @var int */
	public $uvarint5 = 0;

	/** @var int */
	public $long1 = 0;

	/** @var EntityLink[] */
	public $links = [];

	/** @var string */
	public $deviceId = ""; //TODO: fill player's device ID (???)
	/** @var int */
	public $buildPlatform = -1;

	protected function decodePayload(){
		$this->uuid = $this->getUUID();
		$this->username = $this->getString();
		$this->entityUniqueId = $this->getEntityUniqueId();
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->platformChatId = $this->getString();
		$this->position = $this->getVector3();
		$this->motion = $this->getVector3();
		$this->pitch = ((\unpack("g", $this->get(4))[1]));
		$this->yaw = ((\unpack("g", $this->get(4))[1]));
		$this->headYaw = ((\unpack("g", $this->get(4))[1]));
		$this->item = $this->getSlot();
		$this->metadata = $this->getEntityMetadata();

		$this->uvarint1 = $this->getUnsignedVarInt();
		$this->uvarint2 = $this->getUnsignedVarInt();
		$this->uvarint3 = $this->getUnsignedVarInt();
		$this->uvarint4 = $this->getUnsignedVarInt();
		$this->uvarint5 = $this->getUnsignedVarInt();

		$this->long1 = (Binary::readLLong($this->get(8)));

		$linkCount = $this->getUnsignedVarInt();
		for($i = 0; $i < $linkCount; ++$i){
			$this->links[$i] = $this->getEntityLink();
		}

		$this->deviceId = $this->getString();
		$this->buildPlatform = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
	}

	protected function encodePayload(){
		$this->putUUID($this->uuid);
		$this->putString($this->username);
		$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putString($this->platformChatId);
		$this->putVector3($this->position);
		$this->putVector3Nullable($this->motion);
		($this->buffer .= (\pack("g", $this->pitch)));
		($this->buffer .= (\pack("g", $this->yaw)));
		($this->buffer .= (\pack("g", $this->headYaw ?? $this->yaw)));
		$this->putSlot($this->item);
		$this->putEntityMetadata($this->metadata);

		$this->putUnsignedVarInt($this->uvarint1);
		$this->putUnsignedVarInt($this->uvarint2);
		$this->putUnsignedVarInt($this->uvarint3);
		$this->putUnsignedVarInt($this->uvarint4);
		$this->putUnsignedVarInt($this->uvarint5);

		($this->buffer .= (\pack("VV", $this->long1 & 0xFFFFFFFF, $this->long1 >> 32)));

		$this->putUnsignedVarInt(count($this->links));
		foreach($this->links as $link){
			$this->putEntityLink($link);
		}

		$this->putString($this->deviceId);
		($this->buffer .= (\pack("V", $this->buildPlatform)));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAddPlayer($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\entity\Attribute;
use pocketmine\entity\EntityIds;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use function array_search;
use function count;

class AddActorPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ADD_ACTOR_PACKET;

	/*
	 * Really really really really really nasty hack, to preserve backwards compatibility.
	 * We can't transition to string IDs within 3.x because the network IDs (the integer ones) are exposed
	 * to the API in some places (for god's sake shoghi).
	 *
	 * TODO: remove this on 4.0
	 */
	public const LEGACY_ID_MAP_BC = [
		EntityIds::NPC => "minecraft:npc",
		EntityIds::PLAYER => "minecraft:player",
		EntityIds::WITHER_SKELETON => "minecraft:wither_skeleton",
		EntityIds::HUSK => "minecraft:husk",
		EntityIds::STRAY => "minecraft:stray",
		EntityIds::WITCH => "minecraft:witch",
		EntityIds::ZOMBIE_VILLAGER => "minecraft:zombie_villager",
		EntityIds::BLAZE => "minecraft:blaze",
		EntityIds::MAGMA_CUBE => "minecraft:magma_cube",
		EntityIds::GHAST => "minecraft:ghast",
		EntityIds::CAVE_SPIDER => "minecraft:cave_spider",
		EntityIds::SILVERFISH => "minecraft:silverfish",
		EntityIds::ENDERMAN => "minecraft:enderman",
		EntityIds::SLIME => "minecraft:slime",
		EntityIds::ZOMBIE_PIGMAN => "minecraft:zombie_pigman",
		EntityIds::SPIDER => "minecraft:spider",
		EntityIds::SKELETON => "minecraft:skeleton",
		EntityIds::CREEPER => "minecraft:creeper",
		EntityIds::ZOMBIE => "minecraft:zombie",
		EntityIds::SKELETON_HORSE => "minecraft:skeleton_horse",
		EntityIds::MULE => "minecraft:mule",
		EntityIds::DONKEY => "minecraft:donkey",
		EntityIds::DOLPHIN => "minecraft:dolphin",
		EntityIds::TROPICALFISH => "minecraft:tropicalfish",
		EntityIds::WOLF => "minecraft:wolf",
		EntityIds::SQUID => "minecraft:squid",
		EntityIds::DROWNED => "minecraft:drowned",
		EntityIds::SHEEP => "minecraft:sheep",
		EntityIds::MOOSHROOM => "minecraft:mooshroom",
		EntityIds::PANDA => "minecraft:panda",
		EntityIds::SALMON => "minecraft:salmon",
		EntityIds::PIG => "minecraft:pig",
		EntityIds::VILLAGER => "minecraft:villager",
		EntityIds::COD => "minecraft:cod",
		EntityIds::PUFFERFISH => "minecraft:pufferfish",
		EntityIds::COW => "minecraft:cow",
		EntityIds::CHICKEN => "minecraft:chicken",
		EntityIds::BALLOON => "minecraft:balloon",
		EntityIds::LLAMA => "minecraft:llama",
		EntityIds::IRON_GOLEM => "minecraft:iron_golem",
		EntityIds::RABBIT => "minecraft:rabbit",
		EntityIds::SNOW_GOLEM => "minecraft:snow_golem",
		EntityIds::BAT => "minecraft:bat",
		EntityIds::OCELOT => "minecraft:ocelot",
		EntityIds::HORSE => "minecraft:horse",
		EntityIds::CAT => "minecraft:cat",
		EntityIds::POLAR_BEAR => "minecraft:polar_bear",
		EntityIds::ZOMBIE_HORSE => "minecraft:zombie_horse",
		EntityIds::TURTLE => "minecraft:turtle",
		EntityIds::PARROT => "minecraft:parrot",
		EntityIds::GUARDIAN => "minecraft:guardian",
		EntityIds::ELDER_GUARDIAN => "minecraft:elder_guardian",
		EntityIds::VINDICATOR => "minecraft:vindicator",
		EntityIds::WITHER => "minecraft:wither",
		EntityIds::ENDER_DRAGON => "minecraft:ender_dragon",
		EntityIds::SHULKER => "minecraft:shulker",
		EntityIds::ENDERMITE => "minecraft:endermite",
		EntityIds::MINECART => "minecraft:minecart",
		EntityIds::HOPPER_MINECART => "minecraft:hopper_minecart",
		EntityIds::TNT_MINECART => "minecraft:tnt_minecart",
		EntityIds::CHEST_MINECART => "minecraft:chest_minecart",
		EntityIds::COMMAND_BLOCK_MINECART => "minecraft:command_block_minecart",
		EntityIds::ARMOR_STAND => "minecraft:armor_stand",
		EntityIds::ITEM => "minecraft:item",
		EntityIds::TNT => "minecraft:tnt",
		EntityIds::FALLING_BLOCK => "minecraft:falling_block",
		EntityIds::XP_BOTTLE => "minecraft:xp_bottle",
		EntityIds::XP_ORB => "minecraft:xp_orb",
		EntityIds::EYE_OF_ENDER_SIGNAL => "minecraft:eye_of_ender_signal",
		EntityIds::ENDER_CRYSTAL => "minecraft:ender_crystal",
		EntityIds::SHULKER_BULLET => "minecraft:shulker_bullet",
		EntityIds::FISHING_HOOK => "minecraft:fishing_hook",
		EntityIds::DRAGON_FIREBALL => "minecraft:dragon_fireball",
		EntityIds::ARROW => "minecraft:arrow",
		EntityIds::SNOWBALL => "minecraft:snowball",
		EntityIds::EGG => "minecraft:egg",
		EntityIds::PAINTING => "minecraft:painting",
		EntityIds::THROWN_TRIDENT => "minecraft:thrown_trident",
		EntityIds::FIREBALL => "minecraft:fireball",
		EntityIds::SPLASH_POTION => "minecraft:splash_potion",
		EntityIds::ENDER_PEARL => "minecraft:ender_pearl",
		EntityIds::LEASH_KNOT => "minecraft:leash_knot",
		EntityIds::WITHER_SKULL => "minecraft:wither_skull",
		EntityIds::WITHER_SKULL_DANGEROUS => "minecraft:wither_skull_dangerous",
		EntityIds::BOAT => "minecraft:boat",
		EntityIds::LIGHTNING_BOLT => "minecraft:lightning_bolt",
		EntityIds::SMALL_FIREBALL => "minecraft:small_fireball",
		EntityIds::LLAMA_SPIT => "minecraft:llama_spit",
		EntityIds::AREA_EFFECT_CLOUD => "minecraft:area_effect_cloud",
		EntityIds::LINGERING_POTION => "minecraft:lingering_potion",
		EntityIds::FIREWORKS_ROCKET => "minecraft:fireworks_rocket",
		EntityIds::EVOCATION_FANG => "minecraft:evocation_fang",
		EntityIds::EVOCATION_ILLAGER => "minecraft:evocation_illager",
		EntityIds::VEX => "minecraft:vex",
		EntityIds::AGENT => "minecraft:agent",
		EntityIds::ICE_BOMB => "minecraft:ice_bomb",
		EntityIds::PHANTOM => "minecraft:phantom",
		EntityIds::TRIPOD_CAMERA => "minecraft:tripod_camera"
	];

	/** @var int|null */
	public $entityUniqueId = null; //TODO
	/** @var int */
	public $entityRuntimeId;
	/** @var int */
	public $type;
	/** @var Vector3 */
	public $position;
	/** @var Vector3|null */
	public $motion;
	/** @var float */
	public $pitch = 0.0;
	/** @var float */
	public $yaw = 0.0;
	/** @var float */
	public $headYaw = 0.0;

	/** @var Attribute[] */
	public $attributes = [];
	/**
	 * @var mixed[][]
	 * @phpstan-var array<int, array{0: int, 1: mixed}>
	 */
	public $metadata = [];
	/** @var EntityLink[] */
	public $links = [];

	protected function decodePayload(){
		$this->entityUniqueId = $this->getEntityUniqueId();
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->type = array_search($t = $this->getString(), self::LEGACY_ID_MAP_BC, true);
		if($this->type === false){
			throw new \UnexpectedValueException("Can't map ID $t to legacy ID");
		}
		$this->position = $this->getVector3();
		$this->motion = $this->getVector3();
		$this->pitch = ((\unpack("g", $this->get(4))[1]));
		$this->yaw = ((\unpack("g", $this->get(4))[1]));
		$this->headYaw = ((\unpack("g", $this->get(4))[1]));

		$attrCount = $this->getUnsignedVarInt();
		for($i = 0; $i < $attrCount; ++$i){
			$name = $this->getString();
			$min = ((\unpack("g", $this->get(4))[1]));
			$current = ((\unpack("g", $this->get(4))[1]));
			$max = ((\unpack("g", $this->get(4))[1]));
			$attr = Attribute::getAttributeByName($name);

			if($attr !== null){
				$attr->setMinValue($min);
				$attr->setMaxValue($max);
				$attr->setValue($current);
				$this->attributes[] = $attr;
			}else{
				throw new \UnexpectedValueException("Unknown attribute type \"$name\"");
			}
		}

		$this->metadata = $this->getEntityMetadata();
		$linkCount = $this->getUnsignedVarInt();
		for($i = 0; $i < $linkCount; ++$i){
			$this->links[] = $this->getEntityLink();
		}
	}

	protected function encodePayload(){
		$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
		$this->putEntityRuntimeId($this->entityRuntimeId);
		if(!isset(self::LEGACY_ID_MAP_BC[$this->type])){
			throw new \InvalidArgumentException("Unknown entity numeric ID $this->type");
		}
		$this->putString(self::LEGACY_ID_MAP_BC[$this->type]);
		$this->putVector3($this->position);
		$this->putVector3Nullable($this->motion);
		($this->buffer .= (\pack("g", $this->pitch)));
		($this->buffer .= (\pack("g", $this->yaw)));
		($this->buffer .= (\pack("g", $this->headYaw)));

		$this->putUnsignedVarInt(count($this->attributes));
		foreach($this->attributes as $attribute){
			$this->putString($attribute->getName());
			($this->buffer .= (\pack("g", $attribute->getMinValue())));
			($this->buffer .= (\pack("g", $attribute->getValue())));
			($this->buffer .= (\pack("g", $attribute->getMaxValue())));
		}

		$this->putEntityMetadata($this->metadata);
		$this->putUnsignedVarInt(count($this->links));
		foreach($this->links as $link){
			$this->putEntityLink($link);
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAddActor($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

interface EntityIds{

	public const CHICKEN = 10;
	public const COW = 11;
	public const PIG = 12;
	public const SHEEP = 13;
	public const WOLF = 14;
	public const VILLAGER = 15;
	public const MOOSHROOM = 16;
	public const SQUID = 17;
	public const RABBIT = 18;
	public const BAT = 19;
	public const IRON_GOLEM = 20;
	public const SNOW_GOLEM = 21;
	public const OCELOT = 22;
	public const HORSE = 23;
	public const DONKEY = 24;
	public const MULE = 25;
	public const SKELETON_HORSE = 26;
	public const ZOMBIE_HORSE = 27;
	public const POLAR_BEAR = 28;
	public const LLAMA = 29;
	public const PARROT = 30;
	public const DOLPHIN = 31;
	public const ZOMBIE = 32;
	public const CREEPER = 33;
	public const SKELETON = 34;
	public const SPIDER = 35;
	public const ZOMBIE_PIGMAN = 36;
	public const SLIME = 37;
	public const ENDERMAN = 38;
	public const SILVERFISH = 39;
	public const CAVE_SPIDER = 40;
	public const GHAST = 41;
	public const MAGMA_CUBE = 42;
	public const BLAZE = 43;
	public const ZOMBIE_VILLAGER = 44;
	public const WITCH = 45;
	public const STRAY = 46;
	public const HUSK = 47;
	public const WITHER_SKELETON = 48;
	public const GUARDIAN = 49;
	public const ELDER_GUARDIAN = 50;
	public const NPC = 51;
	public const WITHER = 52;
	public const ENDER_DRAGON = 53;
	public const SHULKER = 54;
	public const ENDERMITE = 55;
	public const AGENT = 56, LEARN_TO_CODE_MASCOT = 56;
	public const VINDICATOR = 57;
	public const PHANTOM = 58;

	public const ARMOR_STAND = 61;
	public const TRIPOD_CAMERA = 62;
	public const PLAYER = 63;
	public const ITEM = 64;
	public const TNT = 65;
	public const FALLING_BLOCK = 66;
	public const MOVING_BLOCK = 67;
	public const XP_BOTTLE = 68;
	public const XP_ORB = 69;
	public const EYE_OF_ENDER_SIGNAL = 70;
	public const ENDER_CRYSTAL = 71;
	public const FIREWORKS_ROCKET = 72;
	public const THROWN_TRIDENT = 73, TRIDENT = 73;
	public const TURTLE = 74;
	public const CAT = 75;
	public const SHULKER_BULLET = 76;
	public const FISHING_HOOK = 77;
	public const CHALKBOARD = 78;
	public const DRAGON_FIREBALL = 79;
	public const ARROW = 80;
	public const SNOWBALL = 81;
	public const EGG = 82;
	public const PAINTING = 83;
	public const MINECART = 84;
	public const FIREBALL = 85, LARGE_FIREBALL = 85;
	public const SPLASH_POTION = 86;
	public const ENDER_PEARL = 87;
	public const LEASH_KNOT = 88;
	public const WITHER_SKULL = 89;
	public const BOAT = 90;
	public const WITHER_SKULL_DANGEROUS = 91;
	public const LIGHTNING_BOLT = 93;
	public const SMALL_FIREBALL = 94;
	public const AREA_EFFECT_CLOUD = 95;
	public const HOPPER_MINECART = 96;
	public const TNT_MINECART = 97;
	public const CHEST_MINECART = 98;

	public const COMMAND_BLOCK_MINECART = 100;
	public const LINGERING_POTION = 101;
	public const LLAMA_SPIT = 102;
	public const EVOCATION_FANG = 103;
	public const EVOCATION_ILLAGER = 104;
	public const VEX = 105;
	public const ICE_BOMB = 106;
	public const BALLOON = 107;
	public const PUFFERFISH = 108;
	public const SALMON = 109;
	public const DROWNED = 110;
	public const TROPICALFISH = 111, TROPICAL_FISH = 111;
	public const COD = 112, FISH = 112;
	public const PANDA = 113;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class RemoveActorPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::REMOVE_ACTOR_PACKET;

	/** @var int */
	public $entityUniqueId;

	protected function decodePayload(){
		$this->entityUniqueId = $this->getEntityUniqueId();
	}

	protected function encodePayload(){
		$this->putEntityUniqueId($this->entityUniqueId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleRemoveActor($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class AddItemActorPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ADD_ITEM_ACTOR_PACKET;

	/** @var int|null */
	public $entityUniqueId = null; //TODO
	/** @var int */
	public $entityRuntimeId;
	/** @var Item */
	public $item;
	/** @var Vector3 */
	public $position;
	/** @var Vector3|null */
	public $motion;
	/**
	 * @var mixed[][]
	 * @phpstan-var array<int, array{0: int, 1: mixed}>
	 */
	public $metadata = [];
	/** @var bool */
	public $isFromFishing = false;

	protected function decodePayload(){
		$this->entityUniqueId = $this->getEntityUniqueId();
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->item = $this->getSlot();
		$this->position = $this->getVector3();
		$this->motion = $this->getVector3();
		$this->metadata = $this->getEntityMetadata();
		$this->isFromFishing = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putSlot($this->item);
		$this->putVector3($this->position);
		$this->putVector3Nullable($this->motion);
		$this->putEntityMetadata($this->metadata);
		($this->buffer .= ($this->isFromFishing ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAddItemActor($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class TakeItemActorPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::TAKE_ITEM_ACTOR_PACKET;

	/** @var int */
	public $target;
	/** @var int */
	public $eid;

	protected function decodePayload(){
		$this->target = $this->getEntityRuntimeId();
		$this->eid = $this->getEntityRuntimeId();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->target);
		$this->putEntityRuntimeId($this->eid);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleTakeItemActor($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class MoveActorAbsolutePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MOVE_ACTOR_ABSOLUTE_PACKET;

	public const FLAG_GROUND = 0x01;
	public const FLAG_TELEPORT = 0x02;

	/** @var int */
	public $entityRuntimeId;
	/** @var int */
	public $flags = 0;
	/** @var Vector3 */
	public $position;
	/** @var float */
	public $xRot;
	/** @var float */
	public $yRot;
	/** @var float */
	public $zRot;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->flags = (\ord($this->get(1)));
		$this->position = $this->getVector3();
		$this->xRot = $this->getByteRotation();
		$this->yRot = $this->getByteRotation();
		$this->zRot = $this->getByteRotation();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		($this->buffer .= \chr($this->flags));
		$this->putVector3($this->position);
		$this->putByteRotation($this->xRot);
		$this->putByteRotation($this->yRot);
		$this->putByteRotation($this->zRot);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleMoveActorAbsolute($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class MovePlayerPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MOVE_PLAYER_PACKET;

	public const MODE_NORMAL = 0;
	public const MODE_RESET = 1;
	public const MODE_TELEPORT = 2;
	public const MODE_PITCH = 3; //facepalm Mojang

	/** @var int */
	public $entityRuntimeId;
	/** @var Vector3 */
	public $position;
	/** @var float */
	public $pitch;
	/** @var float */
	public $yaw;
	/** @var float */
	public $headYaw;
	/** @var int */
	public $mode = self::MODE_NORMAL;
	/** @var bool */
	public $onGround = false; //TODO
	/** @var int */
	public $ridingEid = 0;
	/** @var int */
	public $teleportCause = 0;
	/** @var int */
	public $teleportItem = 0;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->position = $this->getVector3();
		$this->pitch = ((\unpack("g", $this->get(4))[1]));
		$this->yaw = ((\unpack("g", $this->get(4))[1]));
		$this->headYaw = ((\unpack("g", $this->get(4))[1]));
		$this->mode = (\ord($this->get(1)));
		$this->onGround = (($this->get(1) !== "\x00"));
		$this->ridingEid = $this->getEntityRuntimeId();
		if($this->mode === MovePlayerPacket::MODE_TELEPORT){
			$this->teleportCause = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
			$this->teleportItem = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		}
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putVector3($this->position);
		($this->buffer .= (\pack("g", $this->pitch)));
		($this->buffer .= (\pack("g", $this->yaw)));
		($this->buffer .= (\pack("g", $this->headYaw))); //TODO
		($this->buffer .= \chr($this->mode));
		($this->buffer .= ($this->onGround ? "\x01" : "\x00"));
		$this->putEntityRuntimeId($this->ridingEid);
		if($this->mode === MovePlayerPacket::MODE_TELEPORT){
			($this->buffer .= (\pack("V", $this->teleportCause)));
			($this->buffer .= (\pack("V", $this->teleportItem)));
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleMovePlayer($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class RiderJumpPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::RIDER_JUMP_PACKET;

	/** @var int */
	public $jumpStrength; //percentage

	protected function decodePayload(){
		$this->jumpStrength = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->jumpStrength);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleRiderJump($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class UpdateBlockPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::UPDATE_BLOCK_PACKET;

	public const FLAG_NONE      = 0b0000;
	public const FLAG_NEIGHBORS = 0b0001;
	public const FLAG_NETWORK   = 0b0010;
	public const FLAG_NOGRAPHIC = 0b0100;
	public const FLAG_PRIORITY  = 0b1000;

	public const FLAG_ALL = self::FLAG_NEIGHBORS | self::FLAG_NETWORK;
	public const FLAG_ALL_PRIORITY = self::FLAG_ALL | self::FLAG_PRIORITY;

	public const DATA_LAYER_NORMAL = 0;
	public const DATA_LAYER_LIQUID = 1;

	/** @var int */
	public $x;
	/** @var int */
	public $z;
	/** @var int */
	public $y;
	/** @var int */
	public $blockRuntimeId;
	/** @var int */
	public $flags;
	/** @var int */
	public $dataLayerId = self::DATA_LAYER_NORMAL;

	protected function decodePayload(){
		$this->getBlockPosition($this->x, $this->y, $this->z);
		$this->blockRuntimeId = $this->getUnsignedVarInt();
		$this->flags = $this->getUnsignedVarInt();
		$this->dataLayerId = $this->getUnsignedVarInt();
	}

	protected function encodePayload(){
		$this->putBlockPosition($this->x, $this->y, $this->z);
		$this->putUnsignedVarInt($this->blockRuntimeId);
		$this->putUnsignedVarInt($this->flags);
		$this->putUnsignedVarInt($this->dataLayerId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleUpdateBlock($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class AddPaintingPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ADD_PAINTING_PACKET;

	/** @var int|null */
	public $entityUniqueId = null;
	/** @var int */
	public $entityRuntimeId;
	/** @var Vector3 */
	public $position;
	/** @var int */
	public $direction;
	/** @var string */
	public $title;

	protected function decodePayload(){
		$this->entityUniqueId = $this->getEntityUniqueId();
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->position = $this->getVector3();
		$this->direction = $this->getVarInt();
		$this->title = $this->getString();
	}

	protected function encodePayload(){
		$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putVector3($this->position);
		$this->putVarInt($this->direction);
		$this->putString($this->title);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAddPainting($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class TickSyncPacket extends DataPacket/* implements ClientboundPacket, ServerboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::TICK_SYNC_PACKET;

	/** @var int */
	private $clientSendTime;
	/** @var int */
	private $serverReceiveTime;

	public static function request(int $clientTime) : self{
		$result = new self;
		$result->clientSendTime = $clientTime;
		$result->serverReceiveTime = 0; //useless
		return $result;
	}

	public static function response(int $clientSendTime, int $serverReceiveTime) : self{
		$result = new self;
		$result->clientSendTime = $clientSendTime;
		$result->serverReceiveTime = $serverReceiveTime;
		return $result;
	}

	public function getClientSendTime() : int{
		return $this->clientSendTime;
	}

	public function getServerReceiveTime() : int{
		return $this->serverReceiveTime;
	}

	protected function decodePayload() : void{
		$this->clientSendTime = (Binary::readLLong($this->get(8)));
		$this->serverReceiveTime = (Binary::readLLong($this->get(8)));
	}

	protected function encodePayload() : void{
		($this->buffer .= (\pack("VV", $this->clientSendTime & 0xFFFFFFFF, $this->clientSendTime >> 32)));
		($this->buffer .= (\pack("VV", $this->serverReceiveTime & 0xFFFFFFFF, $this->serverReceiveTime >> 32)));
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleTickSync($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

/**
 * Useless leftover from a 1.8 refactor, does nothing
 */
class LevelSoundEventPacketV1 extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::LEVEL_SOUND_EVENT_PACKET_V1;

	/** @var int */
	public $sound;
	/** @var Vector3 */
	public $position;
	/** @var int */
	public $extraData = 0;
	/** @var int */
	public $entityType = 1;
	/** @var bool */
	public $isBabyMob = false; //...
	/** @var bool */
	public $disableRelativeVolume = false;

	protected function decodePayload(){
		$this->sound = (\ord($this->get(1)));
		$this->position = $this->getVector3();
		$this->extraData = $this->getVarInt();
		$this->entityType = $this->getVarInt();
		$this->isBabyMob = (($this->get(1) !== "\x00"));
		$this->disableRelativeVolume = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->sound));
		$this->putVector3($this->position);
		$this->putVarInt($this->extraData);
		$this->putVarInt($this->entityType);
		($this->buffer .= ($this->isBabyMob ? "\x01" : "\x00"));
		($this->buffer .= ($this->disableRelativeVolume ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleLevelSoundEventPacketV1($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class LevelEventPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::LEVEL_EVENT_PACKET;

	public const EVENT_SOUND_CLICK = 1000;
	public const EVENT_SOUND_CLICK_FAIL = 1001;
	public const EVENT_SOUND_SHOOT = 1002;
	public const EVENT_SOUND_DOOR = 1003;
	public const EVENT_SOUND_FIZZ = 1004;
	public const EVENT_SOUND_IGNITE = 1005;

	public const EVENT_SOUND_GHAST = 1007;
	public const EVENT_SOUND_GHAST_SHOOT = 1008;
	public const EVENT_SOUND_BLAZE_SHOOT = 1009;
	public const EVENT_SOUND_DOOR_BUMP = 1010;

	public const EVENT_SOUND_DOOR_CRASH = 1012;

	public const EVENT_SOUND_ENDERMAN_TELEPORT = 1018;

	public const EVENT_SOUND_ANVIL_BREAK = 1020;
	public const EVENT_SOUND_ANVIL_USE = 1021;
	public const EVENT_SOUND_ANVIL_FALL = 1022;

	public const EVENT_SOUND_POP = 1030;

	public const EVENT_SOUND_PORTAL = 1032;

	public const EVENT_SOUND_ITEMFRAME_ADD_ITEM = 1040;
	public const EVENT_SOUND_ITEMFRAME_REMOVE = 1041;
	public const EVENT_SOUND_ITEMFRAME_PLACE = 1042;
	public const EVENT_SOUND_ITEMFRAME_REMOVE_ITEM = 1043;
	public const EVENT_SOUND_ITEMFRAME_ROTATE_ITEM = 1044;

	public const EVENT_SOUND_CAMERA = 1050;
	public const EVENT_SOUND_ORB = 1051;
	public const EVENT_SOUND_TOTEM = 1052;

	public const EVENT_SOUND_ARMOR_STAND_BREAK = 1060;
	public const EVENT_SOUND_ARMOR_STAND_HIT = 1061;
	public const EVENT_SOUND_ARMOR_STAND_FALL = 1062;
	public const EVENT_SOUND_ARMOR_STAND_PLACE = 1063;

	//TODO: check 2000-2017
	public const EVENT_PARTICLE_SHOOT = 2000;
	public const EVENT_PARTICLE_DESTROY = 2001;
	public const EVENT_PARTICLE_SPLASH = 2002;
	public const EVENT_PARTICLE_EYE_DESPAWN = 2003;
	public const EVENT_PARTICLE_SPAWN = 2004;

	public const EVENT_GUARDIAN_CURSE = 2006;

	public const EVENT_PARTICLE_BLOCK_FORCE_FIELD = 2008;
	public const EVENT_PARTICLE_PROJECTILE_HIT = 2009;

	public const EVENT_PARTICLE_ENDERMAN_TELEPORT = 2013;
	public const EVENT_PARTICLE_PUNCH_BLOCK = 2014;

	public const EVENT_START_RAIN = 3001;
	public const EVENT_START_THUNDER = 3002;
	public const EVENT_STOP_RAIN = 3003;
	public const EVENT_STOP_THUNDER = 3004;
	public const EVENT_PAUSE_GAME = 3005; //data: 1 to pause, 0 to resume
	public const EVENT_PAUSE_GAME_NO_SCREEN = 3006; //data: 1 to pause, 0 to resume - same effect as normal pause but without screen
	public const EVENT_SET_GAME_SPEED = 3007; //x coordinate of pos = scale factor (default 1.0)

	public const EVENT_REDSTONE_TRIGGER = 3500;
	public const EVENT_CAULDRON_EXPLODE = 3501;
	public const EVENT_CAULDRON_DYE_ARMOR = 3502;
	public const EVENT_CAULDRON_CLEAN_ARMOR = 3503;
	public const EVENT_CAULDRON_FILL_POTION = 3504;
	public const EVENT_CAULDRON_TAKE_POTION = 3505;
	public const EVENT_CAULDRON_FILL_WATER = 3506;
	public const EVENT_CAULDRON_TAKE_WATER = 3507;
	public const EVENT_CAULDRON_ADD_DYE = 3508;
	public const EVENT_CAULDRON_CLEAN_BANNER = 3509;

	public const EVENT_BLOCK_START_BREAK = 3600;
	public const EVENT_BLOCK_STOP_BREAK = 3601;

	public const EVENT_SET_DATA = 4000;

	public const EVENT_PLAYERS_SLEEPING = 9800;

	public const EVENT_ADD_PARTICLE_MASK = 0x4000;

	/** @var int */
	public $evid;
	/** @var Vector3|null */
	public $position;
	/** @var int */
	public $data;

	protected function decodePayload(){
		$this->evid = $this->getVarInt();
		$this->position = $this->getVector3();
		$this->data = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->evid);
		$this->putVector3Nullable($this->position);
		$this->putVarInt($this->data);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleLevelEvent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class BlockEventPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::BLOCK_EVENT_PACKET;

	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;
	/** @var int */
	public $eventType;
	/** @var int */
	public $eventData;

	protected function decodePayload(){
		$this->getBlockPosition($this->x, $this->y, $this->z);
		$this->eventType = $this->getVarInt();
		$this->eventData = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putBlockPosition($this->x, $this->y, $this->z);
		$this->putVarInt($this->eventType);
		$this->putVarInt($this->eventData);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleBlockEvent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ActorEventPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ACTOR_EVENT_PACKET;

	public const HURT_ANIMATION = 2;
	public const DEATH_ANIMATION = 3;
	public const ARM_SWING = 4;

	public const TAME_FAIL = 6;
	public const TAME_SUCCESS = 7;
	public const SHAKE_WET = 8;
	public const USE_ITEM = 9;
	public const EAT_GRASS_ANIMATION = 10;
	public const FISH_HOOK_BUBBLE = 11;
	public const FISH_HOOK_POSITION = 12;
	public const FISH_HOOK_HOOK = 13;
	public const FISH_HOOK_TEASE = 14;
	public const SQUID_INK_CLOUD = 15;
	public const ZOMBIE_VILLAGER_CURE = 16;

	public const RESPAWN = 18;
	public const IRON_GOLEM_OFFER_FLOWER = 19;
	public const IRON_GOLEM_WITHDRAW_FLOWER = 20;
	public const LOVE_PARTICLES = 21; //breeding

	public const WITCH_SPELL_PARTICLES = 24;
	public const FIREWORK_PARTICLES = 25;

	public const SILVERFISH_SPAWN_ANIMATION = 27;

	public const WITCH_DRINK_POTION = 29;
	public const WITCH_THROW_POTION = 30;
	public const MINECART_TNT_PRIME_FUSE = 31;

	public const PLAYER_ADD_XP_LEVELS = 34;
	public const ELDER_GUARDIAN_CURSE = 35;
	public const AGENT_ARM_SWING = 36;
	public const ENDER_DRAGON_DEATH = 37;
	public const DUST_PARTICLES = 38; //not sure what this is
	public const ARROW_SHAKE = 39;

	public const EATING_ITEM = 57;

	public const BABY_ANIMAL_FEED = 60; //green particles, like bonemeal on crops
	public const DEATH_SMOKE_CLOUD = 61;
	public const COMPLETE_TRADE = 62;
	public const REMOVE_LEASH = 63; //data 1 = cut leash

	public const CONSUME_TOTEM = 65;
	public const PLAYER_CHECK_TREASURE_HUNTER_ACHIEVEMENT = 66; //mojang...
	public const ENTITY_SPAWN = 67; //used for MinecraftEventing stuff, not needed
	public const DRAGON_PUKE = 68; //they call this puke particles
	public const ITEM_ENTITY_MERGE = 69;

	//TODO: add more events

	/** @var int */
	public $entityRuntimeId;
	/** @var int */
	public $event;
	/** @var int */
	public $data = 0;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->event = (\ord($this->get(1)));
		$this->data = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		($this->buffer .= \chr($this->event));
		$this->putVarInt($this->data);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleActorEvent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class MobEffectPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MOB_EFFECT_PACKET;

	public const EVENT_ADD = 1;
	public const EVENT_MODIFY = 2;
	public const EVENT_REMOVE = 3;

	/** @var int */
	public $entityRuntimeId;
	/** @var int */
	public $eventId;
	/** @var int */
	public $effectId;
	/** @var int */
	public $amplifier = 0;
	/** @var bool */
	public $particles = true;
	/** @var int */
	public $duration = 0;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->eventId = (\ord($this->get(1)));
		$this->effectId = $this->getVarInt();
		$this->amplifier = $this->getVarInt();
		$this->particles = (($this->get(1) !== "\x00"));
		$this->duration = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		($this->buffer .= \chr($this->eventId));
		$this->putVarInt($this->effectId);
		$this->putVarInt($this->amplifier);
		($this->buffer .= ($this->particles ? "\x01" : "\x00"));
		$this->putVarInt($this->duration);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleMobEffect($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\entity\Attribute;
use pocketmine\network\mcpe\NetworkSession;

class UpdateAttributesPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::UPDATE_ATTRIBUTES_PACKET;

	/** @var int */
	public $entityRuntimeId;
	/** @var Attribute[] */
	public $entries = [];

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->entries = $this->getAttributeList();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putAttributeList(...$this->entries);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleUpdateAttributes($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
use function count;

class InventoryTransactionPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::INVENTORY_TRANSACTION_PACKET;

	public const TYPE_NORMAL = 0;
	public const TYPE_MISMATCH = 1;
	public const TYPE_USE_ITEM = 2;
	public const TYPE_USE_ITEM_ON_ENTITY = 3;
	public const TYPE_RELEASE_ITEM = 4;

	public const USE_ITEM_ACTION_CLICK_BLOCK = 0;
	public const USE_ITEM_ACTION_CLICK_AIR = 1;
	public const USE_ITEM_ACTION_BREAK_BLOCK = 2;

	public const RELEASE_ITEM_ACTION_RELEASE = 0; //bow shoot
	public const RELEASE_ITEM_ACTION_CONSUME = 1; //eat food, drink potion

	public const USE_ITEM_ON_ENTITY_ACTION_INTERACT = 0;
	public const USE_ITEM_ON_ENTITY_ACTION_ATTACK = 1;

	/** @var int */
	public $transactionType;

	/**
	 * @var bool
	 * NOTE: THIS FIELD DOES NOT EXIST IN THE PROTOCOL, it's merely used for convenience for PocketMine-MP to easily
	 * determine whether we're doing a crafting transaction.
	 */
	public $isCraftingPart = false;
	/**
	 * @var bool
	 * NOTE: THIS FIELD DOES NOT EXIST IN THE PROTOCOL, it's merely used for convenience for PocketMine-MP to easily
	 * determine whether we're doing a crafting transaction.
	 */
	public $isFinalCraftingPart = false;

	/** @var NetworkInventoryAction[] */
	public $actions = [];

	/** @var \stdClass */
	public $trData;

	protected function decodePayload(){
		$this->transactionType = $this->getUnsignedVarInt();

		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$this->actions[] = $action = (new NetworkInventoryAction())->read($this);

			if(
				$action->sourceType === NetworkInventoryAction::SOURCE_CONTAINER and
				$action->windowId === ContainerIds::UI and
				$action->inventorySlot === 50 and
				!$action->oldItem->equalsExact($action->newItem)
			){
				$this->isCraftingPart = true;
				if(!$action->oldItem->isNull() and $action->newItem->isNull()){
					$this->isFinalCraftingPart = true;
				}
			}elseif(
				$action->sourceType === NetworkInventoryAction::SOURCE_TODO and (
					$action->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT or
					$action->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_USE_INGREDIENT
				)
			){
				$this->isCraftingPart = true;
			}
		}

		$this->trData = new \stdClass();

		switch($this->transactionType){
			case self::TYPE_NORMAL:
			case self::TYPE_MISMATCH:
				//Regular ComplexInventoryTransaction doesn't read any extra data
				break;
			case self::TYPE_USE_ITEM:
				$this->trData->actionType = $this->getUnsignedVarInt();
				$this->getBlockPosition($this->trData->x, $this->trData->y, $this->trData->z);
				$this->trData->face = $this->getVarInt();
				$this->trData->hotbarSlot = $this->getVarInt();
				$this->trData->itemInHand = $this->getSlot();
				$this->trData->playerPos = $this->getVector3();
				$this->trData->clickPos = $this->getVector3();
				$this->trData->blockRuntimeId = $this->getUnsignedVarInt();
				break;
			case self::TYPE_USE_ITEM_ON_ENTITY:
				$this->trData->entityRuntimeId = $this->getEntityRuntimeId();
				$this->trData->actionType = $this->getUnsignedVarInt();
				$this->trData->hotbarSlot = $this->getVarInt();
				$this->trData->itemInHand = $this->getSlot();
				$this->trData->playerPos = $this->getVector3();
				$this->trData->clickPos = $this->getVector3();
				break;
			case self::TYPE_RELEASE_ITEM:
				$this->trData->actionType = $this->getUnsignedVarInt();
				$this->trData->hotbarSlot = $this->getVarInt();
				$this->trData->itemInHand = $this->getSlot();
				$this->trData->headPos = $this->getVector3();
				break;
			default:
				throw new \UnexpectedValueException("Unknown transaction type $this->transactionType");
		}
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->transactionType);

		$this->putUnsignedVarInt(count($this->actions));
		foreach($this->actions as $action){
			$action->write($this);
		}

		switch($this->transactionType){
			case self::TYPE_NORMAL:
			case self::TYPE_MISMATCH:
				break;
			case self::TYPE_USE_ITEM:
				$this->putUnsignedVarInt($this->trData->actionType);
				$this->putBlockPosition($this->trData->x, $this->trData->y, $this->trData->z);
				$this->putVarInt($this->trData->face);
				$this->putVarInt($this->trData->hotbarSlot);
				$this->putSlot($this->trData->itemInHand);
				$this->putVector3($this->trData->playerPos);
				$this->putVector3($this->trData->clickPos);
				$this->putUnsignedVarInt($this->trData->blockRuntimeId);
				break;
			case self::TYPE_USE_ITEM_ON_ENTITY:
				$this->putEntityRuntimeId($this->trData->entityRuntimeId);
				$this->putUnsignedVarInt($this->trData->actionType);
				$this->putVarInt($this->trData->hotbarSlot);
				$this->putSlot($this->trData->itemInHand);
				$this->putVector3($this->trData->playerPos);
				$this->putVector3($this->trData->clickPos);
				break;
			case self::TYPE_RELEASE_ITEM:
				$this->putUnsignedVarInt($this->trData->actionType);
				$this->putVarInt($this->trData->hotbarSlot);
				$this->putSlot($this->trData->itemInHand);
				$this->putVector3($this->trData->headPos);
				break;
			default:
				throw new \InvalidArgumentException("Unknown transaction type $this->transactionType");
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleInventoryTransaction($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;

class MobEquipmentPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MOB_EQUIPMENT_PACKET;

	/** @var int */
	public $entityRuntimeId;
	/** @var Item */
	public $item;
	/** @var int */
	public $inventorySlot;
	/** @var int */
	public $hotbarSlot;
	/** @var int */
	public $windowId = 0;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->item = $this->getSlot();
		$this->inventorySlot = (\ord($this->get(1)));
		$this->hotbarSlot = (\ord($this->get(1)));
		$this->windowId = (\ord($this->get(1)));
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putSlot($this->item);
		($this->buffer .= \chr($this->inventorySlot));
		($this->buffer .= \chr($this->hotbarSlot));
		($this->buffer .= \chr($this->windowId));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleMobEquipment($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;

class MobArmorEquipmentPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET;

	/** @var int */
	public $entityRuntimeId;

	//this intentionally doesn't use an array because we don't want any implicit dependencies on internal order

	/** @var Item */
	public $head;
	/** @var Item */
	public $chest;
	/** @var Item */
	public $legs;
	/** @var Item */
	public $feet;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->head = $this->getSlot();
		$this->chest = $this->getSlot();
		$this->legs = $this->getSlot();
		$this->feet = $this->getSlot();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putSlot($this->head);
		$this->putSlot($this->chest);
		$this->putSlot($this->legs);
		$this->putSlot($this->feet);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleMobArmorEquipment($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class InteractPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::INTERACT_PACKET;

	public const ACTION_LEAVE_VEHICLE = 3;
	public const ACTION_MOUSEOVER = 4;

	public const ACTION_OPEN_INVENTORY = 6;

	/** @var int */
	public $action;
	/** @var int */
	public $target;

	/** @var float */
	public $x;
	/** @var float */
	public $y;
	/** @var float */
	public $z;

	protected function decodePayload(){
		$this->action = (\ord($this->get(1)));
		$this->target = $this->getEntityRuntimeId();

		if($this->action === self::ACTION_MOUSEOVER){
			//TODO: should this be a vector3?
			$this->x = ((\unpack("g", $this->get(4))[1]));
			$this->y = ((\unpack("g", $this->get(4))[1]));
			$this->z = ((\unpack("g", $this->get(4))[1]));
		}
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->action));
		$this->putEntityRuntimeId($this->target);

		if($this->action === self::ACTION_MOUSEOVER){
			($this->buffer .= (\pack("g", $this->x)));
			($this->buffer .= (\pack("g", $this->y)));
			($this->buffer .= (\pack("g", $this->z)));
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleInteract($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class BlockPickRequestPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::BLOCK_PICK_REQUEST_PACKET;

	/** @var int */
	public $blockX;
	/** @var int */
	public $blockY;
	/** @var int */
	public $blockZ;
	/** @var bool */
	public $addUserData = false;
	/** @var int */
	public $hotbarSlot;

	protected function decodePayload(){
		$this->getSignedBlockPosition($this->blockX, $this->blockY, $this->blockZ);
		$this->addUserData = (($this->get(1) !== "\x00"));
		$this->hotbarSlot = (\ord($this->get(1)));
	}

	protected function encodePayload(){
		$this->putSignedBlockPosition($this->blockX, $this->blockY, $this->blockZ);
		($this->buffer .= ($this->addUserData ? "\x01" : "\x00"));
		($this->buffer .= \chr($this->hotbarSlot));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleBlockPickRequest($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ActorPickRequestPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ACTOR_PICK_REQUEST_PACKET;

	/** @var int */
	public $entityUniqueId;
	/** @var int */
	public $hotbarSlot;

	protected function decodePayload(){
		$this->entityUniqueId = (Binary::readLLong($this->get(8)));
		$this->hotbarSlot = (\ord($this->get(1)));
	}

	protected function encodePayload(){
		($this->buffer .= (\pack("VV", $this->entityUniqueId & 0xFFFFFFFF, $this->entityUniqueId >> 32)));
		($this->buffer .= \chr($this->hotbarSlot));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleActorPickRequest($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class PlayerActionPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::PLAYER_ACTION_PACKET;

	public const ACTION_START_BREAK = 0;
	public const ACTION_ABORT_BREAK = 1;
	public const ACTION_STOP_BREAK = 2;
	public const ACTION_GET_UPDATED_BLOCK = 3;
	public const ACTION_DROP_ITEM = 4;
	public const ACTION_START_SLEEPING = 5;
	public const ACTION_STOP_SLEEPING = 6;
	public const ACTION_RESPAWN = 7;
	public const ACTION_JUMP = 8;
	public const ACTION_START_SPRINT = 9;
	public const ACTION_STOP_SPRINT = 10;
	public const ACTION_START_SNEAK = 11;
	public const ACTION_STOP_SNEAK = 12;
	public const ACTION_DIMENSION_CHANGE_REQUEST = 13; //sent when dying in different dimension
	public const ACTION_DIMENSION_CHANGE_ACK = 14; //sent when spawning in a different dimension to tell the server we spawned
	public const ACTION_START_GLIDE = 15;
	public const ACTION_STOP_GLIDE = 16;
	public const ACTION_BUILD_DENIED = 17;
	public const ACTION_CONTINUE_BREAK = 18;

	public const ACTION_SET_ENCHANTMENT_SEED = 20;
	public const ACTION_START_SWIMMING = 21;
	public const ACTION_STOP_SWIMMING = 22;
	public const ACTION_START_SPIN_ATTACK = 23;
	public const ACTION_STOP_SPIN_ATTACK = 24;
	public const ACTION_INTERACT_BLOCK = 25;

	/** @var int */
	public $entityRuntimeId;
	/** @var int */
	public $action;
	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;
	/** @var int */
	public $face;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->action = $this->getVarInt();
		$this->getBlockPosition($this->x, $this->y, $this->z);
		$this->face = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putVarInt($this->action);
		$this->putBlockPosition($this->x, $this->y, $this->z);
		$this->putVarInt($this->face);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handlePlayerAction($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ActorFallPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ACTOR_FALL_PACKET;

	/** @var int */
	public $entityRuntimeId;
	/** @var float */
	public $fallDistance;
	/** @var bool */
	public $isInVoid;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->fallDistance = ((\unpack("g", $this->get(4))[1]));
		$this->isInVoid = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		($this->buffer .= (\pack("g", $this->fallDistance)));
		($this->buffer .= ($this->isInVoid ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleActorFall($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class HurtArmorPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::HURT_ARMOR_PACKET;

	/** @var int */
	public $health;

	protected function decodePayload(){
		$this->health = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->health);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleHurtArmor($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetActorDataPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_ACTOR_DATA_PACKET;

	/** @var int */
	public $entityRuntimeId;
	/**
	 * @var mixed[][]
	 * @phpstan-var array<int, array{0: int, 1: mixed}>
	 */
	public $metadata;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->metadata = $this->getEntityMetadata();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putEntityMetadata($this->metadata);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetActorData($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class SetActorMotionPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_ACTOR_MOTION_PACKET;

	/** @var int */
	public $entityRuntimeId;
	/** @var Vector3 */
	public $motion;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->motion = $this->getVector3();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putVector3($this->motion);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetActorMotion($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\EntityLink;

class SetActorLinkPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_ACTOR_LINK_PACKET;

	/** @var EntityLink */
	public $link;

	protected function decodePayload(){
		$this->link = $this->getEntityLink();
	}

	protected function encodePayload(){
		$this->putEntityLink($this->link);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetActorLink($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetHealthPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_HEALTH_PACKET;

	/** @var int */
	public $health;

	protected function decodePayload(){
		$this->health = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->health);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetHealth($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetSpawnPositionPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_SPAWN_POSITION_PACKET;

	public const TYPE_PLAYER_SPAWN = 0;
	public const TYPE_WORLD_SPAWN = 1;

	/** @var int */
	public $spawnType;
	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;
	/** @var bool */
	public $spawnForced;

	protected function decodePayload(){
		$this->spawnType = $this->getVarInt();
		$this->getBlockPosition($this->x, $this->y, $this->z);
		$this->spawnForced = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		$this->putVarInt($this->spawnType);
		$this->putBlockPosition($this->x, $this->y, $this->z);
		($this->buffer .= ($this->spawnForced ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetSpawnPosition($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class AnimatePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ANIMATE_PACKET;

	public const ACTION_SWING_ARM = 1;

	public const ACTION_STOP_SLEEP = 3;
	public const ACTION_CRITICAL_HIT = 4;
	public const ACTION_ROW_RIGHT = 128;
	public const ACTION_ROW_LEFT = 129;

	/** @var int */
	public $action;
	/** @var int */
	public $entityRuntimeId;
	/** @var float */
	public $float = 0.0; //TODO (Boat rowing time?)

	protected function decodePayload(){
		$this->action = $this->getVarInt();
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		if(($this->action & 0x80) !== 0){
			$this->float = ((\unpack("g", $this->get(4))[1]));
		}
	}

	protected function encodePayload(){
		$this->putVarInt($this->action);
		$this->putEntityRuntimeId($this->entityRuntimeId);
		if(($this->action & 0x80) !== 0){
			($this->buffer .= (\pack("g", $this->float)));
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAnimate($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class RespawnPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::RESPAWN_PACKET;

	public const SEARCHING_FOR_SPAWN = 0;
	public const READY_TO_SPAWN = 1;
	public const CLIENT_READY_TO_SPAWN = 2;

	/** @var Vector3 */
	public $position;
	/** @var int */
	public $respawnState = self::SEARCHING_FOR_SPAWN;
	/** @var int */
	public $entityRuntimeId;

	protected function decodePayload(){
		$this->position = $this->getVector3();
		$this->respawnState = (\ord($this->get(1)));
		$this->entityRuntimeId = $this->getEntityRuntimeId();
	}

	protected function encodePayload(){
		$this->putVector3($this->position);
		($this->buffer .= \chr($this->respawnState));
		$this->putEntityRuntimeId($this->entityRuntimeId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleRespawn($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ContainerOpenPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CONTAINER_OPEN_PACKET;

	/** @var int */
	public $windowId;
	/** @var int */
	public $type;
	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;
	/** @var int */
	public $entityUniqueId = -1;

	protected function decodePayload(){
		$this->windowId = (\ord($this->get(1)));
		$this->type = (\ord($this->get(1)));
		$this->getBlockPosition($this->x, $this->y, $this->z);
		$this->entityUniqueId = $this->getEntityUniqueId();
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->windowId));
		($this->buffer .= \chr($this->type));
		$this->putBlockPosition($this->x, $this->y, $this->z);
		$this->putEntityUniqueId($this->entityUniqueId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleContainerOpen($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ContainerClosePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CONTAINER_CLOSE_PACKET;

	/** @var int */
	public $windowId;

	protected function decodePayload(){
		$this->windowId = (\ord($this->get(1)));
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->windowId));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleContainerClose($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ContainerIds;

/**
 * One of the most useless packets.
 */
class PlayerHotbarPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::PLAYER_HOTBAR_PACKET;

	/** @var int */
	public $selectedHotbarSlot;
	/** @var int */
	public $windowId = ContainerIds::INVENTORY;
	/** @var bool */
	public $selectHotbarSlot = true;

	protected function decodePayload(){
		$this->selectedHotbarSlot = $this->getUnsignedVarInt();
		$this->windowId = (\ord($this->get(1)));
		$this->selectHotbarSlot = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->selectedHotbarSlot);
		($this->buffer .= \chr($this->windowId));
		($this->buffer .= ($this->selectHotbarSlot ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handlePlayerHotbar($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

interface ContainerIds{

	public const NONE = -1;
	public const INVENTORY = 0;
	public const FIRST = 1;
	public const LAST = 100;
	public const OFFHAND = 119;
	public const ARMOR = 120;
	public const CREATIVE = 121;
	public const HOTBAR = 122;
	public const FIXED_INVENTORY = 123;
	public const UI = 124;

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use function count;

class InventoryContentPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::INVENTORY_CONTENT_PACKET;

	/** @var int */
	public $windowId;
	/** @var Item[] */
	public $items = [];

	protected function decodePayload(){
		$this->windowId = $this->getUnsignedVarInt();
		$count = $this->getUnsignedVarInt();
		for($i = 0; $i < $count; ++$i){
			$this->items[] = $this->getSlot();
		}
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->windowId);
		$this->putUnsignedVarInt(count($this->items));
		foreach($this->items as $item){
			$this->putSlot($item);
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleInventoryContent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;

class InventorySlotPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::INVENTORY_SLOT_PACKET;

	/** @var int */
	public $windowId;
	/** @var int */
	public $inventorySlot;
	/** @var Item */
	public $item;

	protected function decodePayload(){
		$this->windowId = $this->getUnsignedVarInt();
		$this->inventorySlot = $this->getUnsignedVarInt();
		$this->item = $this->getSlot();
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->windowId);
		$this->putUnsignedVarInt($this->inventorySlot);
		$this->putSlot($this->item);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleInventorySlot($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ContainerSetDataPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CONTAINER_SET_DATA_PACKET;

	public const PROPERTY_FURNACE_TICK_COUNT = 0;
	public const PROPERTY_FURNACE_LIT_TIME = 1;
	public const PROPERTY_FURNACE_LIT_DURATION = 2;
	public const PROPERTY_FURNACE_STORED_XP = 3;
	public const PROPERTY_FURNACE_FUEL_AUX = 4;

	public const PROPERTY_BREWING_STAND_BREW_TIME = 0;
	public const PROPERTY_BREWING_STAND_FUEL_AMOUNT = 1;
	public const PROPERTY_BREWING_STAND_FUEL_TOTAL = 2;

	/** @var int */
	public $windowId;
	/** @var int */
	public $property;
	/** @var int */
	public $value;

	protected function decodePayload(){
		$this->windowId = (\ord($this->get(1)));
		$this->property = $this->getVarInt();
		$this->value = $this->getVarInt();
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->windowId));
		$this->putVarInt($this->property);
		$this->putVarInt($this->value);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleContainerSetData($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\inventory\FurnaceRecipe;
use pocketmine\inventory\ShapedRecipe;
use pocketmine\inventory\ShapelessRecipe;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PotionContainerChangeRecipe;
use pocketmine\network\mcpe\protocol\types\PotionTypeRecipe;
use function count;
use function str_repeat;

class CraftingDataPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CRAFTING_DATA_PACKET;

	public const ENTRY_SHAPELESS = 0;
	public const ENTRY_SHAPED = 1;
	public const ENTRY_FURNACE = 2;
	public const ENTRY_FURNACE_DATA = 3;
	public const ENTRY_MULTI = 4; //TODO
	public const ENTRY_SHULKER_BOX = 5; //TODO
	public const ENTRY_SHAPELESS_CHEMISTRY = 6; //TODO
	public const ENTRY_SHAPED_CHEMISTRY = 7; //TODO

	/** @var object[] */
	public $entries = [];
	/** @var PotionTypeRecipe[] */
	public $potionTypeRecipes = [];
	/** @var PotionContainerChangeRecipe[] */
	public $potionContainerRecipes = [];
	/** @var bool */
	public $cleanRecipes = false;

	/** @var mixed[][] */
	public $decodedEntries = [];

	public function clean(){
		$this->entries = [];
		$this->decodedEntries = [];
		return parent::clean();
	}

	protected function decodePayload(){
		$this->decodedEntries = [];
		$recipeCount = $this->getUnsignedVarInt();
		for($i = 0; $i < $recipeCount; ++$i){
			$entry = [];
			$entry["type"] = $recipeType = $this->getVarInt();

			switch($recipeType){
				case self::ENTRY_SHAPELESS:
				case self::ENTRY_SHULKER_BOX:
				case self::ENTRY_SHAPELESS_CHEMISTRY:
					$entry["recipe_id"] = $this->getString();
					$ingredientCount = $this->getUnsignedVarInt();
					/** @var Item */
					$entry["input"] = [];
					for($j = 0; $j < $ingredientCount; ++$j){
						$entry["input"][] = $in = $this->getRecipeIngredient();
						$in->setCount(1); //TODO HACK: they send a useless count field which breaks the PM crafting system because it isn't always 1
					}
					$resultCount = $this->getUnsignedVarInt();
					$entry["output"] = [];
					for($k = 0; $k < $resultCount; ++$k){
						$entry["output"][] = $this->getSlot();
					}
					$entry["uuid"] = $this->getUUID()->toString();
					$entry["block"] = $this->getString();
					$entry["priority"] = $this->getVarInt();

					break;
				case self::ENTRY_SHAPED:
				case self::ENTRY_SHAPED_CHEMISTRY:
					$entry["recipe_id"] = $this->getString();
					$entry["width"] = $this->getVarInt();
					$entry["height"] = $this->getVarInt();
					$count = $entry["width"] * $entry["height"];
					$entry["input"] = [];
					for($j = 0; $j < $count; ++$j){
						$entry["input"][] = $in = $this->getRecipeIngredient();
						$in->setCount(1); //TODO HACK: they send a useless count field which breaks the PM crafting system
					}
					$resultCount = $this->getUnsignedVarInt();
					$entry["output"] = [];
					for($k = 0; $k < $resultCount; ++$k){
						$entry["output"][] = $this->getSlot();
					}
					$entry["uuid"] = $this->getUUID()->toString();
					$entry["block"] = $this->getString();
					$entry["priority"] = $this->getVarInt();

					break;
				case self::ENTRY_FURNACE:
				case self::ENTRY_FURNACE_DATA:
					$inputId = $this->getVarInt();
					$inputData = -1;
					if($recipeType === self::ENTRY_FURNACE_DATA){
						$inputData = $this->getVarInt();
						if($inputData === 0x7fff){
							$inputData = -1;
						}
					}
					$entry["input"] = ItemFactory::get($inputId, $inputData);
					$entry["output"] = $out = $this->getSlot();
					if($out->getDamage() === 0x7fff){
						$out->setDamage(0); //TODO HACK: some 1.12 furnace recipe outputs have wildcard damage values
					}
					$entry["block"] = $this->getString();

					break;
				case self::ENTRY_MULTI:
					$entry["uuid"] = $this->getUUID()->toString();
					break;
				default:
					throw new \UnexpectedValueException("Unhandled recipe type $recipeType!"); //do not continue attempting to decode
			}
			$this->decodedEntries[] = $entry;
		}
		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$input = $this->getVarInt();
			$ingredient = $this->getVarInt();
			$output = $this->getVarInt();
			$this->potionTypeRecipes[] = new PotionTypeRecipe($input, $ingredient, $output);
		}
		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$input = $this->getVarInt();
			$ingredient = $this->getVarInt();
			$output = $this->getVarInt();
			$this->potionContainerRecipes[] = new PotionContainerChangeRecipe($input, $ingredient, $output);
		}
		$this->cleanRecipes = (($this->get(1) !== "\x00"));
	}

	/**
	 * @param object              $entry
	 */
	private static function writeEntry($entry, NetworkBinaryStream $stream, int $pos) : int{
		if($entry instanceof ShapelessRecipe){
			return self::writeShapelessRecipe($entry, $stream, $pos);
		}elseif($entry instanceof ShapedRecipe){
			return self::writeShapedRecipe($entry, $stream, $pos);
		}elseif($entry instanceof FurnaceRecipe){
			return self::writeFurnaceRecipe($entry, $stream);
		}
		//TODO: add MultiRecipe

		return -1;
	}

	private static function writeShapelessRecipe(ShapelessRecipe $recipe, NetworkBinaryStream $stream, int $pos) : int{
		$stream->putString((\pack("N", $pos))); //some kind of recipe ID, doesn't matter what it is as long as it's unique
		$stream->putUnsignedVarInt($recipe->getIngredientCount());
		foreach($recipe->getIngredientList() as $item){
			$stream->putRecipeIngredient($item);
		}

		$results = $recipe->getResults();
		$stream->putUnsignedVarInt(count($results));
		foreach($results as $item){
			$stream->putSlot($item);
		}

		$stream->put(str_repeat("\x00", 16)); //Null UUID
		$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
		$stream->putVarInt(50); //TODO: priority

		return CraftingDataPacket::ENTRY_SHAPELESS;
	}

	private static function writeShapedRecipe(ShapedRecipe $recipe, NetworkBinaryStream $stream, int $pos) : int{
		$stream->putString((\pack("N", $pos))); //some kind of recipe ID, doesn't matter what it is as long as it's unique
		$stream->putVarInt($recipe->getWidth());
		$stream->putVarInt($recipe->getHeight());

		for($z = 0; $z < $recipe->getHeight(); ++$z){
			for($x = 0; $x < $recipe->getWidth(); ++$x){
				$stream->putRecipeIngredient($recipe->getIngredient($x, $z));
			}
		}

		$results = $recipe->getResults();
		$stream->putUnsignedVarInt(count($results));
		foreach($results as $item){
			$stream->putSlot($item);
		}

		$stream->put(str_repeat("\x00", 16)); //Null UUID
		$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
		$stream->putVarInt(50); //TODO: priority

		return CraftingDataPacket::ENTRY_SHAPED;
	}

	private static function writeFurnaceRecipe(FurnaceRecipe $recipe, NetworkBinaryStream $stream) : int{
		$stream->putVarInt($recipe->getInput()->getId());
		$result = CraftingDataPacket::ENTRY_FURNACE;
		if(!$recipe->getInput()->hasAnyDamageValue()){ //Data recipe
			$stream->putVarInt($recipe->getInput()->getDamage());
			$result = CraftingDataPacket::ENTRY_FURNACE_DATA;
		}
		$stream->putSlot($recipe->getResult());
		$stream->putString("furnace"); //TODO: blocktype (no prefix) (this might require internal API breaks)
		return $result;
	}

	/**
	 * @return void
	 */
	public function addShapelessRecipe(ShapelessRecipe $recipe){
		$this->entries[] = $recipe;
	}

	/**
	 * @return void
	 */
	public function addShapedRecipe(ShapedRecipe $recipe){
		$this->entries[] = $recipe;
	}

	/**
	 * @return void
	 */
	public function addFurnaceRecipe(FurnaceRecipe $recipe){
		$this->entries[] = $recipe;
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt(count($this->entries));

		$writer = new NetworkBinaryStream();
		$counter = 0;
		foreach($this->entries as $d){
			$entryType = self::writeEntry($d, $writer, $counter++);
			if($entryType >= 0){
				$this->putVarInt($entryType);
				($this->buffer .= $writer->getBuffer());
			}else{
				$this->putVarInt(-1);
			}

			$writer->reset();
		}
		$this->putUnsignedVarInt(count($this->potionTypeRecipes));
		foreach($this->potionTypeRecipes as $recipe){
			$this->putVarInt($recipe->getInputPotionType());
			$this->putVarInt($recipe->getIngredientItemId());
			$this->putVarInt($recipe->getOutputPotionType());
		}
		$this->putUnsignedVarInt(count($this->potionContainerRecipes));
		foreach($this->potionContainerRecipes as $recipe){
			$this->putVarInt($recipe->getInputItemId());
			$this->putVarInt($recipe->getIngredientItemId());
			$this->putVarInt($recipe->getOutputItemId());
		}

		($this->buffer .= ($this->cleanRecipes ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleCraftingData($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\utils\UUID;
use function count;

class CraftingEventPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CRAFTING_EVENT_PACKET;

	/** @var int */
	public $windowId;
	/** @var int */
	public $type;
	/** @var UUID */
	public $id;
	/** @var Item[] */
	public $input = [];
	/** @var Item[] */
	public $output = [];

	public function clean(){
		$this->input = [];
		$this->output = [];
		return parent::clean();
	}

	protected function decodePayload(){
		$this->windowId = (\ord($this->get(1)));
		$this->type = $this->getVarInt();
		$this->id = $this->getUUID();

		$size = $this->getUnsignedVarInt();
		for($i = 0; $i < $size and $i < 128; ++$i){
			$this->input[] = $this->getSlot();
		}

		$size = $this->getUnsignedVarInt();
		for($i = 0; $i < $size and $i < 128; ++$i){
			$this->output[] = $this->getSlot();
		}
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->windowId));
		$this->putVarInt($this->type);
		$this->putUUID($this->id);

		$this->putUnsignedVarInt(count($this->input));
		foreach($this->input as $item){
			$this->putSlot($item);
		}

		$this->putUnsignedVarInt(count($this->output));
		foreach($this->output as $item){
			$this->putSlot($item);
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleCraftingEvent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class GuiDataPickItemPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::GUI_DATA_PICK_ITEM_PACKET;

	/** @var string */
	public $itemDescription;
	/** @var string */
	public $itemEffects;
	/** @var int */
	public $hotbarSlot;

	protected function decodePayload(){
		$this->itemDescription = $this->getString();
		$this->itemEffects = $this->getString();
		$this->hotbarSlot = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
	}

	protected function encodePayload(){
		$this->putString($this->itemDescription);
		$this->putString($this->itemEffects);
		($this->buffer .= (\pack("V", $this->hotbarSlot)));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleGuiDataPickItem($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;

class AdventureSettingsPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ADVENTURE_SETTINGS_PACKET;

	public const PERMISSION_NORMAL = 0;
	public const PERMISSION_OPERATOR = 1;
	public const PERMISSION_HOST = 2;
	public const PERMISSION_AUTOMATION = 3;
	public const PERMISSION_ADMIN = 4;

	/**
	 * This constant is used to identify flags that should be set on the second field. In a sensible world, these
	 * flags would all be set on the same packet field, but as of MCPE 1.2, the new abilities flags have for some
	 * reason been assigned a separate field.
	 */
	public const BITFLAG_SECOND_SET = 1 << 16;

	public const WORLD_IMMUTABLE = 0x01;
	public const NO_PVP = 0x02;

	public const AUTO_JUMP = 0x20;
	public const ALLOW_FLIGHT = 0x40;
	public const NO_CLIP = 0x80;
	public const WORLD_BUILDER = 0x100;
	public const FLYING = 0x200;
	public const MUTED = 0x400;

	public const BUILD_AND_MINE = 0x01 | self::BITFLAG_SECOND_SET;
	public const DOORS_AND_SWITCHES = 0x02 | self::BITFLAG_SECOND_SET;
	public const OPEN_CONTAINERS = 0x04 | self::BITFLAG_SECOND_SET;
	public const ATTACK_PLAYERS = 0x08 | self::BITFLAG_SECOND_SET;
	public const ATTACK_MOBS = 0x10 | self::BITFLAG_SECOND_SET;
	public const OPERATOR = 0x20 | self::BITFLAG_SECOND_SET;
	public const TELEPORT = 0x80 | self::BITFLAG_SECOND_SET;

	/** @var int */
	public $flags = 0;
	/** @var int */
	public $commandPermission = self::PERMISSION_NORMAL;
	/** @var int */
	public $flags2 = -1;
	/** @var int */
	public $playerPermission = PlayerPermissions::MEMBER;
	/** @var int */
	public $customFlags = 0; //...
	/** @var int */
	public $entityUniqueId; //This is a little-endian long, NOT a var-long. (WTF Mojang)

	protected function decodePayload(){
		$this->flags = $this->getUnsignedVarInt();
		$this->commandPermission = $this->getUnsignedVarInt();
		$this->flags2 = $this->getUnsignedVarInt();
		$this->playerPermission = $this->getUnsignedVarInt();
		$this->customFlags = $this->getUnsignedVarInt();
		$this->entityUniqueId = (Binary::readLLong($this->get(8)));
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->flags);
		$this->putUnsignedVarInt($this->commandPermission);
		$this->putUnsignedVarInt($this->flags2);
		$this->putUnsignedVarInt($this->playerPermission);
		$this->putUnsignedVarInt($this->customFlags);
		($this->buffer .= (\pack("VV", $this->entityUniqueId & 0xFFFFFFFF, $this->entityUniqueId >> 32)));
	}

	public function getFlag(int $flag) : bool{
		if(($flag & self::BITFLAG_SECOND_SET) !== 0){
			return ($this->flags2 & $flag) !== 0;
		}

		return ($this->flags & $flag) !== 0;
	}

	/**
	 * @return void
	 */
	public function setFlag(int $flag, bool $value){
		if(($flag & self::BITFLAG_SECOND_SET) !== 0){
			$flagSet =& $this->flags2;
		}else{
			$flagSet =& $this->flags;
		}

		if($value){
			$flagSet |= $flag;
		}else{
			$flagSet &= ~$flag;
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAdventureSettings($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class BlockActorDataPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::BLOCK_ACTOR_DATA_PACKET;

	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;
	/** @var string */
	public $namedtag;

	protected function decodePayload(){
		$this->getBlockPosition($this->x, $this->y, $this->z);
		$this->namedtag = $this->getRemaining();
	}

	protected function encodePayload(){
		$this->putBlockPosition($this->x, $this->y, $this->z);
		($this->buffer .= $this->namedtag);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleBlockActorData($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class PlayerInputPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::PLAYER_INPUT_PACKET;

	/** @var float */
	public $motionX;
	/** @var float */
	public $motionY;
	/** @var bool */
	public $jumping;
	/** @var bool */
	public $sneaking;

	protected function decodePayload(){
		$this->motionX = ((\unpack("g", $this->get(4))[1]));
		$this->motionY = ((\unpack("g", $this->get(4))[1]));
		$this->jumping = (($this->get(1) !== "\x00"));
		$this->sneaking = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		($this->buffer .= (\pack("g", $this->motionX)));
		($this->buffer .= (\pack("g", $this->motionY)));
		($this->buffer .= ($this->jumping ? "\x01" : "\x00"));
		($this->buffer .= ($this->sneaking ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handlePlayerInput($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use function count;

class LevelChunkPacket extends DataPacket/* implements ClientboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::LEVEL_CHUNK_PACKET;

	/** @var int */
	private $chunkX;
	/** @var int */
	private $chunkZ;
	/** @var int */
	private $subChunkCount;
	/** @var bool */
	private $cacheEnabled;
	/** @var int[] */
	private $usedBlobHashes = [];
	/** @var string */
	private $extraPayload;

	public static function withoutCache(int $chunkX, int $chunkZ, int $subChunkCount, string $payload) : self{
		$result = new self;
		$result->chunkX = $chunkX;
		$result->chunkZ = $chunkZ;
		$result->subChunkCount = $subChunkCount;
		$result->extraPayload = $payload;

		$result->cacheEnabled = false;

		return $result;
	}

	/**
	 * @param int[] $usedBlobHashes
	 */
	public static function withCache(int $chunkX, int $chunkZ, int $subChunkCount, array $usedBlobHashes, string $extraPayload) : self{
		(static function(int ...$hashes) : void{})(...$usedBlobHashes);
		$result = new self;
		$result->chunkX = $chunkX;
		$result->chunkZ = $chunkZ;
		$result->subChunkCount = $subChunkCount;
		$result->extraPayload = $extraPayload;

		$result->cacheEnabled = true;
		$result->usedBlobHashes = $usedBlobHashes;

		return $result;
	}

	public function getChunkX() : int{
		return $this->chunkX;
	}

	public function getChunkZ() : int{
		return $this->chunkZ;
	}

	public function getSubChunkCount() : int{
		return $this->subChunkCount;
	}

	public function isCacheEnabled() : bool{
		return $this->cacheEnabled;
	}

	/**
	 * @return int[]
	 */
	public function getUsedBlobHashes() : array{
		return $this->usedBlobHashes;
	}

	public function getExtraPayload() : string{
		return $this->extraPayload;
	}

	protected function decodePayload() : void{
		$this->chunkX = $this->getVarInt();
		$this->chunkZ = $this->getVarInt();
		$this->subChunkCount = $this->getUnsignedVarInt();
		$this->cacheEnabled = (($this->get(1) !== "\x00"));
		if($this->cacheEnabled){
			for($i =  0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
				$this->usedBlobHashes[] = (Binary::readLLong($this->get(8)));
			}
		}
		$this->extraPayload = $this->getString();
	}

	protected function encodePayload() : void{
		$this->putVarInt($this->chunkX);
		$this->putVarInt($this->chunkZ);
		$this->putUnsignedVarInt($this->subChunkCount);
		($this->buffer .= ($this->cacheEnabled ? "\x01" : "\x00"));
		if($this->cacheEnabled){
			$this->putUnsignedVarInt(count($this->usedBlobHashes));
			foreach($this->usedBlobHashes as $hash){
				($this->buffer .= (\pack("VV", $hash & 0xFFFFFFFF, $hash >> 32)));
			}
		}
		$this->putString($this->extraPayload);
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleLevelChunk($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetCommandsEnabledPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_COMMANDS_ENABLED_PACKET;

	/** @var bool */
	public $enabled;

	protected function decodePayload(){
		$this->enabled = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		($this->buffer .= ($this->enabled ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetCommandsEnabled($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetDifficultyPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_DIFFICULTY_PACKET;

	/** @var int */
	public $difficulty;

	protected function decodePayload(){
		$this->difficulty = $this->getUnsignedVarInt();
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->difficulty);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetDifficulty($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class ChangeDimensionPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CHANGE_DIMENSION_PACKET;

	/** @var int */
	public $dimension;
	/** @var Vector3 */
	public $position;
	/** @var bool */
	public $respawn = false;

	protected function decodePayload(){
		$this->dimension = $this->getVarInt();
		$this->position = $this->getVector3();
		$this->respawn = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		$this->putVarInt($this->dimension);
		$this->putVector3($this->position);
		($this->buffer .= ($this->respawn ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleChangeDimension($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetPlayerGameTypePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_PLAYER_GAME_TYPE_PACKET;

	/** @var int */
	public $gamemode;

	protected function decodePayload(){
		$this->gamemode = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->gamemode);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetPlayerGameType($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use function count;

class PlayerListPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::PLAYER_LIST_PACKET;

	public const TYPE_ADD = 0;
	public const TYPE_REMOVE = 1;

	/** @var PlayerListEntry[] */
	public $entries = [];
	/** @var int */
	public $type;

	public function clean(){
		$this->entries = [];
		return parent::clean();
	}

	protected function decodePayload(){
		$this->type = (\ord($this->get(1)));
		$count = $this->getUnsignedVarInt();
		for($i = 0; $i < $count; ++$i){
			$entry = new PlayerListEntry();

			if($this->type === self::TYPE_ADD){
				$entry->uuid = $this->getUUID();
				$entry->entityUniqueId = $this->getEntityUniqueId();
				$entry->username = $this->getString();
				$entry->xboxUserId = $this->getString();
				$entry->platformChatId = $this->getString();
				$entry->buildPlatform = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
				$entry->skinData = $this->getSkin();
				$entry->isTeacher = (($this->get(1) !== "\x00"));
				$entry->isHost = (($this->get(1) !== "\x00"));
			}else{
				$entry->uuid = $this->getUUID();
			}

			$this->entries[$i] = $entry;
		}
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->type));
		$this->putUnsignedVarInt(count($this->entries));
		foreach($this->entries as $entry){
			if($this->type === self::TYPE_ADD){
				$this->putUUID($entry->uuid);
				$this->putEntityUniqueId($entry->entityUniqueId);
				$this->putString($entry->username);
				$this->putString($entry->xboxUserId);
				$this->putString($entry->platformChatId);
				($this->buffer .= (\pack("V", $entry->buildPlatform)));
				$this->putSkin($entry->skinData);
				($this->buffer .= ($entry->isTeacher ? "\x01" : "\x00"));
				($this->buffer .= ($entry->isHost ? "\x01" : "\x00"));
			}else{
				$this->putUUID($entry->uuid);
			}
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handlePlayerList($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SimpleEventPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SIMPLE_EVENT_PACKET;

	public const TYPE_ENABLE_COMMANDS = 1;
	public const TYPE_DISABLE_COMMANDS = 2;

	/** @var int */
	public $eventType;

	protected function decodePayload(){
		$this->eventType = ((\unpack("v", $this->get(2))[1]));
	}

	protected function encodePayload(){
		($this->buffer .= (\pack("v", $this->eventType)));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSimpleEvent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class EventPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::EVENT_PACKET;

	public const TYPE_ACHIEVEMENT_AWARDED = 0;
	public const TYPE_ENTITY_INTERACT = 1;
	public const TYPE_PORTAL_BUILT = 2;
	public const TYPE_PORTAL_USED = 3;
	public const TYPE_MOB_KILLED = 4;
	public const TYPE_CAULDRON_USED = 5;
	public const TYPE_PLAYER_DEATH = 6;
	public const TYPE_BOSS_KILLED = 7;
	public const TYPE_AGENT_COMMAND = 8;
	public const TYPE_AGENT_CREATED = 9;
	public const TYPE_PATTERN_REMOVED = 10; //???
	public const TYPE_COMMANED_EXECUTED = 11;
	public const TYPE_FISH_BUCKETED = 12;
	public const TYPE_MOB_BORN = 13;
	public const TYPE_PET_DIED = 14;
	public const TYPE_CAULDRON_BLOCK_USED = 15;
	public const TYPE_COMPOSTER_BLOCK_USED = 16;
	public const TYPE_BELL_BLOCK_USED = 17;

	/** @var int */
	public $playerRuntimeId;
	/** @var int */
	public $eventData;
	/** @var int */
	public $type;

	protected function decodePayload(){
		$this->playerRuntimeId = $this->getEntityRuntimeId();
		$this->eventData = $this->getVarInt();
		$this->type = (\ord($this->get(1)));

		//TODO: nice confusing mess
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->playerRuntimeId);
		$this->putVarInt($this->eventData);
		($this->buffer .= \chr($this->type));

		//TODO: also nice confusing mess
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleEvent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class SpawnExperienceOrbPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SPAWN_EXPERIENCE_ORB_PACKET;

	/** @var Vector3 */
	public $position;
	/** @var int */
	public $amount;

	protected function decodePayload(){
		$this->position = $this->getVector3();
		$this->amount = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVector3($this->position);
		$this->putVarInt($this->amount);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSpawnExperienceOrb($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\DimensionIds;
use pocketmine\network\mcpe\protocol\types\MapDecoration;
use pocketmine\network\mcpe\protocol\types\MapTrackedObject;
use pocketmine\utils\Color;
use function count;

class ClientboundMapItemDataPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CLIENTBOUND_MAP_ITEM_DATA_PACKET;

	public const BITFLAG_TEXTURE_UPDATE = 0x02;
	public const BITFLAG_DECORATION_UPDATE = 0x04;

	/** @var int */
	public $mapId;
	/** @var int */
	public $type;
	/** @var int */
	public $dimensionId = DimensionIds::OVERWORLD;
	/** @var bool */
	public $isLocked = false;

	/** @var int[] */
	public $eids = [];
	/** @var int */
	public $scale;

	/** @var MapTrackedObject[] */
	public $trackedEntities = [];
	/** @var MapDecoration[] */
	public $decorations = [];

	/** @var int */
	public $width;
	/** @var int */
	public $height;
	/** @var int */
	public $xOffset = 0;
	/** @var int */
	public $yOffset = 0;
	/** @var Color[][] */
	public $colors = [];

	protected function decodePayload(){
		$this->mapId = $this->getEntityUniqueId();
		$this->type = $this->getUnsignedVarInt();
		$this->dimensionId = (\ord($this->get(1)));
		$this->isLocked = (($this->get(1) !== "\x00"));

		if(($this->type & 0x08) !== 0){
			$count = $this->getUnsignedVarInt();
			for($i = 0; $i < $count; ++$i){
				$this->eids[] = $this->getEntityUniqueId();
			}
		}

		if(($this->type & (0x08 | self::BITFLAG_DECORATION_UPDATE | self::BITFLAG_TEXTURE_UPDATE)) !== 0){ //Decoration bitflag or colour bitflag
			$this->scale = (\ord($this->get(1)));
		}

		if(($this->type & self::BITFLAG_DECORATION_UPDATE) !== 0){
			for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
				$object = new MapTrackedObject();
				$object->type = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
				if($object->type === MapTrackedObject::TYPE_BLOCK){
					$this->getBlockPosition($object->x, $object->y, $object->z);
				}elseif($object->type === MapTrackedObject::TYPE_ENTITY){
					$object->entityUniqueId = $this->getEntityUniqueId();
				}else{
					throw new \UnexpectedValueException("Unknown map object type $object->type");
				}
				$this->trackedEntities[] = $object;
			}

			for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
				$icon = (\ord($this->get(1)));
				$rotation = (\ord($this->get(1)));
				$xOffset = (\ord($this->get(1)));
				$yOffset = (\ord($this->get(1)));
				$label = $this->getString();
				$color = Color::fromABGR($this->getUnsignedVarInt());
				$this->decorations[] = new MapDecoration($icon, $rotation, $xOffset, $yOffset, $label, $color);
			}
		}

		if(($this->type & self::BITFLAG_TEXTURE_UPDATE) !== 0){
			$this->width = $this->getVarInt();
			$this->height = $this->getVarInt();
			$this->xOffset = $this->getVarInt();
			$this->yOffset = $this->getVarInt();

			$count = $this->getUnsignedVarInt();
			if($count !== $this->width * $this->height){
				throw new \UnexpectedValueException("Expected colour count of " . ($this->height * $this->width) . " (height $this->height * width $this->width), got $count");
			}

			for($y = 0; $y < $this->height; ++$y){
				for($x = 0; $x < $this->width; ++$x){
					$this->colors[$y][$x] = Color::fromABGR($this->getUnsignedVarInt());
				}
			}
		}
	}

	protected function encodePayload(){
		$this->putEntityUniqueId($this->mapId);

		$type = 0;
		if(($eidsCount = count($this->eids)) > 0){
			$type |= 0x08;
		}
		if(($decorationCount = count($this->decorations)) > 0){
			$type |= self::BITFLAG_DECORATION_UPDATE;
		}
		if(count($this->colors) > 0){
			$type |= self::BITFLAG_TEXTURE_UPDATE;
		}

		$this->putUnsignedVarInt($type);
		($this->buffer .= \chr($this->dimensionId));
		($this->buffer .= ($this->isLocked ? "\x01" : "\x00"));

		if(($type & 0x08) !== 0){ //TODO: find out what these are for
			$this->putUnsignedVarInt($eidsCount);
			foreach($this->eids as $eid){
				$this->putEntityUniqueId($eid);
			}
		}

		if(($type & (0x08 | self::BITFLAG_TEXTURE_UPDATE | self::BITFLAG_DECORATION_UPDATE)) !== 0){
			($this->buffer .= \chr($this->scale));
		}

		if(($type & self::BITFLAG_DECORATION_UPDATE) !== 0){
			$this->putUnsignedVarInt(count($this->trackedEntities));
			foreach($this->trackedEntities as $object){
				($this->buffer .= (\pack("V", $object->type)));
				if($object->type === MapTrackedObject::TYPE_BLOCK){
					$this->putBlockPosition($object->x, $object->y, $object->z);
				}elseif($object->type === MapTrackedObject::TYPE_ENTITY){
					$this->putEntityUniqueId($object->entityUniqueId);
				}else{
					throw new \InvalidArgumentException("Unknown map object type $object->type");
				}
			}

			$this->putUnsignedVarInt($decorationCount);
			foreach($this->decorations as $decoration){
				($this->buffer .= \chr($decoration->getIcon()));
				($this->buffer .= \chr($decoration->getRotation()));
				($this->buffer .= \chr($decoration->getXOffset()));
				($this->buffer .= \chr($decoration->getYOffset()));
				$this->putString($decoration->getLabel());
				$this->putUnsignedVarInt($decoration->getColor()->toABGR());
			}
		}

		if(($type & self::BITFLAG_TEXTURE_UPDATE) !== 0){
			$this->putVarInt($this->width);
			$this->putVarInt($this->height);
			$this->putVarInt($this->xOffset);
			$this->putVarInt($this->yOffset);

			$this->putUnsignedVarInt($this->width * $this->height); //list count, but we handle it as a 2D array... thanks for the confusion mojang

			for($y = 0; $y < $this->height; ++$y){
				for($x = 0; $x < $this->width; ++$x){
					$this->putUnsignedVarInt($this->colors[$y][$x]->toABGR());
				}
			}
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleClientboundMapItemData($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

interface DimensionIds{

	public const OVERWORLD = 0;
	public const NETHER = 1;
	public const THE_END = 2;

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class MapInfoRequestPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MAP_INFO_REQUEST_PACKET;

	/** @var int */
	public $mapId;

	protected function decodePayload(){
		$this->mapId = $this->getEntityUniqueId();
	}

	protected function encodePayload(){
		$this->putEntityUniqueId($this->mapId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleMapInfoRequest($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class RequestChunkRadiusPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::REQUEST_CHUNK_RADIUS_PACKET;

	/** @var int */
	public $radius;

	protected function decodePayload(){
		$this->radius = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->radius);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleRequestChunkRadius($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ChunkRadiusUpdatedPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CHUNK_RADIUS_UPDATED_PACKET;

	/** @var int */
	public $radius;

	protected function decodePayload(){
		$this->radius = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->radius);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleChunkRadiusUpdated($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ItemFrameDropItemPacket extends DataPacket{

	public const NETWORK_ID = ProtocolInfo::ITEM_FRAME_DROP_ITEM_PACKET;

	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;

	protected function decodePayload(){
		$this->getBlockPosition($this->x, $this->y, $this->z);
	}

	protected function encodePayload(){
		$this->putBlockPosition($this->x, $this->y, $this->z);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleItemFrameDropItem($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class GameRulesChangedPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::GAME_RULES_CHANGED_PACKET;

	/**
	 * @var mixed[][]
	 * @phpstan-var array<string, array{0: int, 1: bool|int|float}>
	 */
	public $gameRules = [];

	protected function decodePayload(){
		$this->gameRules = $this->getGameRules();
	}

	protected function encodePayload(){
		$this->putGameRules($this->gameRules);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleGameRulesChanged($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class CameraPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::CAMERA_PACKET;

	/** @var int */
	public $cameraUniqueId;
	/** @var int */
	public $playerUniqueId;

	protected function decodePayload(){
		$this->cameraUniqueId = $this->getEntityUniqueId();
		$this->playerUniqueId = $this->getEntityUniqueId();
	}

	protected function encodePayload(){
		$this->putEntityUniqueId($this->cameraUniqueId);
		$this->putEntityUniqueId($this->playerUniqueId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleCamera($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class BossEventPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::BOSS_EVENT_PACKET;

	/* S2C: Shows the boss-bar to the player. */
	public const TYPE_SHOW = 0;
	/* C2S: Registers a player to a boss fight. */
	public const TYPE_REGISTER_PLAYER = 1;
	/* S2C: Removes the boss-bar from the client. */
	public const TYPE_HIDE = 2;
	/* C2S: Unregisters a player from a boss fight. */
	public const TYPE_UNREGISTER_PLAYER = 3;
	/* S2C: Sets the bar percentage. */
	public const TYPE_HEALTH_PERCENT = 4;
	/* S2C: Sets title of the bar. */
	public const TYPE_TITLE = 5;
	/* S2C: Not sure on this. Includes color and overlay fields, plus an unknown short. TODO: check this */
	public const TYPE_UNKNOWN_6 = 6;
	/* S2C: Not implemented :( Intended to alter bar appearance, but these currently produce no effect on client-side whatsoever. */
	public const TYPE_TEXTURE = 7;

	/** @var int */
	public $bossEid;
	/** @var int */
	public $eventType;

	/** @var int (long) */
	public $playerEid;
	/** @var float */
	public $healthPercent;
	/** @var string */
	public $title;
	/** @var int */
	public $unknownShort;
	/** @var int */
	public $color;
	/** @var int */
	public $overlay;

	protected function decodePayload(){
		$this->bossEid = $this->getEntityUniqueId();
		$this->eventType = $this->getUnsignedVarInt();
		switch($this->eventType){
			case self::TYPE_REGISTER_PLAYER:
			case self::TYPE_UNREGISTER_PLAYER:
				$this->playerEid = $this->getEntityUniqueId();
				break;
			/** @noinspection PhpMissingBreakStatementInspection */
			case self::TYPE_SHOW:
				$this->title = $this->getString();
				$this->healthPercent = ((\unpack("g", $this->get(4))[1]));
			/** @noinspection PhpMissingBreakStatementInspection */
			case self::TYPE_UNKNOWN_6:
				$this->unknownShort = ((\unpack("v", $this->get(2))[1]));
			case self::TYPE_TEXTURE:
				$this->color = $this->getUnsignedVarInt();
				$this->overlay = $this->getUnsignedVarInt();
				break;
			case self::TYPE_HEALTH_PERCENT:
				$this->healthPercent = ((\unpack("g", $this->get(4))[1]));
				break;
			case self::TYPE_TITLE:
				$this->title = $this->getString();
				break;
			default:
				break;
		}
	}

	protected function encodePayload(){
		$this->putEntityUniqueId($this->bossEid);
		$this->putUnsignedVarInt($this->eventType);
		switch($this->eventType){
			case self::TYPE_REGISTER_PLAYER:
			case self::TYPE_UNREGISTER_PLAYER:
				$this->putEntityUniqueId($this->playerEid);
				break;
			/** @noinspection PhpMissingBreakStatementInspection */
			case self::TYPE_SHOW:
				$this->putString($this->title);
				($this->buffer .= (\pack("g", $this->healthPercent)));
			/** @noinspection PhpMissingBreakStatementInspection */
			case self::TYPE_UNKNOWN_6:
				($this->buffer .= (\pack("v", $this->unknownShort)));
			case self::TYPE_TEXTURE:
				$this->putUnsignedVarInt($this->color);
				$this->putUnsignedVarInt($this->overlay);
				break;
			case self::TYPE_HEALTH_PERCENT:
				($this->buffer .= (\pack("g", $this->healthPercent)));
				break;
			case self::TYPE_TITLE:
				$this->putString($this->title);
				break;
			default:
				break;
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleBossEvent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ShowCreditsPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SHOW_CREDITS_PACKET;

	public const STATUS_START_CREDITS = 0;
	public const STATUS_END_CREDITS = 1;

	/** @var int */
	public $playerEid;
	/** @var int */
	public $status;

	protected function decodePayload(){
		$this->playerEid = $this->getEntityRuntimeId();
		$this->status = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->playerEid);
		$this->putVarInt($this->status);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleShowCredits($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\CommandData;
use pocketmine\network\mcpe\protocol\types\CommandEnum;
use pocketmine\network\mcpe\protocol\types\CommandEnumConstraint;
use pocketmine\network\mcpe\protocol\types\CommandParameter;
use pocketmine\utils\BinaryDataException;
use function array_search;
use function count;
use function dechex;

class AvailableCommandsPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::AVAILABLE_COMMANDS_PACKET;

	/**
	 * This flag is set on all types EXCEPT the POSTFIX type. Not completely sure what this is for, but it is required
	 * for the argtype to work correctly. VALID seems as good a name as any.
	 */
	public const ARG_FLAG_VALID = 0x100000;

	/**
	 * Basic parameter types. These must be combined with the ARG_FLAG_VALID constant.
	 * ARG_FLAG_VALID | (type const)
	 */
	public const ARG_TYPE_INT             = 0x01;
	public const ARG_TYPE_FLOAT           = 0x02;
	public const ARG_TYPE_VALUE           = 0x03;
	public const ARG_TYPE_WILDCARD_INT    = 0x04;
	public const ARG_TYPE_OPERATOR        = 0x05;
	public const ARG_TYPE_TARGET          = 0x06;

	public const ARG_TYPE_FILEPATH = 0x0e;

	public const ARG_TYPE_STRING   = 0x1d;

	public const ARG_TYPE_POSITION = 0x25;

	public const ARG_TYPE_MESSAGE  = 0x29;

	public const ARG_TYPE_RAWTEXT  = 0x2b;

	public const ARG_TYPE_JSON     = 0x2f;

	public const ARG_TYPE_COMMAND  = 0x36;

	/**
	 * Enums are a little different: they are composed as follows:
	 * ARG_FLAG_ENUM | ARG_FLAG_VALID | (enum index)
	 */
	public const ARG_FLAG_ENUM = 0x200000;

	/**
	 * This is used for /xp <level: int>L. It can only be applied to integer parameters.
	 */
	public const ARG_FLAG_POSTFIX = 0x1000000;

	public const HARDCODED_ENUM_NAMES = [
		"CommandName" => true
	];

	/**
	 * @var CommandData[]
	 * List of command data, including name, description, alias indexes and parameters.
	 */
	public $commandData = [];

	/**
	 * @var CommandEnum[]
	 * List of enums which aren't directly referenced by any vanilla command.
	 * This is used for the `CommandName` enum, which is a magic enum used by the `command` argument type.
	 */
	public $hardcodedEnums = [];

	/**
	 * @var CommandEnum[]
	 * List of dynamic command enums, also referred to as "soft" enums. These can by dynamically updated mid-game
	 * without resending this packet.
	 */
	public $softEnums = [];

	/**
	 * @var CommandEnumConstraint[]
	 * List of constraints for enum members. Used to constrain gamerules that can bechanged in nocheats mode and more.
	 */
	public $enumConstraints = [];

	protected function decodePayload(){
		/** @var string[] $enumValues */
		$enumValues = [];
		for($i = 0, $enumValuesCount = $this->getUnsignedVarInt(); $i < $enumValuesCount; ++$i){
			$enumValues[] = $this->getString();
		}

		/** @var string[] $postfixes */
		$postfixes = [];
		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$postfixes[] = $this->getString();
		}

		/** @var CommandEnum[] $enums */
		$enums = [];
		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$enums[] = $enum = $this->getEnum($enumValues);
			if(isset(self::HARDCODED_ENUM_NAMES[$enum->enumName])){
				$this->hardcodedEnums[] = $enum;
			}
		}

		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$this->commandData[] = $this->getCommandData($enums, $postfixes);
		}

		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$this->softEnums[] = $this->getSoftEnum();
		}

		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$this->enumConstraints[] = $this->getEnumConstraint($enums, $enumValues);
		}
	}

	/**
	 * @param string[] $enumValueList
	 *
	 * @throws \UnexpectedValueException
	 * @throws BinaryDataException
	 */
	protected function getEnum(array $enumValueList) : CommandEnum{
		$retval = new CommandEnum();
		$retval->enumName = $this->getString();

		$listSize = count($enumValueList);

		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$index = $this->getEnumValueIndex($listSize);
			if(!isset($enumValueList[$index])){
				throw new \UnexpectedValueException("Invalid enum value index $index");
			}
			//Get the enum value from the initial pile of mess
			$retval->enumValues[] = $enumValueList[$index];
		}

		return $retval;
	}

	protected function getSoftEnum() : CommandEnum{
		$retval = new CommandEnum();
		$retval->enumName = $this->getString();

		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			//Get the enum value from the initial pile of mess
			$retval->enumValues[] = $this->getString();
		}

		return $retval;
	}

	/**
	 * @param int[]       $enumValueMap string enum name -> int index
	 */
	protected function putEnum(CommandEnum $enum, array $enumValueMap) : void{
		$this->putString($enum->enumName);

		$this->putUnsignedVarInt(count($enum->enumValues));
		$listSize = count($enumValueMap);
		foreach($enum->enumValues as $value){
			$index = $enumValueMap[$value] ?? -1;
			if($index === -1){
				throw new \InvalidStateException("Enum value '$value' not found");
			}
			$this->putEnumValueIndex($index, $listSize);
		}
	}

	protected function putSoftEnum(CommandEnum $enum) : void{
		$this->putString($enum->enumName);

		$this->putUnsignedVarInt(count($enum->enumValues));
		foreach($enum->enumValues as $value){
			$this->putString($value);
		}
	}

	/**
	 * @throws BinaryDataException
	 */
	protected function getEnumValueIndex(int $valueCount) : int{
		if($valueCount < 256){
			return (\ord($this->get(1)));
		}elseif($valueCount < 65536){
			return ((\unpack("v", $this->get(2))[1]));
		}else{
			return ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		}
	}

	protected function putEnumValueIndex(int $index, int $valueCount) : void{
		if($valueCount < 256){
			($this->buffer .= \chr($index));
		}elseif($valueCount < 65536){
			($this->buffer .= (\pack("v", $index)));
		}else{
			($this->buffer .= (\pack("V", $index)));
		}
	}

	/**
	 * @param CommandEnum[] $enums
	 * @param string[]      $enumValues
	 */
	protected function getEnumConstraint(array $enums, array $enumValues) : CommandEnumConstraint{
		//wtf, what was wrong with an offset inside the enum? :(
		$valueIndex = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		if(!isset($enumValues[$valueIndex])){
			throw new \UnexpectedValueException("Enum constraint refers to unknown enum value index $valueIndex");
		}
		$enumIndex = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		if(!isset($enums[$enumIndex])){
			throw new \UnexpectedValueException("Enum constraint refers to unknown enum index $enumIndex");
		}
		$enum = $enums[$enumIndex];
		$valueOffset = array_search($enumValues[$valueIndex], $enum->enumValues, true);
		if($valueOffset === false){
			throw new \UnexpectedValueException("Value \"" . $enumValues[$valueIndex] . "\" does not belong to enum \"$enum->enumName\"");
		}

		$constraintIds = [];
		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$constraintIds[] = (\ord($this->get(1)));
		}

		return new CommandEnumConstraint($enum, $valueOffset, $constraintIds);
	}

	/**
	 * @param int[]                 $enumIndexes string enum name -> int index
	 * @param int[]                 $enumValueIndexes string value -> int index
	 */
	protected function putEnumConstraint(CommandEnumConstraint $constraint, array $enumIndexes, array $enumValueIndexes) : void{
		($this->buffer .= (\pack("V", $enumValueIndexes[$constraint->getAffectedValue()])));
		($this->buffer .= (\pack("V", $enumIndexes[$constraint->getEnum()->enumName])));
		$this->putUnsignedVarInt(count($constraint->getConstraints()));
		foreach($constraint->getConstraints() as $v){
			($this->buffer .= \chr($v));
		}
	}

	/**
	 * @param CommandEnum[] $enums
	 * @param string[]      $postfixes
	 *
	 * @throws \UnexpectedValueException
	 * @throws BinaryDataException
	 */
	protected function getCommandData(array $enums, array $postfixes) : CommandData{
		$retval = new CommandData();
		$retval->commandName = $this->getString();
		$retval->commandDescription = $this->getString();
		$retval->flags = (\ord($this->get(1)));
		$retval->permission = (\ord($this->get(1)));
		$retval->aliases = $enums[((\unpack("V", $this->get(4))[1] << 32 >> 32))] ?? null;

		for($overloadIndex = 0, $overloadCount = $this->getUnsignedVarInt(); $overloadIndex < $overloadCount; ++$overloadIndex){
			$retval->overloads[$overloadIndex] = [];
			for($paramIndex = 0, $paramCount = $this->getUnsignedVarInt(); $paramIndex < $paramCount; ++$paramIndex){
				$parameter = new CommandParameter();
				$parameter->paramName = $this->getString();
				$parameter->paramType = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
				$parameter->isOptional = (($this->get(1) !== "\x00"));
				$parameter->flags = (\ord($this->get(1)));

				if(($parameter->paramType & self::ARG_FLAG_ENUM) !== 0){
					$index = ($parameter->paramType & 0xffff);
					$parameter->enum = $enums[$index] ?? null;
					if($parameter->enum === null){
						throw new \UnexpectedValueException("deserializing $retval->commandName parameter $parameter->paramName: expected enum at $index, but got none");
					}
				}elseif(($parameter->paramType & self::ARG_FLAG_POSTFIX) !== 0){
					$index = ($parameter->paramType & 0xffff);
					$parameter->postfix = $postfixes[$index] ?? null;
					if($parameter->postfix === null){
						throw new \UnexpectedValueException("deserializing $retval->commandName parameter $parameter->paramName: expected postfix at $index, but got none");
					}
				}elseif(($parameter->paramType & self::ARG_FLAG_VALID) === 0){
					throw new \UnexpectedValueException("deserializing $retval->commandName parameter $parameter->paramName: Invalid parameter type 0x" . dechex($parameter->paramType));
				}

				$retval->overloads[$overloadIndex][$paramIndex] = $parameter;
			}
		}

		return $retval;
	}

	/**
	 * @param int[]       $enumIndexes string enum name -> int index
	 * @param int[]       $postfixIndexes
	 */
	protected function putCommandData(CommandData $data, array $enumIndexes, array $postfixIndexes) : void{
		$this->putString($data->commandName);
		$this->putString($data->commandDescription);
		($this->buffer .= \chr($data->flags));
		($this->buffer .= \chr($data->permission));

		if($data->aliases !== null){
			($this->buffer .= (\pack("V", $enumIndexes[$data->aliases->enumName] ?? -1)));
		}else{
			($this->buffer .= (\pack("V", -1)));
		}

		$this->putUnsignedVarInt(count($data->overloads));
		foreach($data->overloads as $overload){
			/** @var CommandParameter[] $overload */
			$this->putUnsignedVarInt(count($overload));
			foreach($overload as $parameter){
				$this->putString($parameter->paramName);

				if($parameter->enum !== null){
					$type = self::ARG_FLAG_ENUM | self::ARG_FLAG_VALID | ($enumIndexes[$parameter->enum->enumName] ?? -1);
				}elseif($parameter->postfix !== null){
					$key = $postfixIndexes[$parameter->postfix] ?? -1;
					if($key === -1){
						throw new \InvalidStateException("Postfix '$parameter->postfix' not in postfixes array");
					}
					$type = self::ARG_FLAG_POSTFIX | $key;
				}else{
					$type = $parameter->paramType;
				}

				($this->buffer .= (\pack("V", $type)));
				($this->buffer .= ($parameter->isOptional ? "\x01" : "\x00"));
				($this->buffer .= \chr($parameter->flags));
			}
		}
	}

	/**
	 * @param string[] $postfixes
	 * @phpstan-param array<int, string> $postfixes
	 */
	private function argTypeToString(int $argtype, array $postfixes) : string{
		if(($argtype & self::ARG_FLAG_VALID) !== 0){
			if(($argtype & self::ARG_FLAG_ENUM) !== 0){
				return "stringenum (" . ($argtype & 0xffff) . ")";
			}

			switch($argtype & 0xffff){
				case self::ARG_TYPE_INT:
					return "int";
				case self::ARG_TYPE_FLOAT:
					return "float";
				case self::ARG_TYPE_VALUE:
					return "mixed";
				case self::ARG_TYPE_TARGET:
					return "target";
				case self::ARG_TYPE_STRING:
					return "string";
				case self::ARG_TYPE_POSITION:
					return "xyz";
				case self::ARG_TYPE_MESSAGE:
					return "message";
				case self::ARG_TYPE_RAWTEXT:
					return "text";
				case self::ARG_TYPE_JSON:
					return "json";
				case self::ARG_TYPE_COMMAND:
					return "command";
			}
		}elseif(($argtype & self::ARG_FLAG_POSTFIX) !== 0){
			$postfix = $postfixes[$argtype & 0xffff];

			return "int (postfix $postfix)";
		}else{
			throw new \UnexpectedValueException("Unknown arg type 0x" . dechex($argtype));
		}

		return "unknown ($argtype)";
	}

	protected function encodePayload(){
		/** @var int[] $enumValueIndexes */
		$enumValueIndexes = [];
		/** @var int[] $postfixIndexes */
		$postfixIndexes = [];
		/** @var int[] $enumIndexes */
		$enumIndexes = [];
		/** @var CommandEnum[] $enums */
		$enums = [];

		$addEnumFn = static function(CommandEnum $enum) use (&$enums, &$enumIndexes, &$enumValueIndexes) : void{
			if(!isset($enumIndexes[$enum->enumName])){
				$enums[$enumIndexes[$enum->enumName] = count($enumIndexes)] = $enum;
			}
			foreach($enum->enumValues as $str){
				$enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes);
			}
		};
		foreach($this->hardcodedEnums as $enum){
			$addEnumFn($enum);
		}
		foreach($this->commandData as $commandData){
			if($commandData->aliases !== null){
				$addEnumFn($commandData->aliases);
			}
			/** @var CommandParameter[] $overload */
			foreach($commandData->overloads as $overload){
				/** @var CommandParameter $parameter */
				foreach($overload as $parameter){
					if($parameter->enum !== null){
						$addEnumFn($parameter->enum);
					}

					if($parameter->postfix !== null){
						$postfixIndexes[$parameter->postfix] = $postfixIndexes[$parameter->postfix] ?? count($postfixIndexes);
					}
				}
			}
		}

		$this->putUnsignedVarInt(count($enumValueIndexes));
		foreach($enumValueIndexes as $enumValue => $index){
			$this->putString((string) $enumValue); //stupid PHP key casting D:
		}

		$this->putUnsignedVarInt(count($postfixIndexes));
		foreach($postfixIndexes as $postfix => $index){
			$this->putString((string) $postfix); //stupid PHP key casting D:
		}

		$this->putUnsignedVarInt(count($enums));
		foreach($enums as $enum){
			$this->putEnum($enum, $enumValueIndexes);
		}

		$this->putUnsignedVarInt(count($this->commandData));
		foreach($this->commandData as $data){
			$this->putCommandData($data, $enumIndexes, $postfixIndexes);
		}

		$this->putUnsignedVarInt(count($this->softEnums));
		foreach($this->softEnums as $enum){
			$this->putSoftEnum($enum);
		}

		$this->putUnsignedVarInt(count($this->enumConstraints));
		foreach($this->enumConstraints as $constraint){
			$this->putEnumConstraint($constraint, $enumIndexes, $enumValueIndexes);
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAvailableCommands($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\CommandOriginData;

class CommandRequestPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::COMMAND_REQUEST_PACKET;

	/** @var string */
	public $command;
	/** @var CommandOriginData */
	public $originData;
	/** @var bool */
	public $isInternal;

	protected function decodePayload(){
		$this->command = $this->getString();
		$this->originData = $this->getCommandOriginData();
		$this->isInternal = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		$this->putString($this->command);
		$this->putCommandOriginData($this->originData);
		($this->buffer .= ($this->isInternal ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleCommandRequest($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class CommandBlockUpdatePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::COMMAND_BLOCK_UPDATE_PACKET;

	/** @var bool */
	public $isBlock;

	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;
	/** @var int */
	public $commandBlockMode;
	/** @var bool */
	public $isRedstoneMode;
	/** @var bool */
	public $isConditional;

	/** @var int */
	public $minecartEid;

	/** @var string */
	public $command;
	/** @var string */
	public $lastOutput;
	/** @var string */
	public $name;
	/** @var bool */
	public $shouldTrackOutput;
	/** @var int */
	public $tickDelay;
	/** @var bool */
	public $executeOnFirstTick;

	protected function decodePayload(){
		$this->isBlock = (($this->get(1) !== "\x00"));

		if($this->isBlock){
			$this->getBlockPosition($this->x, $this->y, $this->z);
			$this->commandBlockMode = $this->getUnsignedVarInt();
			$this->isRedstoneMode = (($this->get(1) !== "\x00"));
			$this->isConditional = (($this->get(1) !== "\x00"));
		}else{
			//Minecart with command block
			$this->minecartEid = $this->getEntityRuntimeId();
		}

		$this->command = $this->getString();
		$this->lastOutput = $this->getString();
		$this->name = $this->getString();

		$this->shouldTrackOutput = (($this->get(1) !== "\x00"));
		$this->tickDelay = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$this->executeOnFirstTick = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		($this->buffer .= ($this->isBlock ? "\x01" : "\x00"));

		if($this->isBlock){
			$this->putBlockPosition($this->x, $this->y, $this->z);
			$this->putUnsignedVarInt($this->commandBlockMode);
			($this->buffer .= ($this->isRedstoneMode ? "\x01" : "\x00"));
			($this->buffer .= ($this->isConditional ? "\x01" : "\x00"));
		}else{
			$this->putEntityRuntimeId($this->minecartEid);
		}

		$this->putString($this->command);
		$this->putString($this->lastOutput);
		$this->putString($this->name);

		($this->buffer .= ($this->shouldTrackOutput ? "\x01" : "\x00"));
		($this->buffer .= (\pack("V", $this->tickDelay)));
		($this->buffer .= ($this->executeOnFirstTick ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleCommandBlockUpdate($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
use pocketmine\network\mcpe\protocol\types\CommandOutputMessage;
use function count;

class CommandOutputPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::COMMAND_OUTPUT_PACKET;

	/** @var CommandOriginData */
	public $originData;
	/** @var int */
	public $outputType;
	/** @var int */
	public $successCount;
	/** @var CommandOutputMessage[] */
	public $messages = [];
	/** @var string */
	public $unknownString;

	protected function decodePayload(){
		$this->originData = $this->getCommandOriginData();
		$this->outputType = (\ord($this->get(1)));
		$this->successCount = $this->getUnsignedVarInt();

		for($i = 0, $size = $this->getUnsignedVarInt(); $i < $size; ++$i){
			$this->messages[] = $this->getCommandMessage();
		}

		if($this->outputType === 4){
			$this->unknownString = $this->getString();
		}
	}

	protected function getCommandMessage() : CommandOutputMessage{
		$message = new CommandOutputMessage();

		$message->isInternal = (($this->get(1) !== "\x00"));
		$message->messageId = $this->getString();

		for($i = 0, $size = $this->getUnsignedVarInt(); $i < $size; ++$i){
			$message->parameters[] = $this->getString();
		}

		return $message;
	}

	protected function encodePayload(){
		$this->putCommandOriginData($this->originData);
		($this->buffer .= \chr($this->outputType));
		$this->putUnsignedVarInt($this->successCount);

		$this->putUnsignedVarInt(count($this->messages));
		foreach($this->messages as $message){
			$this->putCommandMessage($message);
		}

		if($this->outputType === 4){
			$this->putString($this->unknownString);
		}
	}

	/**
	 * @return void
	 */
	protected function putCommandMessage(CommandOutputMessage $message){
		($this->buffer .= ($message->isInternal ? "\x01" : "\x00"));
		$this->putString($message->messageId);

		$this->putUnsignedVarInt(count($message->parameters));
		foreach($message->parameters as $parameter){
			$this->putString($parameter);
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleCommandOutput($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\WindowTypes;

class UpdateTradePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::UPDATE_TRADE_PACKET;

	//TODO: find fields

	/** @var int */
	public $windowId;
	/** @var int */
	public $windowType = WindowTypes::TRADING; //Mojang hardcoded this -_-
	/** @var int */
	public $thisIsAlwaysZero = 0; //hardcoded to 0
	/** @var int */
	public $tradeTier;
	/** @var int */
	public $traderEid;
	/** @var int */
	public $playerEid;
	/** @var string */
	public $displayName;
	/** @var bool */
	public $isWilling;
	/** @var bool */
	public $isV2Trading;
	/** @var string */
	public $offers;

	protected function decodePayload(){
		$this->windowId = (\ord($this->get(1)));
		$this->windowType = (\ord($this->get(1)));
		$this->thisIsAlwaysZero = $this->getVarInt();
		$this->tradeTier = $this->getVarInt();
		$this->traderEid = $this->getEntityUniqueId();
		$this->playerEid = $this->getEntityUniqueId();
		$this->displayName = $this->getString();
		$this->isWilling = (($this->get(1) !== "\x00"));
		$this->isV2Trading = (($this->get(1) !== "\x00"));
		$this->offers = $this->getRemaining();
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->windowId));
		($this->buffer .= \chr($this->windowType));
		$this->putVarInt($this->thisIsAlwaysZero);
		$this->putVarInt($this->tradeTier);
		$this->putEntityUniqueId($this->traderEid);
		$this->putEntityUniqueId($this->playerEid);
		$this->putString($this->displayName);
		($this->buffer .= ($this->isWilling ? "\x01" : "\x00"));
		($this->buffer .= ($this->isV2Trading ? "\x01" : "\x00"));
		($this->buffer .= $this->offers);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleUpdateTrade($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

interface WindowTypes{

	public const NONE = -9;

	public const INVENTORY = -1;
	public const CONTAINER = 0;
	public const WORKBENCH = 1;
	public const FURNACE = 2;
	public const ENCHANTMENT = 3;
	public const BREWING_STAND = 4;
	public const ANVIL = 5;
	public const DISPENSER = 6;
	public const DROPPER = 7;
	public const HOPPER = 8;
	public const CAULDRON = 9;
	public const MINECART_CHEST = 10;
	public const MINECART_HOPPER = 11;
	public const HORSE = 12;
	public const BEACON = 13;
	public const STRUCTURE_EDITOR = 14;
	public const TRADING = 15;
	public const COMMAND_BLOCK = 16;
	public const JUKEBOX = 17;

	public const COMPOUND_CREATOR = 20;
	public const ELEMENT_CONSTRUCTOR = 21;
	public const MATERIAL_REDUCER = 22;
	public const LAB_TABLE = 23;

	public const BLAST_FURNACE = 27;
	public const SMOKER = 28;
	public const STONECUTTER = 29;

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class UpdateEquipPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::UPDATE_EQUIP_PACKET;

	/** @var int */
	public $windowId;
	/** @var int */
	public $windowType;
	/** @var int */
	public $unknownVarint; //TODO: find out what this is (vanilla always sends 0)
	/** @var int */
	public $entityUniqueId;
	/** @var string */
	public $namedtag;

	protected function decodePayload(){
		$this->windowId = (\ord($this->get(1)));
		$this->windowType = (\ord($this->get(1)));
		$this->unknownVarint = $this->getVarInt();
		$this->entityUniqueId = $this->getEntityUniqueId();
		$this->namedtag = $this->getRemaining();
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->windowId));
		($this->buffer .= \chr($this->windowType));
		$this->putVarInt($this->unknownVarint);
		$this->putEntityUniqueId($this->entityUniqueId);
		($this->buffer .= $this->namedtag);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleUpdateEquip($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ResourcePackType;

class ResourcePackDataInfoPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::RESOURCE_PACK_DATA_INFO_PACKET;

	/** @var string */
	public $packId;
	/** @var int */
	public $maxChunkSize;
	/** @var int */
	public $chunkCount;
	/** @var int */
	public $compressedPackSize;
	/** @var string */
	public $sha256;
	/** @var bool */
	public $isPremium = false;
	/** @var int */
	public $packType = ResourcePackType::RESOURCES; //TODO: check the values for this

	protected function decodePayload(){
		$this->packId = $this->getString();
		$this->maxChunkSize = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$this->chunkCount = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$this->compressedPackSize = (Binary::readLLong($this->get(8)));
		$this->sha256 = $this->getString();
		$this->isPremium = (($this->get(1) !== "\x00"));
		$this->packType = (\ord($this->get(1)));
	}

	protected function encodePayload(){
		$this->putString($this->packId);
		($this->buffer .= (\pack("V", $this->maxChunkSize)));
		($this->buffer .= (\pack("V", $this->chunkCount)));
		($this->buffer .= (\pack("VV", $this->compressedPackSize & 0xFFFFFFFF, $this->compressedPackSize >> 32)));
		$this->putString($this->sha256);
		($this->buffer .= ($this->isPremium ? "\x01" : "\x00"));
		($this->buffer .= \chr($this->packType));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleResourcePackDataInfo($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

final class ResourcePackType{

	private function __construct(){
		//NOOP
	}

	public const INVALID = 0;
	public const ADDON = 1;
	public const CACHED = 2;
	public const COPY_PROTECTED = 3;
	public const BEHAVIORS = 4;
	public const PERSONA_PIECE = 5;
	public const RESOURCES = 6;
	public const SKINS = 7;
	public const WORLD_TEMPLATE = 8;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ResourcePackChunkDataPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::RESOURCE_PACK_CHUNK_DATA_PACKET;

	/** @var string */
	public $packId;
	/** @var int */
	public $chunkIndex;
	/** @var int */
	public $progress;
	/** @var string */
	public $data;

	protected function decodePayload(){
		$this->packId = $this->getString();
		$this->chunkIndex = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$this->progress = (Binary::readLLong($this->get(8)));
		$this->data = $this->getString();
	}

	protected function encodePayload(){
		$this->putString($this->packId);
		($this->buffer .= (\pack("V", $this->chunkIndex)));
		($this->buffer .= (\pack("VV", $this->progress & 0xFFFFFFFF, $this->progress >> 32)));
		$this->putString($this->data);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleResourcePackChunkData($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ResourcePackChunkRequestPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::RESOURCE_PACK_CHUNK_REQUEST_PACKET;

	/** @var string */
	public $packId;
	/** @var int */
	public $chunkIndex;

	protected function decodePayload(){
		$this->packId = $this->getString();
		$this->chunkIndex = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
	}

	protected function encodePayload(){
		$this->putString($this->packId);
		($this->buffer .= (\pack("V", $this->chunkIndex)));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleResourcePackChunkRequest($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class TransferPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::TRANSFER_PACKET;

	/** @var string */
	public $address;
	/** @var int */
	public $port = 19132;

	protected function decodePayload(){
		$this->address = $this->getString();
		$this->port = ((\unpack("v", $this->get(2))[1]));
	}

	protected function encodePayload(){
		$this->putString($this->address);
		($this->buffer .= (\pack("v", $this->port)));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleTransfer($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class PlaySoundPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::PLAY_SOUND_PACKET;

	/** @var string */
	public $soundName;
	/** @var float */
	public $x;
	/** @var float */
	public $y;
	/** @var float */
	public $z;
	/** @var float */
	public $volume;
	/** @var float */
	public $pitch;

	protected function decodePayload(){
		$this->soundName = $this->getString();
		$this->getBlockPosition($this->x, $this->y, $this->z);
		$this->x /= 8;
		$this->y /= 8;
		$this->z /= 8;
		$this->volume = ((\unpack("g", $this->get(4))[1]));
		$this->pitch = ((\unpack("g", $this->get(4))[1]));
	}

	protected function encodePayload(){
		$this->putString($this->soundName);
		$this->putBlockPosition((int) ($this->x * 8), (int) ($this->y * 8), (int) ($this->z * 8));
		($this->buffer .= (\pack("g", $this->volume)));
		($this->buffer .= (\pack("g", $this->pitch)));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handlePlaySound($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class StopSoundPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::STOP_SOUND_PACKET;

	/** @var string */
	public $soundName;
	/** @var bool */
	public $stopAll;

	protected function decodePayload(){
		$this->soundName = $this->getString();
		$this->stopAll = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		$this->putString($this->soundName);
		($this->buffer .= ($this->stopAll ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleStopSound($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetTitlePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_TITLE_PACKET;

	public const TYPE_CLEAR_TITLE = 0;
	public const TYPE_RESET_TITLE = 1;
	public const TYPE_SET_TITLE = 2;
	public const TYPE_SET_SUBTITLE = 3;
	public const TYPE_SET_ACTIONBAR_MESSAGE = 4;
	public const TYPE_SET_ANIMATION_TIMES = 5;

	/** @var int */
	public $type;
	/** @var string */
	public $text = "";
	/** @var int */
	public $fadeInTime = 0;
	/** @var int */
	public $stayTime = 0;
	/** @var int */
	public $fadeOutTime = 0;

	protected function decodePayload(){
		$this->type = $this->getVarInt();
		$this->text = $this->getString();
		$this->fadeInTime = $this->getVarInt();
		$this->stayTime = $this->getVarInt();
		$this->fadeOutTime = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->type);
		$this->putString($this->text);
		$this->putVarInt($this->fadeInTime);
		$this->putVarInt($this->stayTime);
		$this->putVarInt($this->fadeOutTime);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetTitle($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class AddBehaviorTreePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ADD_BEHAVIOR_TREE_PACKET;

	/** @var string */
	public $behaviorTreeJson;

	protected function decodePayload(){
		$this->behaviorTreeJson = $this->getString();
	}

	protected function encodePayload(){
		$this->putString($this->behaviorTreeJson);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAddBehaviorTree($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class StructureBlockUpdatePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::STRUCTURE_BLOCK_UPDATE_PACKET;

	protected function decodePayload(){
		//TODO
	}

	protected function encodePayload(){
		//TODO
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleStructureBlockUpdate($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ShowStoreOfferPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SHOW_STORE_OFFER_PACKET;

	/** @var string */
	public $offerId;
	/** @var bool */
	public $showAll;

	protected function decodePayload(){
		$this->offerId = $this->getString();
		$this->showAll = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		$this->putString($this->offerId);
		($this->buffer .= ($this->showAll ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleShowStoreOffer($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use function count;

class PurchaseReceiptPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::PURCHASE_RECEIPT_PACKET;

	/** @var string[] */
	public $entries = [];

	protected function decodePayload(){
		$count = $this->getUnsignedVarInt();
		for($i = 0; $i < $count; ++$i){
			$this->entries[] = $this->getString();
		}
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt(count($this->entries));
		foreach($this->entries as $entry){
			$this->putString($entry);
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handlePurchaseReceipt($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\utils\UUID;

class PlayerSkinPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::PLAYER_SKIN_PACKET;

	/** @var UUID */
	public $uuid;
	/** @var string */
	public $oldSkinName = "";
	/** @var string */
	public $newSkinName = "";
	/** @var SkinData */
	public $skin;

	protected function decodePayload(){
		$this->uuid = $this->getUUID();
		$this->skin = $this->getSkin();
		$this->newSkinName = $this->getString();
		$this->oldSkinName = $this->getString();
	}

	protected function encodePayload(){
		$this->putUUID($this->uuid);
		$this->putSkin($this->skin);
		$this->putString($this->newSkinName);
		$this->putString($this->oldSkinName);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handlePlayerSkin($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SubClientLoginPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SUB_CLIENT_LOGIN_PACKET;

	/** @var string */
	public $connectionRequestData;

	protected function decodePayload(){
		$this->connectionRequestData = $this->getString();
	}

	protected function encodePayload(){
		$this->putString($this->connectionRequestData);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSubClientLogin($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class AutomationClientConnectPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::AUTOMATION_CLIENT_CONNECT_PACKET;

	/** @var string */
	public $serverUri;

	protected function decodePayload(){
		$this->serverUri = $this->getString();
	}

	protected function encodePayload(){
		$this->putString($this->serverUri);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAutomationClientConnect($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetLastHurtByPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_LAST_HURT_BY_PACKET;

	/** @var int */
	public $entityTypeId;

	protected function decodePayload(){
		$this->entityTypeId = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putVarInt($this->entityTypeId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetLastHurtBy($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class BookEditPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::BOOK_EDIT_PACKET;

	public const TYPE_REPLACE_PAGE = 0;
	public const TYPE_ADD_PAGE = 1;
	public const TYPE_DELETE_PAGE = 2;
	public const TYPE_SWAP_PAGES = 3;
	public const TYPE_SIGN_BOOK = 4;

	/** @var int */
	public $type;
	/** @var int */
	public $inventorySlot;
	/** @var int */
	public $pageNumber;
	/** @var int */
	public $secondaryPageNumber;

	/** @var string */
	public $text;
	/** @var string */
	public $photoName;

	/** @var string */
	public $title;
	/** @var string */
	public $author;
	/** @var string */
	public $xuid;

	protected function decodePayload(){
		$this->type = (\ord($this->get(1)));
		$this->inventorySlot = (\ord($this->get(1)));

		switch($this->type){
			case self::TYPE_REPLACE_PAGE:
			case self::TYPE_ADD_PAGE:
				$this->pageNumber = (\ord($this->get(1)));
				$this->text = $this->getString();
				$this->photoName = $this->getString();
				break;
			case self::TYPE_DELETE_PAGE:
				$this->pageNumber = (\ord($this->get(1)));
				break;
			case self::TYPE_SWAP_PAGES:
				$this->pageNumber = (\ord($this->get(1)));
				$this->secondaryPageNumber = (\ord($this->get(1)));
				break;
			case self::TYPE_SIGN_BOOK:
				$this->title = $this->getString();
				$this->author = $this->getString();
				$this->xuid = $this->getString();
				break;
			default:
				throw new \UnexpectedValueException("Unknown book edit type $this->type!");
		}
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->type));
		($this->buffer .= \chr($this->inventorySlot));

		switch($this->type){
			case self::TYPE_REPLACE_PAGE:
			case self::TYPE_ADD_PAGE:
				($this->buffer .= \chr($this->pageNumber));
				$this->putString($this->text);
				$this->putString($this->photoName);
				break;
			case self::TYPE_DELETE_PAGE:
				($this->buffer .= \chr($this->pageNumber));
				break;
			case self::TYPE_SWAP_PAGES:
				($this->buffer .= \chr($this->pageNumber));
				($this->buffer .= \chr($this->secondaryPageNumber));
				break;
			case self::TYPE_SIGN_BOOK:
				$this->putString($this->title);
				$this->putString($this->author);
				$this->putString($this->xuid);
				break;
			default:
				throw new \InvalidArgumentException("Unknown book edit type $this->type!");
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleBookEdit($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class NpcRequestPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::NPC_REQUEST_PACKET;

	/** @var int */
	public $entityRuntimeId;
	/** @var int */
	public $requestType;
	/** @var string */
	public $commandString;
	/** @var int */
	public $actionType;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->requestType = (\ord($this->get(1)));
		$this->commandString = $this->getString();
		$this->actionType = (\ord($this->get(1)));
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		($this->buffer .= \chr($this->requestType));
		$this->putString($this->commandString);
		($this->buffer .= \chr($this->actionType));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleNpcRequest($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class PhotoTransferPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::PHOTO_TRANSFER_PACKET;

	/** @var string */
	public $photoName;
	/** @var string */
	public $photoData;
	/** @var string */
	public $bookId; //photos are stored in a sibling directory to the games folder (screenshots/(some UUID)/bookID/example.png)

	protected function decodePayload(){
		$this->photoName = $this->getString();
		$this->photoData = $this->getString();
		$this->bookId = $this->getString();
	}

	protected function encodePayload(){
		$this->putString($this->photoName);
		$this->putString($this->photoData);
		$this->putString($this->bookId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handlePhotoTransfer($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ModalFormRequestPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MODAL_FORM_REQUEST_PACKET;

	/** @var int */
	public $formId;
	/** @var string */
	public $formData; //json

	protected function decodePayload(){
		$this->formId = $this->getUnsignedVarInt();
		$this->formData = $this->getString();
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->formId);
		$this->putString($this->formData);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleModalFormRequest($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ModalFormResponsePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MODAL_FORM_RESPONSE_PACKET;

	/** @var int */
	public $formId;
	/** @var string */
	public $formData; //json

	protected function decodePayload(){
		$this->formId = $this->getUnsignedVarInt();
		$this->formData = $this->getString();
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->formId);
		$this->putString($this->formData);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleModalFormResponse($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ServerSettingsRequestPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SERVER_SETTINGS_REQUEST_PACKET;

	protected function decodePayload(){
		//No payload
	}

	protected function encodePayload(){
		//No payload
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleServerSettingsRequest($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ServerSettingsResponsePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SERVER_SETTINGS_RESPONSE_PACKET;

	/** @var int */
	public $formId;
	/** @var string */
	public $formData; //json

	protected function decodePayload(){
		$this->formId = $this->getUnsignedVarInt();
		$this->formData = $this->getString();
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->formId);
		$this->putString($this->formData);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleServerSettingsResponse($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ShowProfilePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SHOW_PROFILE_PACKET;

	/** @var string */
	public $xuid;

	protected function decodePayload(){
		$this->xuid = $this->getString();
	}

	protected function encodePayload(){
		$this->putString($this->xuid);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleShowProfile($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetDefaultGameTypePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_DEFAULT_GAME_TYPE_PACKET;

	/** @var int */
	public $gamemode;

	protected function decodePayload(){
		$this->gamemode = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->gamemode);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetDefaultGameType($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class RemoveObjectivePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::REMOVE_OBJECTIVE_PACKET;

	/** @var string */
	public $objectiveName;

	protected function decodePayload(){
		$this->objectiveName = $this->getString();
	}

	protected function encodePayload(){
		$this->putString($this->objectiveName);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleRemoveObjective($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetDisplayObjectivePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_DISPLAY_OBJECTIVE_PACKET;

	/** @var string */
	public $displaySlot;
	/** @var string */
	public $objectiveName;
	/** @var string */
	public $displayName;
	/** @var string */
	public $criteriaName;
	/** @var int */
	public $sortOrder;

	protected function decodePayload(){
		$this->displaySlot = $this->getString();
		$this->objectiveName = $this->getString();
		$this->displayName = $this->getString();
		$this->criteriaName = $this->getString();
		$this->sortOrder = $this->getVarInt();
	}

	protected function encodePayload(){
		$this->putString($this->displaySlot);
		$this->putString($this->objectiveName);
		$this->putString($this->displayName);
		$this->putString($this->criteriaName);
		$this->putVarInt($this->sortOrder);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetDisplayObjective($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ScorePacketEntry;
use function count;

class SetScorePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_SCORE_PACKET;

	public const TYPE_CHANGE = 0;
	public const TYPE_REMOVE = 1;

	/** @var int */
	public $type;
	/** @var ScorePacketEntry[] */
	public $entries = [];

	protected function decodePayload(){
		$this->type = (\ord($this->get(1)));
		for($i = 0, $i2 = $this->getUnsignedVarInt(); $i < $i2; ++$i){
			$entry = new ScorePacketEntry();
			$entry->scoreboardId = $this->getVarLong();
			$entry->objectiveName = $this->getString();
			$entry->score = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
			if($this->type !== self::TYPE_REMOVE){
				$entry->type = (\ord($this->get(1)));
				switch($entry->type){
					case ScorePacketEntry::TYPE_PLAYER:
					case ScorePacketEntry::TYPE_ENTITY:
						$entry->entityUniqueId = $this->getEntityUniqueId();
						break;
					case ScorePacketEntry::TYPE_FAKE_PLAYER:
						$entry->customName = $this->getString();
						break;
					default:
						throw new \UnexpectedValueException("Unknown entry type $entry->type");
				}
			}
			$this->entries[] = $entry;
		}
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->type));
		$this->putUnsignedVarInt(count($this->entries));
		foreach($this->entries as $entry){
			$this->putVarLong($entry->scoreboardId);
			$this->putString($entry->objectiveName);
			($this->buffer .= (\pack("V", $entry->score)));
			if($this->type !== self::TYPE_REMOVE){
				($this->buffer .= \chr($entry->type));
				switch($entry->type){
					case ScorePacketEntry::TYPE_PLAYER:
					case ScorePacketEntry::TYPE_ENTITY:
						$this->putEntityUniqueId($entry->entityUniqueId);
						break;
					case ScorePacketEntry::TYPE_FAKE_PLAYER:
						$this->putString($entry->customName);
						break;
					default:
						throw new \InvalidArgumentException("Unknown entry type $entry->type");
				}
			}
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetScore($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class LabTablePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::LAB_TABLE_PACKET;

	/** @var int */
	public $uselessByte; //0 for client -> server, 1 for server -> client. Seems useless.

	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;

	/** @var int */
	public $reactionType;

	protected function decodePayload(){
		$this->uselessByte = (\ord($this->get(1)));
		$this->getSignedBlockPosition($this->x, $this->y, $this->z);
		$this->reactionType = (\ord($this->get(1)));
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->uselessByte));
		$this->putSignedBlockPosition($this->x, $this->y, $this->z);
		($this->buffer .= \chr($this->reactionType));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleLabTable($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class UpdateBlockSyncedPacket extends UpdateBlockPacket{
	public const NETWORK_ID = ProtocolInfo::UPDATE_BLOCK_SYNCED_PACKET;

	/** @var int */
	public $entityUniqueId = 0;
	/** @var int */
	public $uvarint64_2 = 0;

	protected function decodePayload(){
		parent::decodePayload();
		$this->entityUniqueId = $this->getUnsignedVarLong();
		$this->uvarint64_2 = $this->getUnsignedVarLong();
	}

	protected function encodePayload(){
		parent::encodePayload();
		$this->putUnsignedVarLong($this->entityUniqueId);
		$this->putUnsignedVarLong($this->uvarint64_2);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleUpdateBlockSynced($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class MoveActorDeltaPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MOVE_ACTOR_DELTA_PACKET;

	public const FLAG_HAS_X = 0x01;
	public const FLAG_HAS_Y = 0x02;
	public const FLAG_HAS_Z = 0x04;
	public const FLAG_HAS_ROT_X = 0x08;
	public const FLAG_HAS_ROT_Y = 0x10;
	public const FLAG_HAS_ROT_Z = 0x20;

	/** @var int */
	public $entityRuntimeId;
	/** @var int */
	public $flags;
	/** @var int */
	public $xDiff = 0;
	/** @var int */
	public $yDiff = 0;
	/** @var int */
	public $zDiff = 0;
	/** @var float */
	public $xRot = 0.0;
	/** @var float */
	public $yRot = 0.0;
	/** @var float */
	public $zRot = 0.0;

	private function maybeReadCoord(int $flag) : int{
		if(($this->flags & $flag) !== 0){
			return $this->getVarInt();
		}
		return 0;
	}

	private function maybeReadRotation(int $flag) : float{
		if(($this->flags & $flag) !== 0){
			return $this->getByteRotation();
		}
		return 0.0;
	}

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->flags = ((\unpack("v", $this->get(2))[1]));
		$this->xDiff = $this->maybeReadCoord(self::FLAG_HAS_X);
		$this->yDiff = $this->maybeReadCoord(self::FLAG_HAS_Y);
		$this->zDiff = $this->maybeReadCoord(self::FLAG_HAS_Z);
		$this->xRot = $this->maybeReadRotation(self::FLAG_HAS_ROT_X);
		$this->yRot = $this->maybeReadRotation(self::FLAG_HAS_ROT_Y);
		$this->zRot = $this->maybeReadRotation(self::FLAG_HAS_ROT_Z);
	}

	private function maybeWriteCoord(int $flag, int $val) : void{
		if(($this->flags & $flag) !== 0){
			$this->putVarInt($val);
		}
	}

	private function maybeWriteRotation(int $flag, float $val) : void{
		if(($this->flags & $flag) !== 0){
			$this->putByteRotation($val);
		}
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
		($this->buffer .= (\pack("v", $this->flags)));
		$this->maybeWriteCoord(self::FLAG_HAS_X, $this->xDiff);
		$this->maybeWriteCoord(self::FLAG_HAS_Y, $this->yDiff);
		$this->maybeWriteCoord(self::FLAG_HAS_Z, $this->zDiff);
		$this->maybeWriteRotation(self::FLAG_HAS_ROT_X, $this->xRot);
		$this->maybeWriteRotation(self::FLAG_HAS_ROT_Y, $this->yRot);
		$this->maybeWriteRotation(self::FLAG_HAS_ROT_Z, $this->zRot);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleMoveActorDelta($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ScoreboardIdentityPacketEntry;
use function count;

class SetScoreboardIdentityPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_SCOREBOARD_IDENTITY_PACKET;

	public const TYPE_REGISTER_IDENTITY = 0;
	public const TYPE_CLEAR_IDENTITY = 1;

	/** @var int */
	public $type;
	/** @var ScoreboardIdentityPacketEntry[] */
	public $entries = [];

	protected function decodePayload(){
		$this->type = (\ord($this->get(1)));
		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$entry = new ScoreboardIdentityPacketEntry();
			$entry->scoreboardId = $this->getVarLong();
			if($this->type === self::TYPE_REGISTER_IDENTITY){
				$entry->entityUniqueId = $this->getEntityUniqueId();
			}

			$this->entries[] = $entry;
		}
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->type));
		$this->putUnsignedVarInt(count($this->entries));
		foreach($this->entries as $entry){
			$this->putVarLong($entry->scoreboardId);
			if($this->type === self::TYPE_REGISTER_IDENTITY){
				$this->putEntityUniqueId($entry->entityUniqueId);
			}
		}
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetScoreboardIdentity($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SetLocalPlayerAsInitializedPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SET_LOCAL_PLAYER_AS_INITIALIZED_PACKET;

	/** @var int */
	public $entityRuntimeId;

	protected function decodePayload(){
		$this->entityRuntimeId = $this->getEntityRuntimeId();
	}

	protected function encodePayload(){
		$this->putEntityRuntimeId($this->entityRuntimeId);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSetLocalPlayerAsInitialized($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use function count;

class UpdateSoftEnumPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::UPDATE_SOFT_ENUM_PACKET;

	public const TYPE_ADD = 0;
	public const TYPE_REMOVE = 1;
	public const TYPE_SET = 2;

	/** @var string */
	public $enumName;
	/** @var string[] */
	public $values = [];
	/** @var int */
	public $type;

	protected function decodePayload(){
		$this->enumName = $this->getString();
		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$this->values[] = $this->getString();
		}
		$this->type = (\ord($this->get(1)));
	}

	protected function encodePayload(){
		$this->putString($this->enumName);
		$this->putUnsignedVarInt(count($this->values));
		foreach($this->values as $v){
			$this->putString($v);
		}
		($this->buffer .= \chr($this->type));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleUpdateSoftEnum($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class NetworkStackLatencyPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::NETWORK_STACK_LATENCY_PACKET;

	/** @var int */
	public $timestamp;
	/** @var bool */
	public $needResponse;

	protected function decodePayload(){
		$this->timestamp = (Binary::readLLong($this->get(8)));
		$this->needResponse = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		($this->buffer .= (\pack("VV", $this->timestamp & 0xFFFFFFFF, $this->timestamp >> 32)));
		($this->buffer .= ($this->needResponse ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleNetworkStackLatency($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ScriptCustomEventPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SCRIPT_CUSTOM_EVENT_PACKET;

	/** @var string */
	public $eventName;
	/** @var string json data */
	public $eventData;

	protected function decodePayload(){
		$this->eventName = $this->getString();
		$this->eventData = $this->getString();
	}

	protected function encodePayload(){
		$this->putString($this->eventName);
		$this->putString($this->eventData);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleScriptCustomEvent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\DimensionIds;

class SpawnParticleEffectPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::SPAWN_PARTICLE_EFFECT_PACKET;

	/** @var int */
	public $dimensionId = DimensionIds::OVERWORLD; //wtf mojang
	/** @var int */
	public $entityUniqueId = -1; //default none
	/** @var Vector3 */
	public $position;
	/** @var string */
	public $particleName;

	protected function decodePayload(){
		$this->dimensionId = (\ord($this->get(1)));
		$this->entityUniqueId = $this->getEntityUniqueId();
		$this->position = $this->getVector3();
		$this->particleName = $this->getString();
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->dimensionId));
		$this->putEntityUniqueId($this->entityUniqueId);
		$this->putVector3($this->position);
		$this->putString($this->particleName);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleSpawnParticleEffect($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use function file_get_contents;

class AvailableActorIdentifiersPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::AVAILABLE_ACTOR_IDENTIFIERS_PACKET;

	/** @var string|null */
	private static $DEFAULT_NBT_CACHE = null;

	/** @var string */
	public $namedtag;

	protected function decodePayload(){
		$this->namedtag = $this->getRemaining();
	}

	protected function encodePayload(){
		($this->buffer .=  			$this->namedtag ?? 			self::$DEFAULT_NBT_CACHE ?? 			(self::$DEFAULT_NBT_CACHE = file_get_contents(\pocketmine\RESOURCE_PATH . '/vanilla/entity_identifiers.nbt')) 		);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleAvailableActorIdentifiers($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

/**
 * Useless leftover from a 1.9 refactor, does nothing
 */
class LevelSoundEventPacketV2 extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::LEVEL_SOUND_EVENT_PACKET_V2;

	/** @var int */
	public $sound;
	/** @var Vector3 */
	public $position;
	/** @var int */
	public $extraData = -1;
	/** @var string */
	public $entityType = ":"; //???
	/** @var bool */
	public $isBabyMob = false; //...
	/** @var bool */
	public $disableRelativeVolume = false;

	protected function decodePayload(){
		$this->sound = (\ord($this->get(1)));
		$this->position = $this->getVector3();
		$this->extraData = $this->getVarInt();
		$this->entityType = $this->getString();
		$this->isBabyMob = (($this->get(1) !== "\x00"));
		$this->disableRelativeVolume = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		($this->buffer .= \chr($this->sound));
		$this->putVector3($this->position);
		$this->putVarInt($this->extraData);
		$this->putString($this->entityType);
		($this->buffer .= ($this->isBabyMob ? "\x01" : "\x00"));
		($this->buffer .= ($this->disableRelativeVolume ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleLevelSoundEventPacketV2($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class NetworkChunkPublisherUpdatePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::NETWORK_CHUNK_PUBLISHER_UPDATE_PACKET;

	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;
	/** @var int */
	public $radius;

	protected function decodePayload(){
		$this->getSignedBlockPosition($this->x, $this->y, $this->z);
		$this->radius = $this->getUnsignedVarInt();
	}

	protected function encodePayload(){
		$this->putSignedBlockPosition($this->x, $this->y, $this->z);
		$this->putUnsignedVarInt($this->radius);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleNetworkChunkPublisherUpdate($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use function file_get_contents;

class BiomeDefinitionListPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::BIOME_DEFINITION_LIST_PACKET;

	/** @var string|null */
	private static $DEFAULT_NBT_CACHE = null;

	/** @var string */
	public $namedtag;

	protected function decodePayload(){
		$this->namedtag = $this->getRemaining();
	}

	protected function encodePayload(){
		($this->buffer .=  			$this->namedtag ?? 			self::$DEFAULT_NBT_CACHE ?? 			(self::$DEFAULT_NBT_CACHE = file_get_contents(\pocketmine\RESOURCE_PATH . '/vanilla/biome_definitions.nbt')) 		);
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleBiomeDefinitionList($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;

class LevelSoundEventPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::LEVEL_SOUND_EVENT_PACKET;

	public const SOUND_ITEM_USE_ON = 0;
	public const SOUND_HIT = 1;
	public const SOUND_STEP = 2;
	public const SOUND_FLY = 3;
	public const SOUND_JUMP = 4;
	public const SOUND_BREAK = 5;
	public const SOUND_PLACE = 6;
	public const SOUND_HEAVY_STEP = 7;
	public const SOUND_GALLOP = 8;
	public const SOUND_FALL = 9;
	public const SOUND_AMBIENT = 10;
	public const SOUND_AMBIENT_BABY = 11;
	public const SOUND_AMBIENT_IN_WATER = 12;
	public const SOUND_BREATHE = 13;
	public const SOUND_DEATH = 14;
	public const SOUND_DEATH_IN_WATER = 15;
	public const SOUND_DEATH_TO_ZOMBIE = 16;
	public const SOUND_HURT = 17;
	public const SOUND_HURT_IN_WATER = 18;
	public const SOUND_MAD = 19;
	public const SOUND_BOOST = 20;
	public const SOUND_BOW = 21;
	public const SOUND_SQUISH_BIG = 22;
	public const SOUND_SQUISH_SMALL = 23;
	public const SOUND_FALL_BIG = 24;
	public const SOUND_FALL_SMALL = 25;
	public const SOUND_SPLASH = 26;
	public const SOUND_FIZZ = 27;
	public const SOUND_FLAP = 28;
	public const SOUND_SWIM = 29;
	public const SOUND_DRINK = 30;
	public const SOUND_EAT = 31;
	public const SOUND_TAKEOFF = 32;
	public const SOUND_SHAKE = 33;
	public const SOUND_PLOP = 34;
	public const SOUND_LAND = 35;
	public const SOUND_SADDLE = 36;
	public const SOUND_ARMOR = 37;
	public const SOUND_MOB_ARMOR_STAND_PLACE = 38;
	public const SOUND_ADD_CHEST = 39;
	public const SOUND_THROW = 40;
	public const SOUND_ATTACK = 41;
	public const SOUND_ATTACK_NODAMAGE = 42;
	public const SOUND_ATTACK_STRONG = 43;
	public const SOUND_WARN = 44;
	public const SOUND_SHEAR = 45;
	public const SOUND_MILK = 46;
	public const SOUND_THUNDER = 47;
	public const SOUND_EXPLODE = 48;
	public const SOUND_FIRE = 49;
	public const SOUND_IGNITE = 50;
	public const SOUND_FUSE = 51;
	public const SOUND_STARE = 52;
	public const SOUND_SPAWN = 53;
	public const SOUND_SHOOT = 54;
	public const SOUND_BREAK_BLOCK = 55;
	public const SOUND_LAUNCH = 56;
	public const SOUND_BLAST = 57;
	public const SOUND_LARGE_BLAST = 58;
	public const SOUND_TWINKLE = 59;
	public const SOUND_REMEDY = 60;
	public const SOUND_UNFECT = 61;
	public const SOUND_LEVELUP = 62;
	public const SOUND_BOW_HIT = 63;
	public const SOUND_BULLET_HIT = 64;
	public const SOUND_EXTINGUISH_FIRE = 65;
	public const SOUND_ITEM_FIZZ = 66;
	public const SOUND_CHEST_OPEN = 67;
	public const SOUND_CHEST_CLOSED = 68;
	public const SOUND_SHULKERBOX_OPEN = 69;
	public const SOUND_SHULKERBOX_CLOSED = 70;
	public const SOUND_ENDERCHEST_OPEN = 71;
	public const SOUND_ENDERCHEST_CLOSED = 72;
	public const SOUND_POWER_ON = 73;
	public const SOUND_POWER_OFF = 74;
	public const SOUND_ATTACH = 75;
	public const SOUND_DETACH = 76;
	public const SOUND_DENY = 77;
	public const SOUND_TRIPOD = 78;
	public const SOUND_POP = 79;
	public const SOUND_DROP_SLOT = 80;
	public const SOUND_NOTE = 81;
	public const SOUND_THORNS = 82;
	public const SOUND_PISTON_IN = 83;
	public const SOUND_PISTON_OUT = 84;
	public const SOUND_PORTAL = 85;
	public const SOUND_WATER = 86;
	public const SOUND_LAVA_POP = 87;
	public const SOUND_LAVA = 88;
	public const SOUND_BURP = 89;
	public const SOUND_BUCKET_FILL_WATER = 90;
	public const SOUND_BUCKET_FILL_LAVA = 91;
	public const SOUND_BUCKET_EMPTY_WATER = 92;
	public const SOUND_BUCKET_EMPTY_LAVA = 93;
	public const SOUND_ARMOR_EQUIP_CHAIN = 94;
	public const SOUND_ARMOR_EQUIP_DIAMOND = 95;
	public const SOUND_ARMOR_EQUIP_GENERIC = 96;
	public const SOUND_ARMOR_EQUIP_GOLD = 97;
	public const SOUND_ARMOR_EQUIP_IRON = 98;
	public const SOUND_ARMOR_EQUIP_LEATHER = 99;
	public const SOUND_ARMOR_EQUIP_ELYTRA = 100;
	public const SOUND_RECORD_13 = 101;
	public const SOUND_RECORD_CAT = 102;
	public const SOUND_RECORD_BLOCKS = 103;
	public const SOUND_RECORD_CHIRP = 104;
	public const SOUND_RECORD_FAR = 105;
	public const SOUND_RECORD_MALL = 106;
	public const SOUND_RECORD_MELLOHI = 107;
	public const SOUND_RECORD_STAL = 108;
	public const SOUND_RECORD_STRAD = 109;
	public const SOUND_RECORD_WARD = 110;
	public const SOUND_RECORD_11 = 111;
	public const SOUND_RECORD_WAIT = 112;
	public const SOUND_STOP_RECORD = 113; //Not really a sound
	public const SOUND_FLOP = 114;
	public const SOUND_ELDERGUARDIAN_CURSE = 115;
	public const SOUND_MOB_WARNING = 116;
	public const SOUND_MOB_WARNING_BABY = 117;
	public const SOUND_TELEPORT = 118;
	public const SOUND_SHULKER_OPEN = 119;
	public const SOUND_SHULKER_CLOSE = 120;
	public const SOUND_HAGGLE = 121;
	public const SOUND_HAGGLE_YES = 122;
	public const SOUND_HAGGLE_NO = 123;
	public const SOUND_HAGGLE_IDLE = 124;
	public const SOUND_CHORUSGROW = 125;
	public const SOUND_CHORUSDEATH = 126;
	public const SOUND_GLASS = 127;
	public const SOUND_POTION_BREWED = 128;
	public const SOUND_CAST_SPELL = 129;
	public const SOUND_PREPARE_ATTACK = 130;
	public const SOUND_PREPARE_SUMMON = 131;
	public const SOUND_PREPARE_WOLOLO = 132;
	public const SOUND_FANG = 133;
	public const SOUND_CHARGE = 134;
	public const SOUND_CAMERA_TAKE_PICTURE = 135;
	public const SOUND_LEASHKNOT_PLACE = 136;
	public const SOUND_LEASHKNOT_BREAK = 137;
	public const SOUND_GROWL = 138;
	public const SOUND_WHINE = 139;
	public const SOUND_PANT = 140;
	public const SOUND_PURR = 141;
	public const SOUND_PURREOW = 142;
	public const SOUND_DEATH_MIN_VOLUME = 143;
	public const SOUND_DEATH_MID_VOLUME = 144;
	public const SOUND_IMITATE_BLAZE = 145;
	public const SOUND_IMITATE_CAVE_SPIDER = 146;
	public const SOUND_IMITATE_CREEPER = 147;
	public const SOUND_IMITATE_ELDER_GUARDIAN = 148;
	public const SOUND_IMITATE_ENDER_DRAGON = 149;
	public const SOUND_IMITATE_ENDERMAN = 150;

	public const SOUND_IMITATE_EVOCATION_ILLAGER = 152;
	public const SOUND_IMITATE_GHAST = 153;
	public const SOUND_IMITATE_HUSK = 154;
	public const SOUND_IMITATE_ILLUSION_ILLAGER = 155;
	public const SOUND_IMITATE_MAGMA_CUBE = 156;
	public const SOUND_IMITATE_POLAR_BEAR = 157;
	public const SOUND_IMITATE_SHULKER = 158;
	public const SOUND_IMITATE_SILVERFISH = 159;
	public const SOUND_IMITATE_SKELETON = 160;
	public const SOUND_IMITATE_SLIME = 161;
	public const SOUND_IMITATE_SPIDER = 162;
	public const SOUND_IMITATE_STRAY = 163;
	public const SOUND_IMITATE_VEX = 164;
	public const SOUND_IMITATE_VINDICATION_ILLAGER = 165;
	public const SOUND_IMITATE_WITCH = 166;
	public const SOUND_IMITATE_WITHER = 167;
	public const SOUND_IMITATE_WITHER_SKELETON = 168;
	public const SOUND_IMITATE_WOLF = 169;
	public const SOUND_IMITATE_ZOMBIE = 170;
	public const SOUND_IMITATE_ZOMBIE_PIGMAN = 171;
	public const SOUND_IMITATE_ZOMBIE_VILLAGER = 172;
	public const SOUND_BLOCK_END_PORTAL_FRAME_FILL = 173;
	public const SOUND_BLOCK_END_PORTAL_SPAWN = 174;
	public const SOUND_RANDOM_ANVIL_USE = 175;
	public const SOUND_BOTTLE_DRAGONBREATH = 176;
	public const SOUND_PORTAL_TRAVEL = 177;
	public const SOUND_ITEM_TRIDENT_HIT = 178;
	public const SOUND_ITEM_TRIDENT_RETURN = 179;
	public const SOUND_ITEM_TRIDENT_RIPTIDE_1 = 180;
	public const SOUND_ITEM_TRIDENT_RIPTIDE_2 = 181;
	public const SOUND_ITEM_TRIDENT_RIPTIDE_3 = 182;
	public const SOUND_ITEM_TRIDENT_THROW = 183;
	public const SOUND_ITEM_TRIDENT_THUNDER = 184;
	public const SOUND_ITEM_TRIDENT_HIT_GROUND = 185;
	public const SOUND_DEFAULT = 186;
	public const SOUND_BLOCK_FLETCHING_TABLE_USE = 187;
	public const SOUND_ELEMCONSTRUCT_OPEN = 188;
	public const SOUND_ICEBOMB_HIT = 189;
	public const SOUND_BALLOONPOP = 190;
	public const SOUND_LT_REACTION_ICEBOMB = 191;
	public const SOUND_LT_REACTION_BLEACH = 192;
	public const SOUND_LT_REACTION_EPASTE = 193;
	public const SOUND_LT_REACTION_EPASTE2 = 194;

	public const SOUND_LT_REACTION_FERTILIZER = 199;
	public const SOUND_LT_REACTION_FIREBALL = 200;
	public const SOUND_LT_REACTION_MGSALT = 201;
	public const SOUND_LT_REACTION_MISCFIRE = 202;
	public const SOUND_LT_REACTION_FIRE = 203;
	public const SOUND_LT_REACTION_MISCEXPLOSION = 204;
	public const SOUND_LT_REACTION_MISCMYSTICAL = 205;
	public const SOUND_LT_REACTION_MISCMYSTICAL2 = 206;
	public const SOUND_LT_REACTION_PRODUCT = 207;
	public const SOUND_SPARKLER_USE = 208;
	public const SOUND_GLOWSTICK_USE = 209;
	public const SOUND_SPARKLER_ACTIVE = 210;
	public const SOUND_CONVERT_TO_DROWNED = 211;
	public const SOUND_BUCKET_FILL_FISH = 212;
	public const SOUND_BUCKET_EMPTY_FISH = 213;
	public const SOUND_BUBBLE_UP = 214;
	public const SOUND_BUBBLE_DOWN = 215;
	public const SOUND_BUBBLE_POP = 216;
	public const SOUND_BUBBLE_UPINSIDE = 217;
	public const SOUND_BUBBLE_DOWNINSIDE = 218;
	public const SOUND_HURT_BABY = 219;
	public const SOUND_DEATH_BABY = 220;
	public const SOUND_STEP_BABY = 221;

	public const SOUND_BORN = 223;
	public const SOUND_BLOCK_TURTLE_EGG_BREAK = 224;
	public const SOUND_BLOCK_TURTLE_EGG_CRACK = 225;
	public const SOUND_BLOCK_TURTLE_EGG_HATCH = 226;

	public const SOUND_BLOCK_TURTLE_EGG_ATTACK = 228;
	public const SOUND_BEACON_ACTIVATE = 229;
	public const SOUND_BEACON_AMBIENT = 230;
	public const SOUND_BEACON_DEACTIVATE = 231;
	public const SOUND_BEACON_POWER = 232;
	public const SOUND_CONDUIT_ACTIVATE = 233;
	public const SOUND_CONDUIT_AMBIENT = 234;
	public const SOUND_CONDUIT_ATTACK = 235;
	public const SOUND_CONDUIT_DEACTIVATE = 236;
	public const SOUND_CONDUIT_SHORT = 237;
	public const SOUND_SWOOP = 238;
	public const SOUND_BLOCK_BAMBOO_SAPLING_PLACE = 239;
	public const SOUND_PRESNEEZE = 240;
	public const SOUND_SNEEZE = 241;
	public const SOUND_AMBIENT_TAME = 242;
	public const SOUND_SCARED = 243;
	public const SOUND_BLOCK_SCAFFOLDING_CLIMB = 244;
	public const SOUND_CROSSBOW_LOADING_START = 245;
	public const SOUND_CROSSBOW_LOADING_MIDDLE = 246;
	public const SOUND_CROSSBOW_LOADING_END = 247;
	public const SOUND_CROSSBOW_SHOOT = 248;
	public const SOUND_CROSSBOW_QUICK_CHARGE_START = 249;
	public const SOUND_CROSSBOW_QUICK_CHARGE_MIDDLE = 250;
	public const SOUND_CROSSBOW_QUICK_CHARGE_END = 251;
	public const SOUND_AMBIENT_AGGRESSIVE = 252;
	public const SOUND_AMBIENT_WORRIED = 253;
	public const SOUND_CANT_BREED = 254;
	public const SOUND_ITEM_SHIELD_BLOCK = 255;
	public const SOUND_ITEM_BOOK_PUT = 256;
	public const SOUND_BLOCK_GRINDSTONE_USE = 257;
	public const SOUND_BLOCK_BELL_HIT = 258;
	public const SOUND_BLOCK_CAMPFIRE_CRACKLE = 259;
	public const SOUND_ROAR = 260;
	public const SOUND_STUN = 261;
	public const SOUND_BLOCK_SWEET_BERRY_BUSH_HURT = 262;
	public const SOUND_BLOCK_SWEET_BERRY_BUSH_PICK = 263;
	public const SOUND_BLOCK_CARTOGRAPHY_TABLE_USE = 264;
	public const SOUND_BLOCK_STONECUTTER_USE = 265;
	public const SOUND_BLOCK_COMPOSTER_EMPTY = 266;
	public const SOUND_BLOCK_COMPOSTER_FILL = 267;
	public const SOUND_BLOCK_COMPOSTER_FILL_SUCCESS = 268;
	public const SOUND_BLOCK_COMPOSTER_READY = 269;
	public const SOUND_BLOCK_BARREL_OPEN = 270;
	public const SOUND_BLOCK_BARREL_CLOSE = 271;
	public const SOUND_RAID_HORN = 272;
	public const SOUND_BLOCK_LOOM_USE = 273;
	public const SOUND_AMBIENT_IN_RAID = 274;
	public const SOUND_UI_CARTOGRAPHY_TABLE_TAKE_RESULT = 275;
	public const SOUND_UI_STONECUTTER_TAKE_RESULT = 276;
	public const SOUND_UI_LOOM_TAKE_RESULT = 277;
	public const SOUND_BLOCK_SMOKER_SMOKE = 278;
	public const SOUND_BLOCK_BLASTFURNACE_FIRE_CRACKLE = 279;
	public const SOUND_BLOCK_SMITHING_TABLE_USE = 280;
	public const SOUND_UNDEFINED = 281;

	/** @var int */
	public $sound;
	/** @var Vector3 */
	public $position;
	/** @var int */
	public $extraData = -1;
	/** @var string */
	public $entityType = ":"; //???
	/** @var bool */
	public $isBabyMob = false; //...
	/** @var bool */
	public $disableRelativeVolume = false;

	protected function decodePayload(){
		$this->sound = $this->getUnsignedVarInt();
		$this->position = $this->getVector3();
		$this->extraData = $this->getVarInt();
		$this->entityType = $this->getString();
		$this->isBabyMob = (($this->get(1) !== "\x00"));
		$this->disableRelativeVolume = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload(){
		$this->putUnsignedVarInt($this->sound);
		$this->putVector3($this->position);
		$this->putVarInt($this->extraData);
		$this->putString($this->entityType);
		($this->buffer .= ($this->isBabyMob ? "\x01" : "\x00"));
		($this->buffer .= ($this->disableRelativeVolume ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleLevelSoundEvent($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\NetworkSession;

class LevelEventGenericPacket extends DataPacket/* implements ClientboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::LEVEL_EVENT_GENERIC_PACKET;

	/** @var int */
	private $eventId;
	/** @var string network-format NBT */
	private $eventData;

	public static function create(int $eventId, CompoundTag $data) : self{
		$result = new self;
		$result->eventId = $eventId;
		$result->eventData = (new NetworkLittleEndianNBTStream())->write($data);
		return $result;
	}

	public function getEventId() : int{
		return $this->eventId;
	}

	public function getEventData() : string{
		return $this->eventData;
	}

	protected function decodePayload() : void{
		$this->eventId = $this->getVarInt();
		$this->eventData = $this->getRemaining();
	}

	protected function encodePayload() : void{
		$this->putVarInt($this->eventId);
		($this->buffer .= $this->eventData);
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleLevelEventGeneric($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class LecternUpdatePacket extends DataPacket/* implements ServerboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::LECTERN_UPDATE_PACKET;

	/** @var int */
	public $page;
	/** @var int */
	public $totalPages;
	/** @var int */
	public $x;
	/** @var int */
	public $y;
	/** @var int */
	public $z;
	/** @var bool */
	public $dropBook;

	protected function decodePayload() : void{
		$this->page = (\ord($this->get(1)));
		$this->totalPages = (\ord($this->get(1)));
		$this->getBlockPosition($this->x, $this->y, $this->z);
		$this->dropBook = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload() : void{
		($this->buffer .= \chr($this->page));
		($this->buffer .= \chr($this->totalPages));
		$this->putBlockPosition($this->x, $this->y, $this->z);
		($this->buffer .= ($this->dropBook ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleLecternUpdate($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class VideoStreamConnectPacket extends DataPacket/* implements ClientboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::VIDEO_STREAM_CONNECT_PACKET;

	public const ACTION_CONNECT = 0;
	public const ACTION_DISCONNECT = 1;

	/** @var string */
	public $serverUri;
	/** @var float */
	public $frameSendFrequency;
	/** @var int */
	public $action;
	/** @var int */
	public $resolutionX;
	/** @var int */
	public $resolutionY;

	protected function decodePayload() : void{
		$this->serverUri = $this->getString();
		$this->frameSendFrequency = ((\unpack("g", $this->get(4))[1]));
		$this->action = (\ord($this->get(1)));
		$this->resolutionX = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
		$this->resolutionY = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
	}

	protected function encodePayload() : void{
		$this->putString($this->serverUri);
		($this->buffer .= (\pack("g", $this->frameSendFrequency)));
		($this->buffer .= \chr($this->action));
		($this->buffer .= (\pack("V", $this->resolutionX)));
		($this->buffer .= (\pack("V", $this->resolutionY)));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleVideoStreamConnect($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class AddEntityPacket extends DataPacket/* implements ClientboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::ADD_ENTITY_PACKET;

	/** @var int */
	private $uvarint1;

	public static function create(int $uvarint1) : self{
		$result = new self;
		$result->uvarint1 = $uvarint1;
		return $result;
	}

	public function getUvarint1() : int{
		return $this->uvarint1;
	}

	protected function decodePayload() : void{
		$this->uvarint1 = $this->getUnsignedVarInt();
	}

	protected function encodePayload() : void{
		$this->putUnsignedVarInt($this->uvarint1);
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleAddEntity($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class RemoveEntityPacket extends DataPacket/* implements ClientboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::REMOVE_ENTITY_PACKET;

	/** @var int */
	private $uvarint1;

	public static function create(int $uvarint1) : self{
		$result = new self;
		$result->uvarint1 = $uvarint1;
		return $result;
	}

	public function getUvarint1() : int{
		return $this->uvarint1;
	}

	protected function decodePayload() : void{
		$this->uvarint1 = $this->getUnsignedVarInt();
	}

	protected function encodePayload() : void{
		$this->putUnsignedVarInt($this->uvarint1);
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleRemoveEntity($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class ClientCacheStatusPacket extends DataPacket/* implements ServerboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::CLIENT_CACHE_STATUS_PACKET;

	/** @var bool */
	private $enabled;

	public static function create(bool $enabled) : self{
		$result = new self;
		$result->enabled = $enabled;
		return $result;
	}

	public function isEnabled() : bool{
		return $this->enabled;
	}

	protected function decodePayload() : void{
		$this->enabled = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload() : void{
		($this->buffer .= ($this->enabled ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleClientCacheStatus($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class OnScreenTextureAnimationPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::ON_SCREEN_TEXTURE_ANIMATION_PACKET;

	/** @var int */
	public $effectId;

	protected function decodePayload() : void{
		$this->effectId = ((\unpack("V", $this->get(4))[1] << 32 >> 32)); //unsigned
	}

	protected function encodePayload() : void{
		($this->buffer .= (\pack("V", $this->effectId)));
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleOnScreenTextureAnimation($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class MapCreateLockedCopyPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::MAP_CREATE_LOCKED_COPY_PACKET;

	/** @var int */
	public $originalMapId;
	/** @var int */
	public $newMapId;

	protected function decodePayload() : void{
		$this->originalMapId = $this->getEntityUniqueId();
		$this->newMapId = $this->getEntityUniqueId();
	}

	protected function encodePayload() : void{
		$this->putEntityUniqueId($this->originalMapId);
		$this->putEntityUniqueId($this->newMapId);
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleMapCreateLockedCopy($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\StructureSettings;

class StructureTemplateDataRequestPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_REQUEST_PACKET;

	public const TYPE_ALWAYS_LOAD = 1;
	public const TYPE_CREATE_AND_LOAD = 2;

	/** @var string */
	public $structureTemplateName;
	/** @var int */
	public $structureBlockX;
	/** @var int */
	public $structureBlockY;
	/** @var int */
	public $structureBlockZ;
	/** @var StructureSettings */
	public $structureSettings;
	/** @var int */
	public $structureTemplateResponseType;

	protected function decodePayload() : void{
		$this->structureTemplateName = $this->getString();
		$this->getBlockPosition($this->structureBlockX, $this->structureBlockY, $this->structureBlockZ);
		$this->structureSettings = $this->getStructureSettings();
		$this->structureTemplateResponseType = (\ord($this->get(1)));
	}

	protected function encodePayload() : void{
		$this->putString($this->structureTemplateName);
		$this->putBlockPosition($this->structureBlockX, $this->structureBlockY, $this->structureBlockZ);
		$this->putStructureSettings($this->structureSettings);
		($this->buffer .= \chr($this->structureTemplateResponseType));
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleStructureTemplateDataRequest($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class StructureTemplateDataResponsePacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_RESPONSE_PACKET;

	/** @var string */
	public $structureTemplateName;
	/** @var string|null */
	public $namedtag;

	protected function decodePayload() : void{
		$this->structureTemplateName = $this->getString();
		if((($this->get(1) !== "\x00"))){
			$this->namedtag = $this->getRemaining();
		}
	}

	protected function encodePayload() : void{
		$this->putString($this->structureTemplateName);
		($this->buffer .= ($this->namedtag !== null ? "\x01" : "\x00"));
		if($this->namedtag !== null){
			($this->buffer .= $this->namedtag);
		}
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleStructureTemplateDataResponse($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\NetworkSession;

class UpdateBlockPropertiesPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::UPDATE_BLOCK_PROPERTIES_PACKET;

	/** @var string */
	private $nbt;

	public static function create(CompoundTag $data) : self{
		$result = new self;
		$result->nbt = (new NetworkLittleEndianNBTStream())->write($data);
		return $result;
	}

	protected function decodePayload() : void{
		$this->nbt = $this->getRemaining();
	}

	protected function encodePayload() : void{
		($this->buffer .= $this->nbt);
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleUpdateBlockProperties($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use function count;

class ClientCacheBlobStatusPacket extends DataPacket/* implements ServerboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::CLIENT_CACHE_BLOB_STATUS_PACKET;

	/** @var int[] xxHash64 subchunk data hashes */
	private $hitHashes = [];
	/** @var int[] xxHash64 subchunk data hashes */
	private $missHashes = [];

	/**
	 * @param int[] $hitHashes
	 * @param int[] $missHashes
	 */
	public static function create(array $hitHashes, array $missHashes) : self{
		//type checks
		(static function(int ...$hashes) : void{})(...$hitHashes);
		(static function(int ...$hashes) : void{})(...$missHashes);

		$result = new self;
		$result->hitHashes = $hitHashes;
		$result->missHashes = $missHashes;
		return $result;
	}

	/**
	 * @return int[]
	 */
	public function getHitHashes() : array{
		return $this->hitHashes;
	}

	/**
	 * @return int[]
	 */
	public function getMissHashes() : array{
		return $this->missHashes;
	}

	protected function decodePayload() : void{
		$hitCount = $this->getUnsignedVarInt();
		$missCount = $this->getUnsignedVarInt();
		for($i = 0; $i < $hitCount; ++$i){
			$this->hitHashes[] = (Binary::readLLong($this->get(8)));
		}
		for($i = 0; $i < $missCount; ++$i){
			$this->missHashes[] = (Binary::readLLong($this->get(8)));
		}
	}

	protected function encodePayload() : void{
		$this->putUnsignedVarInt(count($this->hitHashes));
		$this->putUnsignedVarInt(count($this->missHashes));
		foreach($this->hitHashes as $hash){
			($this->buffer .= (\pack("VV", $hash & 0xFFFFFFFF, $hash >> 32)));
		}
		foreach($this->missHashes as $hash){
			($this->buffer .= (\pack("VV", $hash & 0xFFFFFFFF, $hash >> 32)));
		}
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleClientCacheBlobStatus($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\ChunkCacheBlob;
use function count;

class ClientCacheMissResponsePacket extends DataPacket/* implements ClientboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::CLIENT_CACHE_MISS_RESPONSE_PACKET;

	/** @var ChunkCacheBlob[] */
	private $blobs = [];

	/**
	 * @param ChunkCacheBlob[] $blobs
	 */
	public static function create(array $blobs) : self{
		//type check
		(static function(ChunkCacheBlob ...$blobs) : void{})(...$blobs);

		$result = new self;
		$result->blobs = $blobs;
		return $result;
	}

	/**
	 * @return ChunkCacheBlob[]
	 */
	public function getBlobs() : array{
		return $this->blobs;
	}

	protected function decodePayload() : void{
		for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
			$hash = (Binary::readLLong($this->get(8)));
			$payload = $this->getString();
			$this->blobs[] = new ChunkCacheBlob($hash, $payload);
		}
	}

	protected function encodePayload() : void{
		$this->putUnsignedVarInt(count($this->blobs));
		foreach($this->blobs as $blob){
			($this->buffer .= (\pack("VV", $blob->getHash() & 0xFFFFFFFF, $blob->getHash() >> 32)));
			$this->putString($blob->getPayload());
		}
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleClientCacheMissResponse($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class EducationSettingsPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::EDUCATION_SETTINGS_PACKET;

	/** @var string */
	private $codeBuilderDefaultUri;
	/** @var bool */
	private $hasQuiz;

	public static function create(string $codeBuilderDefaultUri, bool $hasQuiz) : self{
		$result = new self;
		$result->codeBuilderDefaultUri = $codeBuilderDefaultUri;
		$result->hasQuiz = $hasQuiz;
		return $result;
	}

	public function getCodeBuilderDefaultUri() : string{
		return $this->codeBuilderDefaultUri;
	}

	public function getHasQuiz() : bool{
		return $this->hasQuiz;
	}

	protected function decodePayload() : void{
		$this->codeBuilderDefaultUri = $this->getString();
		$this->hasQuiz = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload() : void{
		$this->putString($this->codeBuilderDefaultUri);
		($this->buffer .= ($this->hasQuiz ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleEducationSettings($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class EmotePacket extends DataPacket/* implements ClientboundPacket, ServerboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::EMOTE_PACKET;

	private const FLAG_SERVER = 1 << 0;

	/** @var int */
	private $entityRuntimeId;
	/** @var string */
	private $emoteId;
	/** @var int */
	private $flags;

	public static function create(int $entityRuntimeId, string $emoteId, int $flags) : self{
		$result = new self;
		$result->entityRuntimeId = $entityRuntimeId;
		$result->emoteId = $emoteId;
		$result->flags = $flags;
		return $result;
	}

	/**
	 * TODO: we can't call this getEntityRuntimeId() because of base class collision (crap architecture, thanks Shoghi)
	 */
	public function getEntityRuntimeIdField() : int{
		return $this->entityRuntimeId;
	}

	public function getEmoteId() : string{
		return $this->emoteId;
	}

	public function getFlags() : int{
		return $this->flags;
	}

	protected function decodePayload() : void{
		$this->entityRuntimeId = $this->getEntityRuntimeId();
		$this->emoteId = $this->getString();
		$this->flags = (\ord($this->get(1)));
	}

	protected function encodePayload() : void{
		$this->putEntityRuntimeId($this->entityRuntimeId);
		$this->putString($this->emoteId);
		($this->buffer .= \chr($this->flags));
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleEmote($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class MultiplayerSettingsPacket extends DataPacket/* implements ServerboundPacket*/{ //TODO: this might be clientbound too, but unsure
	public const NETWORK_ID = ProtocolInfo::MULTIPLAYER_SETTINGS_PACKET;

	public const ACTION_ENABLE_MULTIPLAYER = 0;
	public const ACTION_DISABLE_MULTIPLAYER = 1;
	public const ACTION_REFRESH_JOIN_CODE = 2;

	/** @var int */
	private $action;

	public static function create(int $action) : self{
		$result = new self;
		$result->action = $action;
		return $result;
	}

	public function getAction() : int{
		return $this->action;
	}

	protected function decodePayload() : void{
		$this->action = $this->getVarInt();
	}

	protected function encodePayload() : void{
		$this->putVarInt($this->action);
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleMultiplayerSettings($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class SettingsCommandPacket extends DataPacket/* implements ServerboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::SETTINGS_COMMAND_PACKET;

	/** @var string */
	private $command;
	/** @var bool */
	private $suppressOutput;

	public static function create(string $command, bool $suppressOutput) : self{
		$result = new self;
		$result->command = $command;
		$result->suppressOutput = $suppressOutput;
		return $result;
	}

	public function getCommand() : string{
		return $this->command;
	}

	public function getSuppressOutput() : bool{
		return $this->suppressOutput;
	}

	protected function decodePayload() : void{
		$this->command = $this->getString();
		$this->suppressOutput = (($this->get(1) !== "\x00"));
	}

	protected function encodePayload() : void{
		$this->putString($this->command);
		($this->buffer .= ($this->suppressOutput ? "\x01" : "\x00"));
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleSettingsCommand($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class AnvilDamagePacket extends DataPacket/* implements ServerboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::ANVIL_DAMAGE_PACKET;

	/** @var int */
	private $x;
	/** @var int */
	private $y;
	/** @var int */
	private $z;
	/** @var int */
	private $damageAmount;

	public static function create(int $x, int $y, int $z, int $damageAmount) : self{
		$result = new self;
		[$result->x, $result->y, $result->z] = [$x, $y, $z];
		$result->damageAmount = $damageAmount;
		return $result;
	}

	public function getDamageAmount() : int{
		return $this->damageAmount;
	}

	public function getX() : int{
		return $this->x;
	}

	public function getY() : int{
		return $this->y;
	}

	public function getZ() : int{
		return $this->z;
	}

	protected function decodePayload() : void{
		$this->damageAmount = (\ord($this->get(1)));
		$this->getBlockPosition($this->x, $this->y, $this->z);
	}

	protected function encodePayload() : void{
		($this->buffer .= \chr($this->damageAmount));
		$this->putBlockPosition($this->x, $this->y, $this->z);
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleAnvilDamage($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class CompletedUsingItemPacket extends DataPacket{
	public const NETWORK_ID = ProtocolInfo::COMPLETED_USING_ITEM_PACKET;

	public const ACTION_UNKNOWN = -1;
	public const ACTION_EQUIP_ARMOR = 0;
	public const ACTION_EAT = 1;
	public const ACTION_ATTACK = 2;
	public const ACTION_CONSUME = 3;
	public const ACTION_THROW = 4;
	public const ACTION_SHOOT = 5;
	public const ACTION_PLACE = 6;
	public const ACTION_FILL_BOTTLE = 7;
	public const ACTION_FILL_BUCKET = 8;
	public const ACTION_POUR_BUCKET = 9;
	public const ACTION_USE_TOOL = 10;
	public const ACTION_INTERACT = 11;
	public const ACTION_RETRIEVED = 12;
	public const ACTION_DYED = 13;
	public const ACTION_TRADED = 14;

	/** @var int */
	public $itemId;
	/** @var int */
	public $action;

	public function decodePayload() : void{
		$this->itemId = ((\unpack("n", $this->get(2))[1]));
		$this->action = ((\unpack("V", $this->get(4))[1] << 32 >> 32));
	}

	public function encodePayload() : void{
		($this->buffer .= (\pack("n", $this->itemId)));
		($this->buffer .= (\pack("V", $this->action)));
	}

	public function handle(NetworkSession $session) : bool{
		return $session->handleCompletedUsingItem($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\network\mcpe\NetworkSession;

class NetworkSettingsPacket extends DataPacket/* implements ClientboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::NETWORK_SETTINGS_PACKET;

	public const COMPRESS_NOTHING = 0;
	public const COMPRESS_EVERYTHING = 1;

	/** @var int */
	private $compressionThreshold;

	public static function create(int $compressionThreshold) : self{
		$result = new self;
		$result->compressionThreshold = $compressionThreshold;
		return $result;
	}

	public function getCompressionThreshold() : int{
		return $this->compressionThreshold;
	}

	protected function decodePayload() : void{
		$this->compressionThreshold = ((\unpack("v", $this->get(2))[1]));
	}

	protected function encodePayload() : void{
		($this->buffer .= (\pack("v", $this->compressionThreshold)));
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handleNetworkSettings($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\InputMode;
use pocketmine\network\mcpe\protocol\types\PlayMode;
use function assert;

class PlayerAuthInputPacket extends DataPacket/* implements ServerboundPacket*/{
	public const NETWORK_ID = ProtocolInfo::PLAYER_AUTH_INPUT_PACKET;

	/** @var Vector3 */
	private $position;
	/** @var float */
	private $pitch;
	/** @var float */
	private $yaw;
	/** @var float */
	private $headYaw;
	/** @var float */
	private $moveVecX;
	/** @var float */
	private $moveVecZ;
	/** @var int */
	private $inputFlags;
	/** @var int */
	private $inputMode;
	/** @var int */
	private $playMode;
	/** @var Vector3|null */
	private $vrGazeDirection = null;

	/**
	 * @param int          $inputMode @see InputMode
	 * @param int          $playMode @see PlayMode
	 * @param Vector3|null $vrGazeDirection only used when PlayMode::VR
	 */
	public static function create(Vector3 $position, float $pitch, float $yaw, float $headYaw, float $moveVecX, float $moveVecZ, int $inputFlags, int $inputMode, int $playMode, ?Vector3 $vrGazeDirection = null) : self{
		if($playMode === PlayMode::VR and $vrGazeDirection === null){
			//yuck, can we get a properly written packet just once? ...
			throw new \InvalidArgumentException("Gaze direction must be provided for VR play mode");
		}
		$result = new self;
		$result->position = $position->asVector3();
		$result->pitch = $pitch;
		$result->yaw = $yaw;
		$result->headYaw = $headYaw;
		$result->moveVecX = $moveVecX;
		$result->moveVecZ = $moveVecZ;
		$result->inputFlags = $inputFlags;
		$result->inputMode = $inputMode;
		$result->playMode = $playMode;
		if($vrGazeDirection !== null){
			$result->vrGazeDirection = $vrGazeDirection->asVector3();
		}
		return $result;
	}

	public function getPosition() : Vector3{
		return $this->position;
	}

	public function getPitch() : float{
		return $this->pitch;
	}

	public function getYaw() : float{
		return $this->yaw;
	}

	public function getHeadYaw() : float{
		return $this->headYaw;
	}

	public function getMoveVecX() : float{
		return $this->moveVecX;
	}

	public function getMoveVecZ() : float{
		return $this->moveVecZ;
	}

	public function getInputFlags() : int{
		return $this->inputFlags;
	}

	/**
	 * @see InputMode
	 */
	public function getInputMode() : int{
		return $this->inputMode;
	}

	/**
	 * @see PlayMode
	 */
	public function getPlayMode() : int{
		return $this->playMode;
	}

	public function getVrGazeDirection() : ?Vector3{
		return $this->vrGazeDirection;
	}

	protected function decodePayload() : void{
		$this->yaw = ((\unpack("g", $this->get(4))[1]));
		$this->pitch = ((\unpack("g", $this->get(4))[1]));
		$this->position = $this->getVector3();
		$this->moveVecX = ((\unpack("g", $this->get(4))[1]));
		$this->moveVecZ = ((\unpack("g", $this->get(4))[1]));
		$this->headYaw = ((\unpack("g", $this->get(4))[1]));
		$this->inputFlags = $this->getUnsignedVarLong();
		$this->inputMode = $this->getUnsignedVarInt();
		$this->playMode = $this->getUnsignedVarInt();
		if($this->playMode === PlayMode::VR){
			$this->vrGazeDirection = $this->getVector3();
		}
	}

	protected function encodePayload() : void{
		($this->buffer .= (\pack("g", $this->yaw)));
		($this->buffer .= (\pack("g", $this->pitch)));
		$this->putVector3($this->position);
		($this->buffer .= (\pack("g", $this->moveVecX)));
		($this->buffer .= (\pack("g", $this->moveVecZ)));
		($this->buffer .= (\pack("g", $this->headYaw)));
		$this->putUnsignedVarLong($this->inputFlags);
		$this->putUnsignedVarInt($this->inputMode);
		$this->putUnsignedVarInt($this->playMode);
		if($this->playMode === PlayMode::VR){
			assert($this->vrGazeDirection !== null);
			$this->putVector3($this->vrGazeDirection);
		}
	}

	public function handle(NetworkSession $handler) : bool{
		return $handler->handlePlayerAuthInput($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\timings;

use pocketmine\entity\Entity;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\Player;
use pocketmine\scheduler\TaskHandler;
use pocketmine\tile\Tile;
use function dechex;

abstract class Timings{
	/** @var bool */
	private static $initialized = false;

	/** @var TimingsHandler */
	public static $fullTickTimer;
	/** @var TimingsHandler */
	public static $serverTickTimer;
	/** @var TimingsHandler */
	public static $memoryManagerTimer;
	/** @var TimingsHandler */
	public static $garbageCollectorTimer;
	/** @var TimingsHandler */
	public static $titleTickTimer;
	/** @var TimingsHandler */
	public static $playerNetworkTimer;
	/** @var TimingsHandler */
	public static $playerNetworkReceiveTimer;
	/** @var TimingsHandler */
	public static $playerChunkOrderTimer;
	/** @var TimingsHandler */
	public static $playerChunkSendTimer;
	/** @var TimingsHandler */
	public static $connectionTimer;
	/** @var TimingsHandler */
	public static $schedulerTimer;
	/** @var TimingsHandler */
	public static $serverCommandTimer;
	/** @var TimingsHandler */
	public static $worldSaveTimer;
	/** @var TimingsHandler */
	public static $populationTimer;
	/** @var TimingsHandler */
	public static $generationCallbackTimer;
	/** @var TimingsHandler */
	public static $permissibleCalculationTimer;
	/** @var TimingsHandler */
	public static $permissionDefaultTimer;

	/** @var TimingsHandler */
	public static $entityMoveTimer;
	/** @var TimingsHandler */
	public static $playerCheckNearEntitiesTimer;
	/** @var TimingsHandler */
	public static $tickEntityTimer;
	/** @var TimingsHandler */
	public static $tickTileEntityTimer;

	/** @var TimingsHandler */
	public static $timerEntityBaseTick;
	/** @var TimingsHandler */
	public static $timerLivingEntityBaseTick;

	/** @var TimingsHandler */
	public static $schedulerSyncTimer;
	/** @var TimingsHandler */
	public static $schedulerAsyncTimer;

	/** @var TimingsHandler */
	public static $playerCommandTimer;

	/** @var TimingsHandler */
	public static $craftingDataCacheRebuildTimer;

	/** @var TimingsHandler[] */
	public static $entityTypeTimingMap = [];
	/** @var TimingsHandler[] */
	public static $tileEntityTypeTimingMap = [];
	/** @var TimingsHandler[] */
	public static $packetReceiveTimingMap = [];
	/** @var TimingsHandler[] */
	public static $packetSendTimingMap = [];
	/** @var TimingsHandler[] */
	public static $pluginTaskTimingMap = [];

	/**
	 * @return void
	 */
	public static function init(){
		if(self::$initialized){
			return;
		}
		self::$initialized = true;

		self::$fullTickTimer = new TimingsHandler("Full Server Tick");
		self::$serverTickTimer = new TimingsHandler("** Full Server Tick", self::$fullTickTimer);
		self::$memoryManagerTimer = new TimingsHandler("Memory Manager");
		self::$garbageCollectorTimer = new TimingsHandler("Garbage Collector", self::$memoryManagerTimer);
		self::$titleTickTimer = new TimingsHandler("Console Title Tick");
		self::$playerNetworkTimer = new TimingsHandler("Player Network Send");
		self::$playerNetworkReceiveTimer = new TimingsHandler("Player Network Receive");
		self::$playerChunkOrderTimer = new TimingsHandler("Player Order Chunks");
		self::$playerChunkSendTimer = new TimingsHandler("Player Send Chunks");
		self::$connectionTimer = new TimingsHandler("Connection Handler");
		self::$schedulerTimer = new TimingsHandler("Scheduler");
		self::$serverCommandTimer = new TimingsHandler("Server Command");
		self::$worldSaveTimer = new TimingsHandler("World Save");
		self::$populationTimer = new TimingsHandler("World Population");
		self::$generationCallbackTimer = new TimingsHandler("World Generation Callback");
		self::$permissibleCalculationTimer = new TimingsHandler("Permissible Calculation");
		self::$permissionDefaultTimer = new TimingsHandler("Default Permission Calculation");

		self::$entityMoveTimer = new TimingsHandler("** entityMove");
		self::$playerCheckNearEntitiesTimer = new TimingsHandler("** checkNearEntities");
		self::$tickEntityTimer = new TimingsHandler("** tickEntity");
		self::$tickTileEntityTimer = new TimingsHandler("** tickTileEntity");

		self::$timerEntityBaseTick = new TimingsHandler("** entityBaseTick");
		self::$timerLivingEntityBaseTick = new TimingsHandler("** livingEntityBaseTick");

		self::$schedulerSyncTimer = new TimingsHandler("** Scheduler - Sync Tasks");
		self::$schedulerAsyncTimer = new TimingsHandler("** Scheduler - Async Tasks");

		self::$playerCommandTimer = new TimingsHandler("** playerCommand");
		self::$craftingDataCacheRebuildTimer = new TimingsHandler("** craftingDataCacheRebuild");

	}

	public static function getScheduledTaskTimings(TaskHandler $task, int $period) : TimingsHandler{
		$name = "Task: " . ($task->getOwnerName() ?? "Unknown") . " Runnable: " . $task->getTaskName();

		if($period > 0){
			$name .= "(interval:" . $period . ")";
		}else{
			$name .= "(Single)";
		}

		if(!isset(self::$pluginTaskTimingMap[$name])){
			self::$pluginTaskTimingMap[$name] = new TimingsHandler($name, self::$schedulerSyncTimer);
		}

		return self::$pluginTaskTimingMap[$name];
	}

	public static function getEntityTimings(Entity $entity) : TimingsHandler{
		$entityType = (new \ReflectionClass($entity))->getShortName();
		if(!isset(self::$entityTypeTimingMap[$entityType])){
			if($entity instanceof Player){
				self::$entityTypeTimingMap[$entityType] = new TimingsHandler("** tickEntity - EntityPlayer", self::$tickEntityTimer);
			}else{
				self::$entityTypeTimingMap[$entityType] = new TimingsHandler("** tickEntity - " . $entityType, self::$tickEntityTimer);
			}
		}

		return self::$entityTypeTimingMap[$entityType];
	}

	public static function getTileEntityTimings(Tile $tile) : TimingsHandler{
		$tileType = (new \ReflectionClass($tile))->getShortName();
		if(!isset(self::$tileEntityTypeTimingMap[$tileType])){
			self::$tileEntityTypeTimingMap[$tileType] = new TimingsHandler("** tickTileEntity - " . $tileType, self::$tickTileEntityTimer);
		}

		return self::$tileEntityTypeTimingMap[$tileType];
	}

	public static function getReceiveDataPacketTimings(DataPacket $pk) : TimingsHandler{
		if(!isset(self::$packetReceiveTimingMap[$pk::NETWORK_ID])){
			$pkName = (new \ReflectionClass($pk))->getShortName();
			self::$packetReceiveTimingMap[$pk::NETWORK_ID] = new TimingsHandler("** receivePacket - " . $pkName . " [0x" . dechex($pk::NETWORK_ID) . "]", self::$playerNetworkReceiveTimer);
		}

		return self::$packetReceiveTimingMap[$pk::NETWORK_ID];
	}

	public static function getSendDataPacketTimings(DataPacket $pk) : TimingsHandler{
		if(!isset(self::$packetSendTimingMap[$pk::NETWORK_ID])){
			$pkName = (new \ReflectionClass($pk))->getShortName();
			self::$packetSendTimingMap[$pk::NETWORK_ID] = new TimingsHandler("** sendPacket - " . $pkName . " [0x" . dechex($pk::NETWORK_ID) . "]", self::$playerNetworkTimer);
		}

		return self::$packetSendTimingMap[$pk::NETWORK_ID];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\timings;

use pocketmine\entity\Living;
use pocketmine\Server;
use function count;
use function fwrite;
use function microtime;
use function round;
use function spl_object_hash;
use const PHP_EOL;

class TimingsHandler{

	/** @var TimingsHandler[] */
	private static $HANDLERS = [];
	/** @var bool */
	private static $enabled = false;
	/** @var float */
	private static $timingStart = 0;

	/**
	 * @param resource $fp
	 *
	 * @return void
	 */
	public static function printTimings($fp){
		fwrite($fp, "Minecraft" . PHP_EOL);

		foreach(self::$HANDLERS as $timings){
			$time = $timings->totalTime;
			$count = $timings->count;
			if($count === 0){
				continue;
			}

			$avg = $time / $count;

			fwrite($fp, "    " . $timings->name . " Time: " . round($time * 1000000000) . " Count: " . $count . " Avg: " . round($avg * 1000000000) . " Violations: " . $timings->violations . PHP_EOL);
		}

		fwrite($fp, "# Version " . Server::getInstance()->getVersion() . PHP_EOL);
		fwrite($fp, "# " . Server::getInstance()->getName() . " " . Server::getInstance()->getPocketMineVersion() . PHP_EOL);

		$entities = 0;
		$livingEntities = 0;
		foreach(Server::getInstance()->getLevels() as $level){
			$entities += count($level->getEntities());
			foreach($level->getEntities() as $e){
				if($e instanceof Living){
					++$livingEntities;
				}
			}
		}

		fwrite($fp, "# Entities " . $entities . PHP_EOL);
		fwrite($fp, "# LivingEntities " . $livingEntities . PHP_EOL);

		$sampleTime = microtime(true) - self::$timingStart;
		fwrite($fp, "Sample time " . round($sampleTime * 1000000000) . " (" . $sampleTime . "s)" . PHP_EOL);
	}

	public static function isEnabled() : bool{
		return self::$enabled;
	}

	public static function setEnabled(bool $enable = true) : void{
		self::$enabled = $enable;
		self::reload();
	}

	public static function getStartTime() : float{
		return self::$timingStart;
	}

	/**
	 * @return void
	 */
	public static function reload(){
		if(self::$enabled){
			foreach(self::$HANDLERS as $timings){
				$timings->reset();
			}
			self::$timingStart = microtime(true);
		}
	}

	/**
	 * @return void
	 */
	public static function tick(bool $measure = true){
		if(self::$enabled){
			if($measure){
				foreach(self::$HANDLERS as $timings){
					if($timings->curTickTotal > 0.05){
						$timings->violations += (int) round($timings->curTickTotal / 0.05);
					}
					$timings->curTickTotal = 0;
					$timings->curCount = 0;
					$timings->timingDepth = 0;
				}
			}else{
				foreach(self::$HANDLERS as $timings){
					$timings->totalTime -= $timings->curTickTotal;
					$timings->count -= $timings->curCount;

					$timings->curTickTotal = 0;
					$timings->curCount = 0;
					$timings->timingDepth = 0;
				}
			}
		}
	}

	/** @var string */
	private $name;
	/** @var TimingsHandler|null */
	private $parent = null;

	/** @var int */
	private $count = 0;
	/** @var int */
	private $curCount = 0;
	/** @var float */
	private $start = 0;
	/** @var int */
	private $timingDepth = 0;
	/** @var float */
	private $totalTime = 0;
	/** @var float */
	private $curTickTotal = 0;
	/** @var int */
	private $violations = 0;

	public function __construct(string $name, TimingsHandler $parent = null){
		$this->name = $name;
		$this->parent = $parent;

		self::$HANDLERS[spl_object_hash($this)] = $this;
	}

	/**
	 * @return void
	 */
	public function startTiming(){
		if(self::$enabled){
			$this->internalStartTiming(microtime(true));
		}
	}

	private function internalStartTiming(float $now) : void{
		if(++$this->timingDepth === 1){
			$this->start = $now;
			if($this->parent !== null){
				$this->parent->internalStartTiming($now);
			}
		}
	}

	/**
	 * @return void
	 */
	public function stopTiming(){
		if(self::$enabled){
			$this->internalStopTiming(microtime(true));
		}
	}

	private function internalStopTiming(float $now) : void{
		if($this->timingDepth === 0){
			//TODO: it would be nice to bail here, but since we'd have to track timing depth across resets
			//and enable/disable, it would have a performance impact. Therefore, considering the limited
			//usefulness of bailing here anyway, we don't currently bother.
			return;
		}
		if(--$this->timingDepth !== 0 or $this->start == 0){
			return;
		}

		$diff = $now - $this->start;
		$this->totalTime += $diff;
		$this->curTickTotal += $diff;
		++$this->curCount;
		++$this->count;
		$this->start = 0;
		if($this->parent !== null){
			$this->parent->internalStopTiming($now);
		}
	}

	/**
	 * @return void
	 */
	public function reset(){
		$this->count = 0;
		$this->curCount = 0;
		$this->violations = 0;
		$this->curTickTotal = 0;
		$this->totalTime = 0;
		$this->start = 0;
		$this->timingDepth = 0;
	}

	/**
	 * @return void
	 */
	public function remove(){
		unset(self::$HANDLERS[spl_object_hash($this)]);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command;

use pocketmine\command\defaults\BanCommand;
use pocketmine\command\defaults\BanIpCommand;
use pocketmine\command\defaults\BanListCommand;
use pocketmine\command\defaults\DefaultGamemodeCommand;
use pocketmine\command\defaults\DeopCommand;
use pocketmine\command\defaults\DifficultyCommand;
use pocketmine\command\defaults\DumpMemoryCommand;
use pocketmine\command\defaults\EffectCommand;
use pocketmine\command\defaults\EnchantCommand;
use pocketmine\command\defaults\GamemodeCommand;
use pocketmine\command\defaults\GarbageCollectorCommand;
use pocketmine\command\defaults\GiveCommand;
use pocketmine\command\defaults\HelpCommand;
use pocketmine\command\defaults\KickCommand;
use pocketmine\command\defaults\KillCommand;
use pocketmine\command\defaults\ListCommand;
use pocketmine\command\defaults\MeCommand;
use pocketmine\command\defaults\OpCommand;
use pocketmine\command\defaults\PardonCommand;
use pocketmine\command\defaults\PardonIpCommand;
use pocketmine\command\defaults\ParticleCommand;
use pocketmine\command\defaults\PluginsCommand;
use pocketmine\command\defaults\ReloadCommand;
use pocketmine\command\defaults\SaveCommand;
use pocketmine\command\defaults\SaveOffCommand;
use pocketmine\command\defaults\SaveOnCommand;
use pocketmine\command\defaults\SayCommand;
use pocketmine\command\defaults\SeedCommand;
use pocketmine\command\defaults\SetWorldSpawnCommand;
use pocketmine\command\defaults\SpawnpointCommand;
use pocketmine\command\defaults\StatusCommand;
use pocketmine\command\defaults\StopCommand;
use pocketmine\command\defaults\TeleportCommand;
use pocketmine\command\defaults\TellCommand;
use pocketmine\command\defaults\TimeCommand;
use pocketmine\command\defaults\TimingsCommand;
use pocketmine\command\defaults\TitleCommand;
use pocketmine\command\defaults\TransferServerCommand;
use pocketmine\command\defaults\VanillaCommand;
use pocketmine\command\defaults\VersionCommand;
use pocketmine\command\defaults\WhitelistCommand;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\Server;
use function array_shift;
use function count;
use function explode;
use function implode;
use function min;
use function preg_match_all;
use function strcasecmp;
use function stripslashes;
use function strpos;
use function strtolower;
use function trim;

class SimpleCommandMap implements CommandMap{

	/** @var Command[] */
	protected $knownCommands = [];

	/** @var Server */
	private $server;

	public function __construct(Server $server){
		$this->server = $server;
		$this->setDefaultCommands();
	}

	private function setDefaultCommands() : void{
		$this->registerAll("pocketmine", [
			new BanCommand("ban"),
			new BanIpCommand("ban-ip"),
			new BanListCommand("banlist"),
			new DefaultGamemodeCommand("defaultgamemode"),
			new DeopCommand("deop"),
			new DifficultyCommand("difficulty"),
			new DumpMemoryCommand("dumpmemory"),
			new EffectCommand("effect"),
			new EnchantCommand("enchant"),
			new GamemodeCommand("gamemode"),
			new GarbageCollectorCommand("gc"),
			new GiveCommand("give"),
			new HelpCommand("help"),
			new KickCommand("kick"),
			new KillCommand("kill"),
			new ListCommand("list"),
			new MeCommand("me"),
			new OpCommand("op"),
			new PardonCommand("pardon"),
			new PardonIpCommand("pardon-ip"),
			new ParticleCommand("particle"),
			new PluginsCommand("plugins"),
			new ReloadCommand("reload"),
			new SaveCommand("save-all"),
			new SaveOffCommand("save-off"),
			new SaveOnCommand("save-on"),
			new SayCommand("say"),
			new SeedCommand("seed"),
			new SetWorldSpawnCommand("setworldspawn"),
			new SpawnpointCommand("spawnpoint"),
			new StatusCommand("status"),
			new StopCommand("stop"),
			new TeleportCommand("tp"),
			new TellCommand("tell"),
			new TimeCommand("time"),
			new TimingsCommand("timings"),
			new TitleCommand("title"),
			new TransferServerCommand("transferserver"),
			new VersionCommand("version"),
			new WhitelistCommand("whitelist")
		]);
	}

	public function registerAll(string $fallbackPrefix, array $commands){
		foreach($commands as $command){
			$this->register($fallbackPrefix, $command);
		}
	}

	public function register(string $fallbackPrefix, Command $command, string $label = null) : bool{
		if($label === null){
			$label = $command->getName();
		}
		$label = trim($label);
		$fallbackPrefix = strtolower(trim($fallbackPrefix));

		$registered = $this->registerAlias($command, false, $fallbackPrefix, $label);

		$aliases = $command->getAliases();
		foreach($aliases as $index => $alias){
			if(!$this->registerAlias($command, true, $fallbackPrefix, $alias)){
				unset($aliases[$index]);
			}
		}
		$command->setAliases($aliases);

		if(!$registered){
			$command->setLabel($fallbackPrefix . ":" . $label);
		}

		$command->register($this);

		return $registered;
	}

	public function unregister(Command $command) : bool{
		foreach($this->knownCommands as $lbl => $cmd){
			if($cmd === $command){
				unset($this->knownCommands[$lbl]);
			}
		}

		$command->unregister($this);

		return true;
	}

	private function registerAlias(Command $command, bool $isAlias, string $fallbackPrefix, string $label) : bool{
		$this->knownCommands[$fallbackPrefix . ":" . $label] = $command;
		if(($command instanceof VanillaCommand or $isAlias) and isset($this->knownCommands[$label])){
			return false;
		}

		if(isset($this->knownCommands[$label]) and $this->knownCommands[$label]->getLabel() === $label){
			return false;
		}

		if(!$isAlias){
			$command->setLabel($label);
		}

		$this->knownCommands[$label] = $command;

		return true;
	}

	/**
	 * Returns a command to match the specified command line, or null if no matching command was found.
	 * This method is intended to provide capability for handling commands with spaces in their name.
	 * The referenced parameters will be modified accordingly depending on the resulting matched command.
	 *
	 * @param string   $commandName reference parameter
	 * @param string[] $args reference parameter
	 *
	 * @return Command|null
	 */
	public function matchCommand(string &$commandName, array &$args){
		$count = min(count($args), 255);

		for($i = 0; $i < $count; ++$i){
			$commandName .= array_shift($args);
			if(($command = $this->getCommand($commandName)) instanceof Command){
				return $command;
			}

			$commandName .= " ";
		}

		return null;
	}

	public function dispatch(CommandSender $sender, string $commandLine) : bool{
		$args = [];
		preg_match_all('/"((?:\\\\.|[^\\\\"])*)"|(\S+)/u', $commandLine, $matches);
		foreach($matches[0] as $k => $_){
			for($i = 1; $i <= 2; ++$i){
				if($matches[$i][$k] !== ""){
					$args[$k] = stripslashes($matches[$i][$k]);
					break;
				}
			}
		}
		$sentCommandLabel = "";
		$target = $this->matchCommand($sentCommandLabel, $args);

		if($target === null){
			return false;
		}

		$target->timings->startTiming();

		try{
			$target->execute($sender, $sentCommandLabel, $args);
		}catch(InvalidCommandSyntaxException $e){
			$sender->sendMessage($this->server->getLanguage()->translateString("commands.generic.usage", [$target->getUsage()]));
		}finally{
			$target->timings->stopTiming();
		}

		return true;
	}

	public function clearCommands(){
		foreach($this->knownCommands as $command){
			$command->unregister($this);
		}
		$this->knownCommands = [];
		$this->setDefaultCommands();
	}

	public function getCommand(string $name){
		return $this->knownCommands[$name] ?? null;
	}

	/**
	 * @return Command[]
	 */
	public function getCommands() : array{
		return $this->knownCommands;
	}

	/**
	 * @return void
	 */
	public function registerServerAliases(){
		$values = $this->server->getCommandAliases();

		foreach($values as $alias => $commandStrings){
			if(strpos($alias, ":") !== false){
				$this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.command.alias.illegal", [$alias]));
				continue;
			}

			$targets = [];
			$bad = [];
			$recursive = [];

			foreach($commandStrings as $commandString){
				$args = explode(" ", $commandString);
				$commandName = "";
				$command = $this->matchCommand($commandName, $args);

				if($command === null){
					$bad[] = $commandString;
				}elseif(strcasecmp($commandName, $alias) === 0){
					$recursive[] = $commandString;
				}else{
					$targets[] = $commandString;
				}
			}

			if(count($recursive) > 0){
				$this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.command.alias.recursive", [$alias, implode(", ", $recursive)]));
				continue;
			}

			if(count($bad) > 0){
				$this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.command.alias.notFound", [$alias, implode(", ", $bad)]));
				continue;
			}

			//These registered commands have absolute priority
			if(count($targets) > 0){
				$this->knownCommands[strtolower($alias)] = new FormattedCommandAlias(strtolower($alias), $targets);
			}else{
				unset($this->knownCommands[strtolower($alias)]);
			}

		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command;

interface CommandMap{

	/**
	 * @param Command[] $commands
	 *
	 * @return void
	 */
	public function registerAll(string $fallbackPrefix, array $commands);

	public function register(string $fallbackPrefix, Command $command, string $label = null) : bool;

	public function dispatch(CommandSender $sender, string $cmdLine) : bool;

	/**
	 * @return void
	 */
	public function clearCommands();

	/**
	 * @return Command|null
	 */
	public function getCommand(string $name);

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use function array_shift;
use function count;
use function implode;

class BanCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.ban.player.description",
			"%commands.ban.usage"
		);
		$this->setPermission("pocketmine.command.ban.player");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			throw new InvalidCommandSyntaxException();
		}

		$name = array_shift($args);
		$reason = implode(" ", $args);

		$sender->getServer()->getNameBans()->addBan($name, $reason, null, $sender->getName());

		if(($player = $sender->getServer()->getPlayerExact($name)) instanceof Player){
			$player->kick($reason !== "" ? "Banned by admin. Reason: " . $reason : "Banned by admin.");
		}

		Command::broadcastCommandMessage($sender, new TranslationContainer("%commands.ban.success", [$player !== null ? $player->getName() : $name]));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\utils\TextFormat;
use function is_numeric;
use function substr;

abstract class VanillaCommand extends Command{
	public const MAX_COORD = 30000000;
	public const MIN_COORD = -30000000;

	/**
	 * @param mixed         $value
	 */
	protected function getInteger(CommandSender $sender, $value, int $min = self::MIN_COORD, int $max = self::MAX_COORD) : int{
		$i = (int) $value;

		if($i < $min){
			$i = $min;
		}elseif($i > $max){
			$i = $max;
		}

		return $i;
	}

	protected function getRelativeDouble(float $original, CommandSender $sender, string $input, float $min = self::MIN_COORD, float $max = self::MAX_COORD) : float{
		if($input[0] === "~"){
			$value = $this->getDouble($sender, substr($input, 1));

			return $original + $value;
		}

		return $this->getDouble($sender, $input, $min, $max);
	}

	/**
	 * @param mixed         $value
	 */
	protected function getDouble(CommandSender $sender, $value, float $min = self::MIN_COORD, float $max = self::MAX_COORD) : float{
		$i = (double) $value;

		if($i < $min){
			$i = $min;
		}elseif($i > $max){
			$i = $max;
		}

		return $i;
	}

	protected function getBoundedInt(CommandSender $sender, string $input, int $min, int $max) : ?int{
		if(!is_numeric($input)){
			throw new InvalidCommandSyntaxException();
		}

		$v = (int) $input;
		if($v > $max){
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.num.tooBig", [$input, (string) $max]));
			return null;
		}
		if($v < $min){
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.num.tooSmall", [$input, (string) $min]));
			return null;
		}

		return $v;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Command handling related classes
 */
namespace pocketmine\command;

use pocketmine\command\utils\CommandException;
use pocketmine\lang\TextContainer;
use pocketmine\lang\TranslationContainer;
use pocketmine\permission\PermissionManager;
use pocketmine\Server;
use pocketmine\timings\TimingsHandler;
use pocketmine\utils\TextFormat;
use function explode;
use function str_replace;

abstract class Command{

	/** @var string */
	private $name;

	/** @var string */
	private $nextLabel;

	/** @var string */
	private $label;

	/** @var string[] */
	private $aliases = [];

	/** @var string[] */
	private $activeAliases = [];

	/** @var CommandMap|null */
	private $commandMap = null;

	/** @var string */
	protected $description = "";

	/** @var string */
	protected $usageMessage;

	/** @var string|null */
	private $permission = null;

	/** @var string|null */
	private $permissionMessage = null;

	/** @var TimingsHandler|null */
	public $timings = null;

	/**
	 * @param string[] $aliases
	 */
	public function __construct(string $name, string $description = "", string $usageMessage = null, array $aliases = []){
		$this->name = $name;
		$this->setLabel($name);
		$this->setDescription($description);
		$this->usageMessage = $usageMessage ?? ("/" . $name);
		$this->setAliases($aliases);
	}

	/**
	 * @param string[] $args
	 *
	 * @return mixed
	 * @throws CommandException
	 */
	abstract public function execute(CommandSender $sender, string $commandLabel, array $args);

	public function getName() : string{
		return $this->name;
	}

	/**
	 * @return string|null
	 */
	public function getPermission(){
		return $this->permission;
	}

	/**
	 * @return void
	 */
	public function setPermission(string $permission = null){
		$this->permission = $permission;
	}

	public function testPermission(CommandSender $target) : bool{
		if($this->testPermissionSilent($target)){
			return true;
		}

		if($this->permissionMessage === null){
			$target->sendMessage($target->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));
		}elseif($this->permissionMessage !== ""){
			$target->sendMessage(str_replace("<permission>", $this->permission, $this->permissionMessage));
		}

		return false;
	}

	public function testPermissionSilent(CommandSender $target) : bool{
		if($this->permission === null or $this->permission === ""){
			return true;
		}

		foreach(explode(";", $this->permission) as $permission){
			if($target->hasPermission($permission)){
				return true;
			}
		}

		return false;
	}

	public function getLabel() : string{
		return $this->label;
	}

	public function setLabel(string $name) : bool{
		$this->nextLabel = $name;
		if(!$this->isRegistered()){
			if($this->timings instanceof TimingsHandler){
				$this->timings->remove();
			}
			$this->timings = new TimingsHandler("** Command: " . $name);
			$this->label = $name;

			return true;
		}

		return false;
	}

	/**
	 * Registers the command into a Command map
	 */
	public function register(CommandMap $commandMap) : bool{
		if($this->allowChangesFrom($commandMap)){
			$this->commandMap = $commandMap;

			return true;
		}

		return false;
	}

	public function unregister(CommandMap $commandMap) : bool{
		if($this->allowChangesFrom($commandMap)){
			$this->commandMap = null;
			$this->activeAliases = $this->aliases;
			$this->label = $this->nextLabel;

			return true;
		}

		return false;
	}

	private function allowChangesFrom(CommandMap $commandMap) : bool{
		return $this->commandMap === null or $this->commandMap === $commandMap;
	}

	public function isRegistered() : bool{
		return $this->commandMap !== null;
	}

	/**
	 * @return string[]
	 */
	public function getAliases() : array{
		return $this->activeAliases;
	}

	public function getPermissionMessage() : ?string{
		return $this->permissionMessage;
	}

	public function getDescription() : string{
		return $this->description;
	}

	public function getUsage() : string{
		return $this->usageMessage;
	}

	/**
	 * @param string[] $aliases
	 *
	 * @return void
	 */
	public function setAliases(array $aliases){
		$this->aliases = $aliases;
		if(!$this->isRegistered()){
			$this->activeAliases = $aliases;
		}
	}

	/**
	 * @return void
	 */
	public function setDescription(string $description){
		$this->description = $description;
	}

	/**
	 * @return void
	 */
	public function setPermissionMessage(string $permissionMessage){
		$this->permissionMessage = $permissionMessage;
	}

	/**
	 * @return void
	 */
	public function setUsage(string $usage){
		$this->usageMessage = $usage;
	}

	/**
	 * @param TextContainer|string $message
	 *
	 * @return void
	 */
	public static function broadcastCommandMessage(CommandSender $source, $message, bool $sendToSource = true){
		if($message instanceof TextContainer){
			$m = clone $message;
			$result = "[" . $source->getName() . ": " . ($source->getServer()->getLanguage()->get($m->getText()) !== $m->getText() ? "%" : "") . $m->getText() . "]";

			$users = PermissionManager::getInstance()->getPermissionSubscriptions(Server::BROADCAST_CHANNEL_ADMINISTRATIVE);
			$colored = TextFormat::GRAY . TextFormat::ITALIC . $result;

			$m->setText($result);
			$result = clone $m;
			$m->setText($colored);
			$colored = clone $m;
		}else{
			$users = PermissionManager::getInstance()->getPermissionSubscriptions(Server::BROADCAST_CHANNEL_ADMINISTRATIVE);
			$result = new TranslationContainer("chat.type.admin", [$source->getName(), $message]);
			$colored = new TranslationContainer(TextFormat::GRAY . TextFormat::ITALIC . "%chat.type.admin", [$source->getName(), $message]);
		}

		if($sendToSource and !($source instanceof ConsoleCommandSender)){
			$source->sendMessage($message);
		}

		foreach($users as $user){
			if($user instanceof CommandSender){
				if($user instanceof ConsoleCommandSender){
					$user->sendMessage($result);
				}elseif($user !== $source){
					$user->sendMessage($colored);
				}
			}
		}
	}

	public function __toString() : string{
		return $this->name;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use function array_shift;
use function count;
use function implode;
use function preg_match;

class BanIpCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.ban.ip.description",
			"%commands.banip.usage"
		);
		$this->setPermission("pocketmine.command.ban.ip");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			throw new InvalidCommandSyntaxException();
		}

		$value = array_shift($args);
		$reason = implode(" ", $args);

		if(preg_match("/^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$/", $value)){
			$this->processIPBan($value, $sender, $reason);

			Command::broadcastCommandMessage($sender, new TranslationContainer("commands.banip.success", [$value]));
		}else{
			if(($player = $sender->getServer()->getPlayer($value)) instanceof Player){
				$this->processIPBan($player->getAddress(), $sender, $reason);

				Command::broadcastCommandMessage($sender, new TranslationContainer("commands.banip.success.players", [$player->getAddress(), $player->getName()]));
			}else{
				$sender->sendMessage(new TranslationContainer("commands.banip.invalid"));

				return false;
			}
		}

		return true;
	}

	private function processIPBan(string $ip, CommandSender $sender, string $reason) : void{
		$sender->getServer()->getIPBans()->addBan($ip, $reason, null, $sender->getName());

		foreach($sender->getServer()->getOnlinePlayers() as $player){
			if($player->getAddress() === $ip){
				$player->kick($reason !== "" ? $reason : "IP banned.");
			}
		}

		$sender->getServer()->getNetwork()->blockAddress($ip, -1);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\permission\BanEntry;
use function array_map;
use function count;
use function implode;
use function strtolower;

class BanListCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.banlist.description",
			"%commands.banlist.usage"
		);
		$this->setPermission("pocketmine.command.ban.list");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(isset($args[0])){
			$args[0] = strtolower($args[0]);
			if($args[0] === "ips"){
				$list = $sender->getServer()->getIPBans();
			}elseif($args[0] === "players"){
				$list = $sender->getServer()->getNameBans();
			}else{
				throw new InvalidCommandSyntaxException();
			}
		}else{
			$list = $sender->getServer()->getNameBans();
			$args[0] = "players";
		}

		$list = $list->getEntries();
		$message = implode(", ", array_map(function(BanEntry $entry) : string{
			return $entry->getName();
		}, $list));

		if($args[0] === "ips"){
			$sender->sendMessage(new TranslationContainer("commands.banlist.ips", [count($list)]));
		}else{
			$sender->sendMessage(new TranslationContainer("commands.banlist.players", [count($list)]));
		}

		$sender->sendMessage($message);

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Server;
use function count;

class DefaultGamemodeCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.defaultgamemode.description",
			"%commands.defaultgamemode.usage"
		);
		$this->setPermission("pocketmine.command.defaultgamemode");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			throw new InvalidCommandSyntaxException();
		}

		$gameMode = Server::getGamemodeFromString($args[0]);

		if($gameMode !== -1){
			$sender->getServer()->setConfigInt("gamemode", $gameMode);
			$sender->sendMessage(new TranslationContainer("commands.defaultgamemode.success", [Server::getGamemodeString($gameMode)]));
		}else{
			$sender->sendMessage("Unknown game mode");
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function array_shift;
use function count;

class DeopCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.deop.description",
			"%commands.deop.usage"
		);
		$this->setPermission("pocketmine.command.op.take");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			throw new InvalidCommandSyntaxException();
		}

		$name = array_shift($args);
		if(!Player::isValidUserName($name)){
			throw new InvalidCommandSyntaxException();
		}

		$player = $sender->getServer()->getOfflinePlayer($name);
		$player->setOp(false);
		if($player instanceof Player){
			$player->sendMessage(TextFormat::GRAY . "You are no longer op!");
		}
		Command::broadcastCommandMessage($sender, new TranslationContainer("commands.deop.success", [$player->getName()]));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\level\Level;
use function count;

class DifficultyCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.difficulty.description",
			"%commands.difficulty.usage"
		);
		$this->setPermission("pocketmine.command.difficulty");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) !== 1){
			throw new InvalidCommandSyntaxException();
		}

		$difficulty = Level::getDifficultyFromString($args[0]);

		if($sender->getServer()->isHardcore()){
			$difficulty = Level::DIFFICULTY_HARD;
		}

		if($difficulty !== -1){
			$sender->getServer()->setConfigInt("difficulty", $difficulty);

			//TODO: add per-world support
			foreach($sender->getServer()->getLevels() as $level){
				$level->setDifficulty($difficulty);
			}

			Command::broadcastCommandMessage($sender, new TranslationContainer("commands.difficulty.success", [$difficulty]));
		}else{
			throw new InvalidCommandSyntaxException();
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use function date;

class DumpMemoryCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"Dumps the memory",
			"/$name [path]"
		);
		$this->setPermission("pocketmine.command.dumpmemory");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		$sender->getServer()->getMemoryManager()->dumpServerMemory($args[0] ?? ($sender->getServer()->getDataPath() . "/memory_dumps/" . date("D_M_j-H.i.s-T_Y")), 48, 80);
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;
use pocketmine\lang\TranslationContainer;
use pocketmine\utils\TextFormat;
use function count;
use function strtolower;
use const INT32_MAX;

class EffectCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.effect.description",
			"%commands.effect.usage"
		);
		$this->setPermission("pocketmine.command.effect");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) < 2){
			throw new InvalidCommandSyntaxException();
		}

		$player = $sender->getServer()->getPlayer($args[0]);

		if($player === null){
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound"));
			return true;
		}

		if(strtolower($args[1]) === "clear"){
			foreach($player->getEffects() as $effect){
				$player->removeEffect($effect->getId());
			}

			$sender->sendMessage(new TranslationContainer("commands.effect.success.removed.all", [$player->getDisplayName()]));
			return true;
		}

		$effect = Effect::getEffectByName($args[1]);

		if($effect === null){
			$effect = Effect::getEffect((int) $args[1]);
		}

		if($effect === null){
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.effect.notFound", [$args[1]]));
			return true;
		}

		$amplification = 0;

		if(count($args) >= 3){
			if(($d = $this->getBoundedInt($sender, $args[2], 0, (int) (INT32_MAX / 20))) === null){
				return false;
			}
			$duration = $d * 20; //ticks
		}else{
			$duration = null;
		}

		if(count($args) >= 4){
			$amplification = $this->getBoundedInt($sender, $args[3], 0, 255);
			if($amplification === null){
				return false;
			}
		}

		$visible = true;
		if(count($args) >= 5){
			$v = strtolower($args[4]);
			if($v === "on" or $v === "true" or $v === "t" or $v === "1"){
				$visible = false;
			}
		}

		if($duration === 0){
			if(!$player->hasEffect($effect->getId())){
				if(count($player->getEffects()) === 0){
					$sender->sendMessage(new TranslationContainer("commands.effect.failure.notActive.all", [$player->getDisplayName()]));
				}else{
					$sender->sendMessage(new TranslationContainer("commands.effect.failure.notActive", [$effect->getName(), $player->getDisplayName()]));
				}
				return true;
			}

			$player->removeEffect($effect->getId());
			$sender->sendMessage(new TranslationContainer("commands.effect.success.removed", [$effect->getName(), $player->getDisplayName()]));
		}else{
			$instance = new EffectInstance($effect, $duration, $amplification, $visible);
			$player->addEffect($instance);
			self::broadcastCommandMessage($sender, new TranslationContainer("%commands.effect.success", [$effect->getName(), $instance->getAmplifier(), $player->getDisplayName(), $instance->getDuration() / 20, $effect->getId()]));
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\enchantment\EnchantmentInstance;
use pocketmine\lang\TranslationContainer;
use pocketmine\utils\TextFormat;
use function count;
use function is_numeric;

class EnchantCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.enchant.description",
			"%commands.enchant.usage"
		);
		$this->setPermission("pocketmine.command.enchant");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) < 2){
			throw new InvalidCommandSyntaxException();
		}

		$player = $sender->getServer()->getPlayer($args[0]);

		if($player === null){
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound"));
			return true;
		}

		$item = $player->getInventory()->getItemInHand();

		if($item->isNull()){
			$sender->sendMessage(new TranslationContainer("commands.enchant.noItem"));
			return true;
		}

		if(is_numeric($args[1])){
			$enchantment = Enchantment::getEnchantment((int) $args[1]);
		}else{
			$enchantment = Enchantment::getEnchantmentByName($args[1]);
		}

		if(!($enchantment instanceof Enchantment)){
			$sender->sendMessage(new TranslationContainer("commands.enchant.notFound", [$args[1]]));
			return true;
		}

		$level = 1;
		if(isset($args[2])){
			$level = $this->getBoundedInt($sender, $args[2], 1, $enchantment->getMaxLevel());
			if($level === null){
				return false;
			}
		}

		$item->addEnchantment(new EnchantmentInstance($enchantment, $level));
		$player->getInventory()->setItemInHand($item);

		self::broadcastCommandMessage($sender, new TranslationContainer("%commands.enchant.success", [$player->getName()]));
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\utils\TextFormat;
use function count;

class GamemodeCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.gamemode.description",
			"%commands.gamemode.usage"
		);
		$this->setPermission("pocketmine.command.gamemode");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			throw new InvalidCommandSyntaxException();
		}

		$gameMode = Server::getGamemodeFromString($args[0]);

		if($gameMode === -1){
			$sender->sendMessage("Unknown game mode");

			return true;
		}

		if(isset($args[1])){
			$target = $sender->getServer()->getPlayer($args[1]);
			if($target === null){
				$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound"));

				return true;
			}
		}elseif($sender instanceof Player){
			$target = $sender;
		}else{
			throw new InvalidCommandSyntaxException();
		}

		$target->setGamemode($gameMode);
		if($gameMode !== $target->getGamemode()){
			$sender->sendMessage("Game mode change for " . $target->getName() . " failed!");
		}else{
			if($target === $sender){
				Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.self", [Server::getGamemodeString($gameMode)]));
			}else{
				$target->sendMessage(new TranslationContainer("gameMode.changed", [Server::getGamemodeString($gameMode)]));
				Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.other", [Server::getGamemodeString($gameMode), $target->getName()]));
			}
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\utils\TextFormat;
use function count;
use function memory_get_usage;
use function number_format;
use function round;

class GarbageCollectorCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.gc.description",
			"%pocketmine.command.gc.usage"
		);
		$this->setPermission("pocketmine.command.gc");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		$chunksCollected = 0;
		$entitiesCollected = 0;
		$tilesCollected = 0;

		$memory = memory_get_usage();

		foreach($sender->getServer()->getLevels() as $level){
			$diff = [count($level->getChunks()), count($level->getEntities()), count($level->getTiles())];
			$level->doChunkGarbageCollection();
			$level->unloadChunks(true);
			$chunksCollected += $diff[0] - count($level->getChunks());
			$entitiesCollected += $diff[1] - count($level->getEntities());
			$tilesCollected += $diff[2] - count($level->getTiles());
			$level->clearCache(true);
		}

		$cyclesCollected = $sender->getServer()->getMemoryManager()->triggerGarbageCollector();

		$sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Garbage collection result" . TextFormat::GREEN . " ----");
		$sender->sendMessage(TextFormat::GOLD . "Chunks: " . TextFormat::RED . number_format($chunksCollected));
		$sender->sendMessage(TextFormat::GOLD . "Entities: " . TextFormat::RED . number_format($entitiesCollected));
		$sender->sendMessage(TextFormat::GOLD . "Tiles: " . TextFormat::RED . number_format($tilesCollected));

		$sender->sendMessage(TextFormat::GOLD . "Cycles: " . TextFormat::RED . number_format($cyclesCollected));
		$sender->sendMessage(TextFormat::GOLD . "Memory freed: " . TextFormat::RED . number_format(round((($memory - memory_get_usage()) / 1024) / 1024, 2), 2) . " MB");
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\item\ItemFactory;
use pocketmine\lang\TranslationContainer;
use pocketmine\nbt\JsonNbtParser;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\utils\TextFormat;
use function array_slice;
use function count;
use function implode;

class GiveCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.give.description",
			"%pocketmine.command.give.usage"
		);
		$this->setPermission("pocketmine.command.give");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) < 2){
			throw new InvalidCommandSyntaxException();
		}

		$player = $sender->getServer()->getPlayer($args[0]);
		if($player === null){
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound"));
			return true;
		}

		try{
			$item = ItemFactory::fromString($args[1]);
		}catch(\InvalidArgumentException $e){
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.give.item.notFound", [$args[1]]));
			return true;
		}

		if(!isset($args[2])){
			$item->setCount($item->getMaxStackSize());
		}else{
			$item->setCount((int) $args[2]);
		}

		if(isset($args[3])){
			$tags = $exception = null;
			$data = implode(" ", array_slice($args, 3));
			try{
				$tags = JsonNbtParser::parseJson($data);
			}catch(\Exception $ex){
				$exception = $ex;
			}

			if(!($tags instanceof CompoundTag) or $exception !== null){
				$sender->sendMessage(new TranslationContainer("commands.give.tagError", [$exception !== null ? $exception->getMessage() : "Invalid tag conversion"]));
				return true;
			}

			$item->setNamedTag($tags);
		}

		//TODO: overflow
		$player->getInventory()->addItem(clone $item);

		Command::broadcastCommandMessage($sender, new TranslationContainer("%commands.give.success", [
			$item->getName() . " (" . $item->getId() . ":" . $item->getDamage() . ")",
			(string) $item->getCount(),
			$player->getName()
		]));
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;
use pocketmine\utils\TextFormat;
use function array_chunk;
use function array_pop;
use function count;
use function explode;
use function implode;
use function is_numeric;
use function ksort;
use function min;
use function strtolower;
use const SORT_FLAG_CASE;
use const SORT_NATURAL;

class HelpCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.help.description",
			"%commands.help.usage",
			["?"]
		);
		$this->setPermission("pocketmine.command.help");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			$commandName = "";
			$pageNumber = 1;
		}elseif(is_numeric($args[count($args) - 1])){
			$pageNumber = (int) array_pop($args);
			if($pageNumber <= 0){
				$pageNumber = 1;
			}
			$commandName = implode(" ", $args);
		}else{
			$commandName = implode(" ", $args);
			$pageNumber = 1;
		}

		$pageHeight = $sender->getScreenLineHeight();

		if($commandName === ""){
			/** @var Command[][] $commands */
			$commands = [];
			foreach($sender->getServer()->getCommandMap()->getCommands() as $command){
				if($command->testPermissionSilent($sender)){
					$commands[$command->getName()] = $command;
				}
			}
			ksort($commands, SORT_NATURAL | SORT_FLAG_CASE);
			$commands = array_chunk($commands, $pageHeight);
			$pageNumber = min(count($commands), $pageNumber);
			if($pageNumber < 1){
				$pageNumber = 1;
			}
			$sender->sendMessage(new TranslationContainer("commands.help.header", [$pageNumber, count($commands)]));
			if(isset($commands[$pageNumber - 1])){
				foreach($commands[$pageNumber - 1] as $command){
					$sender->sendMessage(TextFormat::DARK_GREEN . "/" . $command->getName() . ": " . TextFormat::WHITE . $command->getDescription());
				}
			}

			return true;
		}else{
			if(($cmd = $sender->getServer()->getCommandMap()->getCommand(strtolower($commandName))) instanceof Command){
				if($cmd->testPermissionSilent($sender)){
					$message = TextFormat::YELLOW . "--------- " . TextFormat::WHITE . " Help: /" . $cmd->getName() . TextFormat::YELLOW . " ---------\n";
					$message .= TextFormat::GOLD . "Description: " . TextFormat::WHITE . $cmd->getDescription() . "\n";
					$message .= TextFormat::GOLD . "Usage: " . TextFormat::WHITE . implode("\n" . TextFormat::WHITE, explode("\n", $cmd->getUsage())) . "\n";
					$sender->sendMessage($message);

					return true;
				}
			}
			$sender->sendMessage(TextFormat::RED . "No help for " . strtolower($commandName));

			return true;
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function array_shift;
use function count;
use function implode;
use function trim;

class KickCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.kick.description",
			"%commands.kick.usage"
		);
		$this->setPermission("pocketmine.command.kick");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			throw new InvalidCommandSyntaxException();
		}

		$name = array_shift($args);
		$reason = trim(implode(" ", $args));

		if(($player = $sender->getServer()->getPlayer($name)) instanceof Player){
			$player->kick($reason);
			if($reason !== ""){
				Command::broadcastCommandMessage($sender, new TranslationContainer("commands.kick.success.reason", [$player->getName(), $reason]));
			}else{
				Command::broadcastCommandMessage($sender, new TranslationContainer("commands.kick.success", [$player->getName()]));
			}
		}else{
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound"));
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function count;

class KillCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.kill.description",
			"%pocketmine.command.kill.usage",
			["suicide"]
		);
		$this->setPermission("pocketmine.command.kill.self;pocketmine.command.kill.other");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) >= 2){
			throw new InvalidCommandSyntaxException();
		}

		if(count($args) === 1){
			if(!$sender->hasPermission("pocketmine.command.kill.other")){
				$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));

				return true;
			}

			$player = $sender->getServer()->getPlayer($args[0]);

			if($player instanceof Player){
				$player->attack(new EntityDamageEvent($player, EntityDamageEvent::CAUSE_SUICIDE, 1000));
				Command::broadcastCommandMessage($sender, new TranslationContainer("commands.kill.successful", [$player->getName()]));
			}else{
				$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound"));
			}

			return true;
		}

		if($sender instanceof Player){
			if(!$sender->hasPermission("pocketmine.command.kill.self")){
				$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));

				return true;
			}

			$sender->attack(new EntityDamageEvent($sender, EntityDamageEvent::CAUSE_SUICIDE, 1000));
			$sender->sendMessage(new TranslationContainer("commands.kill.successful", [$sender->getName()]));
		}else{
			throw new InvalidCommandSyntaxException();
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use function array_filter;
use function array_map;
use function count;
use function implode;

class ListCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.list.description",
			"%command.players.usage"
		);
		$this->setPermission("pocketmine.command.list");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		$playerNames = array_map(function(Player $player) : string{
			return $player->getName();
		}, array_filter($sender->getServer()->getOnlinePlayers(), function(Player $player) use ($sender) : bool{
			return $player->isOnline() and (!($sender instanceof Player) or $sender->canSee($player));
		}));

		$sender->sendMessage(new TranslationContainer("commands.players.list", [count($playerNames), $sender->getServer()->getMaxPlayers()]));
		$sender->sendMessage(implode(", ", $playerNames));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function count;
use function implode;

class MeCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.me.description",
			"%commands.me.usage"
		);
		$this->setPermission("pocketmine.command.me");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			throw new InvalidCommandSyntaxException();
		}

		$sender->getServer()->broadcastMessage(new TranslationContainer("chat.type.emote", [$sender instanceof Player ? $sender->getDisplayName() : $sender->getName(), TextFormat::WHITE . implode(" ", $args)]));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function array_shift;
use function count;

class OpCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.op.description",
			"%commands.op.usage"
		);
		$this->setPermission("pocketmine.command.op.give");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			throw new InvalidCommandSyntaxException();
		}

		$name = array_shift($args);
		if(!Player::isValidUserName($name)){
			throw new InvalidCommandSyntaxException();
		}

		$player = $sender->getServer()->getOfflinePlayer($name);
		Command::broadcastCommandMessage($sender, new TranslationContainer("commands.op.success", [$player->getName()]));
		if($player instanceof Player){
			$player->sendMessage(TextFormat::GRAY . "You are now op!");
		}
		$player->setOp(true);
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use function count;

class PardonCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.unban.player.description",
			"%commands.unban.usage",
			["unban"]
		);
		$this->setPermission("pocketmine.command.unban.player");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) !== 1){
			throw new InvalidCommandSyntaxException();
		}

		$sender->getServer()->getNameBans()->remove($args[0]);

		Command::broadcastCommandMessage($sender, new TranslationContainer("commands.unban.success", [$args[0]]));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use function count;
use function preg_match;

class PardonIpCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.unban.ip.description",
			"%commands.unbanip.usage",
			["unban-ip"]
		);
		$this->setPermission("pocketmine.command.unban.ip");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) !== 1){
			throw new InvalidCommandSyntaxException();
		}

		if(preg_match("/^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$/", $args[0])){
			$sender->getServer()->getIPBans()->remove($args[0]);
			$sender->getServer()->getNetwork()->unblockAddress($args[0]);
			Command::broadcastCommandMessage($sender, new TranslationContainer("commands.unbanip.success", [$args[0]]));
		}else{
			$sender->sendMessage(new TranslationContainer("commands.unbanip.invalid"));
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\block\BlockFactory;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\lang\TranslationContainer;
use pocketmine\level\Level;
use pocketmine\level\particle\AngryVillagerParticle;
use pocketmine\level\particle\BlockForceFieldParticle;
use pocketmine\level\particle\BubbleParticle;
use pocketmine\level\particle\CriticalParticle;
use pocketmine\level\particle\DustParticle;
use pocketmine\level\particle\EnchantmentTableParticle;
use pocketmine\level\particle\EnchantParticle;
use pocketmine\level\particle\ExplodeParticle;
use pocketmine\level\particle\FlameParticle;
use pocketmine\level\particle\HappyVillagerParticle;
use pocketmine\level\particle\HeartParticle;
use pocketmine\level\particle\HugeExplodeParticle;
use pocketmine\level\particle\HugeExplodeSeedParticle;
use pocketmine\level\particle\InkParticle;
use pocketmine\level\particle\InstantEnchantParticle;
use pocketmine\level\particle\ItemBreakParticle;
use pocketmine\level\particle\LavaDripParticle;
use pocketmine\level\particle\LavaParticle;
use pocketmine\level\particle\Particle;
use pocketmine\level\particle\PortalParticle;
use pocketmine\level\particle\RainSplashParticle;
use pocketmine\level\particle\RedstoneParticle;
use pocketmine\level\particle\SmokeParticle;
use pocketmine\level\particle\SplashParticle;
use pocketmine\level\particle\SporeParticle;
use pocketmine\level\particle\TerrainParticle;
use pocketmine\level\particle\WaterDripParticle;
use pocketmine\level\particle\WaterParticle;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\Random;
use pocketmine\utils\TextFormat;
use function count;
use function explode;
use function max;
use function microtime;
use function mt_rand;
use function strpos;
use function strtolower;

class ParticleCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.particle.description",
			"%pocketmine.command.particle.usage"
		);
		$this->setPermission("pocketmine.command.particle");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) < 7){
			throw new InvalidCommandSyntaxException();
		}

		if($sender instanceof Player){
			$level = $sender->getLevel();
			$pos = new Vector3(
				$this->getRelativeDouble($sender->getX(), $sender, $args[1]),
				$this->getRelativeDouble($sender->getY(), $sender, $args[2], 0, Level::Y_MAX),
				$this->getRelativeDouble($sender->getZ(), $sender, $args[3])
			);
		}else{
			$level = $sender->getServer()->getDefaultLevel();
			$pos = new Vector3((float) $args[1], (float) $args[2], (float) $args[3]);
		}

		$name = strtolower($args[0]);

		$xd = (float) $args[4];
		$yd = (float) $args[5];
		$zd = (float) $args[6];

		$count = isset($args[7]) ? max(1, (int) $args[7]) : 1;

		$data = isset($args[8]) ? (int) $args[8] : null;

		$particle = $this->getParticle($name, $pos, $xd, $yd, $zd, $data);

		if($particle === null){
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.particle.notFound", [$name]));
			return true;
		}

		$sender->sendMessage(new TranslationContainer("commands.particle.success", [$name, $count]));

		$random = new Random((int) (microtime(true) * 1000) + mt_rand());

		for($i = 0; $i < $count; ++$i){
			$particle->setComponents(
				$pos->x + $random->nextSignedFloat() * $xd,
				$pos->y + $random->nextSignedFloat() * $yd,
				$pos->z + $random->nextSignedFloat() * $zd
			);
			$level->addParticle($particle);
		}

		return true;
	}

	/**
	 * @return Particle|null
	 */
	private function getParticle(string $name, Vector3 $pos, float $xd, float $yd, float $zd, int $data = null){
		switch($name){
			case "explode":
				return new ExplodeParticle($pos);
			case "hugeexplosion":
				return new HugeExplodeParticle($pos);
			case "hugeexplosionseed":
				return new HugeExplodeSeedParticle($pos);
			case "bubble":
				return new BubbleParticle($pos);
			case "splash":
				return new SplashParticle($pos);
			case "wake":
			case "water":
				return new WaterParticle($pos);
			case "crit":
				return new CriticalParticle($pos);
			case "smoke":
				return new SmokeParticle($pos, $data ?? 0);
			case "spell":
				return new EnchantParticle($pos);
			case "instantspell":
				return new InstantEnchantParticle($pos);
			case "dripwater":
				return new WaterDripParticle($pos);
			case "driplava":
				return new LavaDripParticle($pos);
			case "townaura":
			case "spore":
				return new SporeParticle($pos);
			case "portal":
				return new PortalParticle($pos);
			case "flame":
				return new FlameParticle($pos);
			case "lava":
				return new LavaParticle($pos);
			case "reddust":
				return new RedstoneParticle($pos, $data ?? 1);
			case "snowballpoof":
				return new ItemBreakParticle($pos, ItemFactory::get(Item::SNOWBALL));
			case "slime":
				return new ItemBreakParticle($pos, ItemFactory::get(Item::SLIMEBALL));
			case "itembreak":
				if($data !== null and $data !== 0){
					return new ItemBreakParticle($pos, ItemFactory::get($data));
				}
				break;
			case "terrain":
				if($data !== null and $data !== 0){
					return new TerrainParticle($pos, BlockFactory::get($data));
				}
				break;
			case "heart":
				return new HeartParticle($pos, $data ?? 0);
			case "ink":
				return new InkParticle($pos, $data ?? 0);
			case "droplet":
				return new RainSplashParticle($pos);
			case "enchantmenttable":
				return new EnchantmentTableParticle($pos);
			case "happyvillager":
				return new HappyVillagerParticle($pos);
			case "angryvillager":
				return new AngryVillagerParticle($pos);
			case "forcefield":
				return new BlockForceFieldParticle($pos, $data ?? 0);

		}

		if(strpos($name, "iconcrack_") === 0){
			$d = explode("_", $name);
			if(count($d) === 3){
				return new ItemBreakParticle($pos, ItemFactory::get((int) $d[1], (int) $d[2]));
			}
		}elseif(strpos($name, "blockcrack_") === 0){
			$d = explode("_", $name);
			if(count($d) === 2){
				return new TerrainParticle($pos, BlockFactory::get(((int) $d[1]) & 0xff, ((int) $d[1]) >> 12));
			}
		}elseif(strpos($name, "blockdust_") === 0){
			$d = explode("_", $name);
			if(count($d) >= 4){
				return new DustParticle($pos, ((int) $d[1]) & 0xff, ((int) $d[2]) & 0xff, ((int) $d[3]) & 0xff, isset($d[4]) ? ((int) $d[4]) & 0xff : 255);
			}
		}

		return null;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;
use pocketmine\plugin\Plugin;
use pocketmine\utils\TextFormat;
use function array_map;
use function count;
use function implode;

class PluginsCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.plugins.description",
			"%pocketmine.command.plugins.usage",
			["pl"]
		);
		$this->setPermission("pocketmine.command.plugins");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		$list = array_map(function(Plugin $plugin) : string{
			return ($plugin->isEnabled() ? TextFormat::GREEN : TextFormat::RED) . $plugin->getDescription()->getFullName();
		}, $sender->getServer()->getPluginManager()->getPlugins());

		$sender->sendMessage(new TranslationContainer("pocketmine.command.plugins.success", [count($list), implode(TextFormat::WHITE . ", ", $list)]));
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;
use pocketmine\utils\TextFormat;

class ReloadCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.reload.description",
			"%pocketmine.command.reload.usage"
		);
		$this->setPermission("pocketmine.command.reload");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		Command::broadcastCommandMessage($sender, new TranslationContainer(TextFormat::YELLOW . "%pocketmine.command.reload.reloading"));

		$sender->getServer()->reload();
		Command::broadcastCommandMessage($sender, new TranslationContainer(TextFormat::YELLOW . "%pocketmine.command.reload.reloaded"));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;
use function microtime;
use function round;

class SaveCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.save.description",
			"%commands.save.usage"
		);
		$this->setPermission("pocketmine.command.save.perform");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		Command::broadcastCommandMessage($sender, new TranslationContainer("pocketmine.save.start"));
		$start = microtime(true);

		foreach($sender->getServer()->getOnlinePlayers() as $player){
			$player->save();
		}

		foreach($sender->getServer()->getLevels() as $level){
			$level->save(true);
		}

		Command::broadcastCommandMessage($sender, new TranslationContainer("pocketmine.save.success", [round(microtime(true) - $start, 3)]));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;

class SaveOffCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.saveoff.description",
			"%commands.save-off.usage"
		);
		$this->setPermission("pocketmine.command.save.disable");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		$sender->getServer()->setAutoSave(false);

		Command::broadcastCommandMessage($sender, new TranslationContainer("commands.save.disabled"));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;

class SaveOnCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.saveon.description",
			"%commands.save-on.usage"
		);
		$this->setPermission("pocketmine.command.save.enable");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		$sender->getServer()->setAutoSave(true);

		Command::broadcastCommandMessage($sender, new TranslationContainer("commands.save.enabled"));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\ConsoleCommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function count;
use function implode;

class SayCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.say.description",
			"%commands.say.usage"
		);
		$this->setPermission("pocketmine.command.say");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			throw new InvalidCommandSyntaxException();
		}

		$sender->getServer()->broadcastMessage(new TranslationContainer(TextFormat::LIGHT_PURPLE . "%chat.type.announcement", [$sender instanceof Player ? $sender->getDisplayName() : ($sender instanceof ConsoleCommandSender ? "Server" : $sender->getName()), TextFormat::LIGHT_PURPLE . implode(" ", $args)]));
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;

class SeedCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.seed.description",
			"%commands.seed.usage"
		);
		$this->setPermission("pocketmine.command.seed");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if($sender instanceof Player){
			$seed = $sender->getLevel()->getSeed();
		}else{
			$seed = $sender->getServer()->getDefaultLevel()->getSeed();
		}
		$sender->sendMessage(new TranslationContainer("commands.seed.success", [$seed]));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function count;
use function round;

class SetWorldSpawnCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.setworldspawn.description",
			"%commands.setworldspawn.usage"
		);
		$this->setPermission("pocketmine.command.setworldspawn");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			if($sender instanceof Player){
				$level = $sender->getLevel();
				$pos = (new Vector3($sender->x, $sender->y, $sender->z))->round();
			}else{
				$sender->sendMessage(TextFormat::RED . "You can only perform this command as a player");

				return true;
			}
		}elseif(count($args) === 3){
			$level = $sender->getServer()->getDefaultLevel();
			$pos = new Vector3($this->getInteger($sender, $args[0]), $this->getInteger($sender, $args[1]), $this->getInteger($sender, $args[2]));
		}else{
			throw new InvalidCommandSyntaxException();
		}

		$level->setSpawnLocation($pos);

		Command::broadcastCommandMessage($sender, new TranslationContainer("commands.setworldspawn.success", [round($pos->x, 2), round($pos->y, 2), round($pos->z, 2)]));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\level\Level;
use pocketmine\level\Position;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function count;
use function round;

class SpawnpointCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.spawnpoint.description",
			"%commands.spawnpoint.usage"
		);
		$this->setPermission("pocketmine.command.spawnpoint");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		$target = null;

		if(count($args) === 0){
			if($sender instanceof Player){
				$target = $sender;
			}else{
				$sender->sendMessage(TextFormat::RED . "Please provide a player!");

				return true;
			}
		}else{
			$target = $sender->getServer()->getPlayer($args[0]);
			if($target === null){
				$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound"));

				return true;
			}
		}

		if(count($args) === 4){
			if($target->isValid()){
				$level = $target->getLevel();
				$pos = $sender instanceof Player ? $sender->getPosition() : $level->getSpawnLocation();
				$x = $this->getRelativeDouble($pos->x, $sender, $args[1]);
				$y = $this->getRelativeDouble($pos->y, $sender, $args[2], 0, Level::Y_MAX);
				$z = $this->getRelativeDouble($pos->z, $sender, $args[3]);
				$target->setSpawn(new Position($x, $y, $z, $level));

				Command::broadcastCommandMessage($sender, new TranslationContainer("commands.spawnpoint.success", [$target->getName(), round($x, 2), round($y, 2), round($z, 2)]));

				return true;
			}
		}elseif(count($args) <= 1){
			if($sender instanceof Player){
				$pos = new Position($sender->getFloorX(), $sender->getFloorY(), $sender->getFloorZ(), $sender->getLevel());
				$target->setSpawn($pos);

				Command::broadcastCommandMessage($sender, new TranslationContainer("commands.spawnpoint.success", [$target->getName(), round($pos->x, 2), round($pos->y, 2), round($pos->z, 2)]));
				return true;
			}else{
				$sender->sendMessage(TextFormat::RED . "Please provide a player!");

				return true;
			}
		}

		throw new InvalidCommandSyntaxException();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils;
use function count;
use function floor;
use function microtime;
use function number_format;
use function round;

class StatusCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.status.description",
			"%pocketmine.command.status.usage"
		);
		$this->setPermission("pocketmine.command.status");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		$rUsage = Utils::getRealMemoryUsage();
		$mUsage = Utils::getMemoryUsage(true);

		$server = $sender->getServer();
		$sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Server status" . TextFormat::GREEN . " ----");

		$time = microtime(true) - \pocketmine\START_TIME;

		$seconds = floor($time % 60);
		$minutes = null;
		$hours = null;
		$days = null;

		if($time >= 60){
			$minutes = floor(($time % 3600) / 60);
			if($time >= 3600){
				$hours = floor(($time % (3600 * 24)) / 3600);
				if($time >= 3600 * 24){
					$days = floor($time / (3600 * 24));
				}
			}
		}

		$uptime = ($minutes !== null ?
				($hours !== null ?
					($days !== null ?
						"$days days "
					: "") . "$hours hours "
					: "") . "$minutes minutes "
			: "") . "$seconds seconds";

		$sender->sendMessage(TextFormat::GOLD . "Uptime: " . TextFormat::RED . $uptime);

		$tpsColor = TextFormat::GREEN;
		if($server->getTicksPerSecond() < 17){
			$tpsColor = TextFormat::GOLD;
		}elseif($server->getTicksPerSecond() < 12){
			$tpsColor = TextFormat::RED;
		}

		$sender->sendMessage(TextFormat::GOLD . "Current TPS: {$tpsColor}{$server->getTicksPerSecond()} ({$server->getTickUsage()}%)");
		$sender->sendMessage(TextFormat::GOLD . "Average TPS: {$tpsColor}{$server->getTicksPerSecondAverage()} ({$server->getTickUsageAverage()}%)");

		$sender->sendMessage(TextFormat::GOLD . "Network upload: " . TextFormat::RED . round($server->getNetwork()->getUpload() / 1024, 2) . " kB/s");
		$sender->sendMessage(TextFormat::GOLD . "Network download: " . TextFormat::RED . round($server->getNetwork()->getDownload() / 1024, 2) . " kB/s");

		$sender->sendMessage(TextFormat::GOLD . "Thread count: " . TextFormat::RED . Utils::getThreadCount());

		$sender->sendMessage(TextFormat::GOLD . "Main thread memory: " . TextFormat::RED . number_format(round(($mUsage[0] / 1024) / 1024, 2), 2) . " MB.");
		$sender->sendMessage(TextFormat::GOLD . "Total memory: " . TextFormat::RED . number_format(round(($mUsage[1] / 1024) / 1024, 2), 2) . " MB.");
		$sender->sendMessage(TextFormat::GOLD . "Total virtual memory: " . TextFormat::RED . number_format(round(($mUsage[2] / 1024) / 1024, 2), 2) . " MB.");
		$sender->sendMessage(TextFormat::GOLD . "Heap memory: " . TextFormat::RED . number_format(round(($rUsage[0] / 1024) / 1024, 2), 2) . " MB.");
		$sender->sendMessage(TextFormat::GOLD . "Maximum memory (system): " . TextFormat::RED . number_format(round(($mUsage[2] / 1024) / 1024, 2), 2) . " MB.");

		if($server->getProperty("memory.global-limit") > 0){
			$sender->sendMessage(TextFormat::GOLD . "Maximum memory (manager): " . TextFormat::RED . number_format(round($server->getProperty("memory.global-limit"), 2), 2) . " MB.");
		}

		foreach($server->getLevels() as $level){
			$levelName = $level->getFolderName() !== $level->getName() ? " (" . $level->getName() . ")" : "";
			$timeColor = $level->getTickRateTime() > 40 ? TextFormat::RED : TextFormat::YELLOW;
			$sender->sendMessage(TextFormat::GOLD . "World \"{$level->getFolderName()}\"$levelName: " .
				TextFormat::RED . number_format(count($level->getChunks())) . TextFormat::GREEN . " chunks, " .
				TextFormat::RED . number_format(count($level->getEntities())) . TextFormat::GREEN . " entities. " .
				"Time $timeColor" . round($level->getTickRateTime(), 2) . "ms"
			);
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;

class StopCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.stop.description",
			"%commands.stop.usage"
		);
		$this->setPermission("pocketmine.command.stop");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		Command::broadcastCommandMessage($sender, new TranslationContainer("commands.stop.start"));

		$sender->getServer()->shutdown();

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function array_filter;
use function array_values;
use function count;
use function round;

class TeleportCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.tp.description",
			"%commands.tp.usage",
			["teleport"]
		);
		$this->setPermission("pocketmine.command.teleport");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		$args = array_values(array_filter($args, function(string $arg) : bool{
			return $arg !== "";
		}));
		if(count($args) < 1 or count($args) > 6){
			throw new InvalidCommandSyntaxException();
		}

		$target = null;
		$origin = $sender;

		if(count($args) === 1 or count($args) === 3){
			if($sender instanceof Player){
				$target = $sender;
			}else{
				$sender->sendMessage(TextFormat::RED . "Please provide a player!");

				return true;
			}
			if(count($args) === 1){
				$target = $sender->getServer()->getPlayer($args[0]);
				if($target === null){
					$sender->sendMessage(TextFormat::RED . "Can't find player " . $args[0]);

					return true;
				}
			}
		}else{
			$target = $sender->getServer()->getPlayer($args[0]);
			if($target === null){
				$sender->sendMessage(TextFormat::RED . "Can't find player " . $args[0]);

				return true;
			}
			if(count($args) === 2){
				$origin = $target;
				$target = $sender->getServer()->getPlayer($args[1]);
				if($target === null){
					$sender->sendMessage(TextFormat::RED . "Can't find player " . $args[1]);

					return true;
				}
			}
		}

		if(count($args) < 3){
			$origin->teleport($target);
			Command::broadcastCommandMessage($sender, new TranslationContainer("commands.tp.success", [$origin->getName(), $target->getName()]));

			return true;
		}elseif($target->isValid()){
			if(count($args) === 4 or count($args) === 6){
				$pos = 1;
			}else{
				$pos = 0;
			}

			$x = $this->getRelativeDouble($target->x, $sender, $args[$pos++]);
			$y = $this->getRelativeDouble($target->y, $sender, $args[$pos++], 0, 256);
			$z = $this->getRelativeDouble($target->z, $sender, $args[$pos++]);
			$yaw = $target->getYaw();
			$pitch = $target->getPitch();

			if(count($args) === 6 or (count($args) === 5 and $pos === 3)){
				$yaw = (float) $args[$pos++];
				$pitch = (float) $args[$pos++];
			}

			$target->teleport(new Vector3($x, $y, $z), $yaw, $pitch);
			Command::broadcastCommandMessage($sender, new TranslationContainer("commands.tp.success.coordinates", [$target->getName(), round($x, 2), round($y, 2), round($z, 2)]));

			return true;
		}

		throw new InvalidCommandSyntaxException();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function array_shift;
use function count;
use function implode;

class TellCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.tell.description",
			"%commands.message.usage",
			["w", "msg"]
		);
		$this->setPermission("pocketmine.command.tell");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) < 2){
			throw new InvalidCommandSyntaxException();
		}

		$player = $sender->getServer()->getPlayer(array_shift($args));

		if($player === $sender){
			$sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.message.sameTarget"));
			return true;
		}

		if($player instanceof Player){
			$sender->sendMessage("[{$sender->getName()} -> {$player->getDisplayName()}] " . implode(" ", $args));
			$name = $sender instanceof Player ? $sender->getDisplayName() : $sender->getName();
			$player->sendMessage("[$name -> {$player->getName()}] " . implode(" ", $args));
		}else{
			$sender->sendMessage(new TranslationContainer("commands.generic.player.notFound"));
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\level\Level;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function count;

class TimeCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.time.description",
			"%pocketmine.command.time.usage"
		);
		$this->setPermission("pocketmine.command.time.add;pocketmine.command.time.set;pocketmine.command.time.start;pocketmine.command.time.stop");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(count($args) < 1){
			throw new InvalidCommandSyntaxException();
		}

		if($args[0] === "start"){
			if(!$sender->hasPermission("pocketmine.command.time.start")){
				$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));

				return true;
			}
			foreach($sender->getServer()->getLevels() as $level){
				$level->startTime();
			}
			Command::broadcastCommandMessage($sender, "Restarted the time");
			return true;
		}elseif($args[0] === "stop"){
			if(!$sender->hasPermission("pocketmine.command.time.stop")){
				$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));

				return true;
			}
			foreach($sender->getServer()->getLevels() as $level){
				$level->stopTime();
			}
			Command::broadcastCommandMessage($sender, "Stopped the time");
			return true;
		}elseif($args[0] === "query"){
			if(!$sender->hasPermission("pocketmine.command.time.query")){
				$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));

				return true;
			}
			if($sender instanceof Player){
				$level = $sender->getLevel();
			}else{
				$level = $sender->getServer()->getDefaultLevel();
			}
			$sender->sendMessage($sender->getServer()->getLanguage()->translateString("commands.time.query", [$level->getTime()]));
			return true;
		}

		if(count($args) < 2){
			throw new InvalidCommandSyntaxException();
		}

		if($args[0] === "set"){
			if(!$sender->hasPermission("pocketmine.command.time.set")){
				$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));

				return true;
			}

			if($args[1] === "day"){
				$value = Level::TIME_DAY;
			}elseif($args[1] === "night"){
				$value = Level::TIME_NIGHT;
			}else{
				$value = $this->getInteger($sender, $args[1], 0);
			}

			foreach($sender->getServer()->getLevels() as $level){
				$level->setTime($value);
			}
			Command::broadcastCommandMessage($sender, new TranslationContainer("commands.time.set", [$value]));
		}elseif($args[0] === "add"){
			if(!$sender->hasPermission("pocketmine.command.time.add")){
				$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));

				return true;
			}

			$value = $this->getInteger($sender, $args[1], 0);
			foreach($sender->getServer()->getLevels() as $level){
				$level->setTime($level->getTime() + $value);
			}
			Command::broadcastCommandMessage($sender, new TranslationContainer("commands.time.added", [$value]));
		}else{
			throw new InvalidCommandSyntaxException();
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\scheduler\BulkCurlTask;
use pocketmine\Server;
use pocketmine\timings\TimingsHandler;
use pocketmine\utils\InternetException;
use function count;
use function fclose;
use function file_exists;
use function fopen;
use function fseek;
use function http_build_query;
use function is_array;
use function json_decode;
use function mkdir;
use function stream_get_contents;
use function strtolower;
use const CURLOPT_AUTOREFERER;
use const CURLOPT_FOLLOWLOCATION;
use const CURLOPT_HTTPHEADER;
use const CURLOPT_POST;
use const CURLOPT_POSTFIELDS;

class TimingsCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.timings.description",
			"%pocketmine.command.timings.usage"
		);
		$this->setPermission("pocketmine.command.timings");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) !== 1){
			throw new InvalidCommandSyntaxException();
		}

		$mode = strtolower($args[0]);

		if($mode === "on"){
			TimingsHandler::setEnabled();
			$sender->sendMessage(new TranslationContainer("pocketmine.command.timings.enable"));

			return true;
		}elseif($mode === "off"){
			TimingsHandler::setEnabled(false);
			$sender->sendMessage(new TranslationContainer("pocketmine.command.timings.disable"));
			return true;
		}

		if(!TimingsHandler::isEnabled()){
			$sender->sendMessage(new TranslationContainer("pocketmine.command.timings.timingsDisabled"));

			return true;
		}

		$paste = $mode === "paste";

		if($mode === "reset"){
			TimingsHandler::reload();
			$sender->sendMessage(new TranslationContainer("pocketmine.command.timings.reset"));
		}elseif($mode === "merged" or $mode === "report" or $paste){
			$timings = "";
			if($paste){
				$fileTimings = fopen("php://temp", "r+b");
			}else{
				$index = 0;
				$timingFolder = $sender->getServer()->getDataPath() . "timings/";

				if(!file_exists($timingFolder)){
					mkdir($timingFolder, 0777);
				}
				$timings = $timingFolder . "timings.txt";
				while(file_exists($timings)){
					$timings = $timingFolder . "timings" . (++$index) . ".txt";
				}

				$fileTimings = fopen($timings, "a+b");
			}
			TimingsHandler::printTimings($fileTimings);

			if($paste){
				fseek($fileTimings, 0);
				$data = [
					"browser" => $agent = $sender->getServer()->getName() . " " . $sender->getServer()->getPocketMineVersion(),
					"data" => $content = stream_get_contents($fileTimings)
				];
				fclose($fileTimings);

				$host = $sender->getServer()->getProperty("timings.host", "timings.pmmp.io");

				$sender->getServer()->getAsyncPool()->submitTask(new class($sender, $host, $agent, $data) extends BulkCurlTask{
					/** @var string */
					private $host;

					/**
					 * @param string[] $data
					 * @phpstan-param array<string, string> $data
					 */
					public function __construct(CommandSender $sender, string $host, string $agent, array $data){
						parent::__construct([
							[
								"page" => "https://$host?upload=true",
								"extraOpts" => [
									CURLOPT_HTTPHEADER => [
										"User-Agent: $agent",
										"Content-Type: application/x-www-form-urlencoded"
									],
									CURLOPT_POST => true,
									CURLOPT_POSTFIELDS => http_build_query($data),
									CURLOPT_AUTOREFERER => false,
									CURLOPT_FOLLOWLOCATION => false
								]
							]
						], $sender);
						$this->host = $host;
					}

					public function onCompletion(Server $server){
						$sender = $this->fetchLocal();
						if($sender instanceof Player and !$sender->isOnline()){ // TODO replace with a more generic API method for checking availability of CommandSender
							return;
						}
						$result = $this->getResult()[0];
						if($result instanceof InternetException){
							$server->getLogger()->logException($result);
							return;
						}
						if(isset($result[0]) && is_array($response = json_decode($result[0], true)) && isset($response["id"])){
							$sender->sendMessage(new TranslationContainer("pocketmine.command.timings.timingsRead",
								["https://" . $this->host . "/?id=" . $response["id"]]));
						}else{
							$sender->sendMessage(new TranslationContainer("pocketmine.command.timings.pasteError"));
						}
					}
				});
			}else{
				fclose($fileTimings);
				$sender->sendMessage(new TranslationContainer("pocketmine.command.timings.timingsWrite", [$timings]));
			}
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use function array_slice;
use function count;
use function implode;

class TitleCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.title.description",
			"%commands.title.usage"
		);
		$this->setPermission("pocketmine.command.title");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) < 2){
			throw new InvalidCommandSyntaxException();
		}

		$player = $sender->getServer()->getPlayer($args[0]);
		if($player === null){
			$sender->sendMessage(new TranslationContainer("commands.generic.player.notFound"));
			return true;
		}

		switch($args[1]){
			case "clear":
				$player->removeTitles();
				break;
			case "reset":
				$player->resetTitles();
				break;
			case "title":
				if(count($args) < 3){
					throw new InvalidCommandSyntaxException();
				}

				$player->addTitle(implode(" ", array_slice($args, 2)));
				break;
			case "subtitle":
				if(count($args) < 3){
					throw new InvalidCommandSyntaxException();
				}

				$player->addSubTitle(implode(" ", array_slice($args, 2)));
				break;
			case "actionbar":
				if(count($args) < 3){
					throw new InvalidCommandSyntaxException();
				}

				$player->addActionBarMessage(implode(" ", array_slice($args, 2)));
				break;
			case "times":
				if(count($args) < 5){
					throw new InvalidCommandSyntaxException();
				}

				$player->setTitleDuration($this->getInteger($sender, $args[2]), $this->getInteger($sender, $args[3]), $this->getInteger($sender, $args[4]));
				break;
			default:
				throw new InvalidCommandSyntaxException();
		}

		$sender->sendMessage(new TranslationContainer("commands.title.success"));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\Player;
use function count;

class TransferServerCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.transferserver.description",
			"%pocketmine.command.transferserver.usage"
		);
		$this->setPermission("pocketmine.command.transferserver");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) < 1){
			throw new InvalidCommandSyntaxException();
		}elseif(!($sender instanceof Player)){
			$sender->sendMessage("This command must be executed as a player");

			return false;
		}

		$sender->transfer($args[0], (int) ($args[1] ?? 19132));

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\CommandSender;
use pocketmine\lang\TranslationContainer;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\plugin\Plugin;
use pocketmine\utils\TextFormat;
use function count;
use function implode;
use function stripos;
use function strtolower;

class VersionCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.version.description",
			"%pocketmine.command.version.usage",
			["ver", "about"]
		);
		$this->setPermission("pocketmine.command.version");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0){
			$sender->sendMessage(new TranslationContainer("pocketmine.server.info.extended", [
				$sender->getServer()->getName(),
				$sender->getServer()->getPocketMineVersion(),
				$sender->getServer()->getVersion(),
				ProtocolInfo::CURRENT_PROTOCOL
			]));
		}else{
			$pluginName = implode(" ", $args);
			$exactPlugin = $sender->getServer()->getPluginManager()->getPlugin($pluginName);

			if($exactPlugin instanceof Plugin){
				$this->describeToSender($exactPlugin, $sender);

				return true;
			}

			$found = false;
			$pluginName = strtolower($pluginName);
			foreach($sender->getServer()->getPluginManager()->getPlugins() as $plugin){
				if(stripos($plugin->getName(), $pluginName) !== false){
					$this->describeToSender($plugin, $sender);
					$found = true;
				}
			}

			if(!$found){
				$sender->sendMessage(new TranslationContainer("pocketmine.command.version.noSuchPlugin"));
			}
		}

		return true;
	}

	private function describeToSender(Plugin $plugin, CommandSender $sender) : void{
		$desc = $plugin->getDescription();
		$sender->sendMessage(TextFormat::DARK_GREEN . $desc->getName() . TextFormat::WHITE . " version " . TextFormat::DARK_GREEN . $desc->getVersion());

		if($desc->getDescription() !== ""){
			$sender->sendMessage($desc->getDescription());
		}

		if($desc->getWebsite() !== ""){
			$sender->sendMessage("Website: " . $desc->getWebsite());
		}

		if(count($authors = $desc->getAuthors()) > 0){
			if(count($authors) === 1){
				$sender->sendMessage("Author: " . implode(", ", $authors));
			}else{
				$sender->sendMessage("Authors: " . implode(", ", $authors));
			}
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\command\defaults;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\TranslationContainer;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function count;
use function implode;
use function strtolower;

class WhitelistCommand extends VanillaCommand{

	public function __construct(string $name){
		parent::__construct(
			$name,
			"%pocketmine.command.whitelist.description",
			"%commands.whitelist.usage"
		);
		$this->setPermission("pocketmine.command.whitelist.reload;pocketmine.command.whitelist.enable;pocketmine.command.whitelist.disable;pocketmine.command.whitelist.list;pocketmine.command.whitelist.add;pocketmine.command.whitelist.remove");
	}

	public function execute(CommandSender $sender, string $commandLabel, array $args){
		if(!$this->testPermission($sender)){
			return true;
		}

		if(count($args) === 0 or count($args) > 2){
			throw new InvalidCommandSyntaxException();
		}

		if(count($args) === 1){
			if($this->badPerm($sender, strtolower($args[0]))){
				return false;
			}
			switch(strtolower($args[0])){
				case "reload":
					$sender->getServer()->reloadWhitelist();
					Command::broadcastCommandMessage($sender, new TranslationContainer("commands.whitelist.reloaded"));

					return true;
				case "on":
					$sender->getServer()->setConfigBool("white-list", true);
					Command::broadcastCommandMessage($sender, new TranslationContainer("commands.whitelist.enabled"));

					return true;
				case "off":
					$sender->getServer()->setConfigBool("white-list", false);
					Command::broadcastCommandMessage($sender, new TranslationContainer("commands.whitelist.disabled"));

					return true;
				case "list":
					$entries = $sender->getServer()->getWhitelisted()->getAll(true);
					$result = implode($entries, ", ");
					$count = count($entries);

					$sender->sendMessage(new TranslationContainer("commands.whitelist.list", [$count, $count]));
					$sender->sendMessage($result);

					return true;

				case "add":
					$sender->sendMessage(new TranslationContainer("commands.generic.usage", ["%commands.whitelist.add.usage"]));
					return true;

				case "remove":
					$sender->sendMessage(new TranslationContainer("commands.generic.usage", ["%commands.whitelist.remove.usage"]));
					return true;
			}
		}elseif(count($args) === 2){
			if($this->badPerm($sender, strtolower($args[0]))){
				return false;
			}
			if(!Player::isValidUserName($args[1])){
				throw new InvalidCommandSyntaxException();
			}
			switch(strtolower($args[0])){
				case "add":
					$sender->getServer()->getOfflinePlayer($args[1])->setWhitelisted(true);
					Command::broadcastCommandMessage($sender, new TranslationContainer("commands.whitelist.add.success", [$args[1]]));

					return true;
				case "remove":
					$sender->getServer()->getOfflinePlayer($args[1])->setWhitelisted(false);
					Command::broadcastCommandMessage($sender, new TranslationContainer("commands.whitelist.remove.success", [$args[1]]));

					return true;
			}
		}

		return true;
	}

	private function badPerm(CommandSender $sender, string $subcommand) : bool{
		static $map = [
			"on" => "enable",
			"off" => "disable"
		];
		if(!$sender->hasPermission("pocketmine.command.whitelist." . ($map[$subcommand] ?? $subcommand))){
			$sender->sendMessage($sender->getServer()->getLanguage()->translateString(TextFormat::RED . "%commands.generic.permission"));

			return true;
		}

		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * All the entity classes
 */
namespace pocketmine\entity;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\block\Water;
use pocketmine\entity\object\ExperienceOrb;
use pocketmine\entity\object\FallingBlock;
use pocketmine\entity\object\ItemEntity;
use pocketmine\entity\object\Painting;
use pocketmine\entity\object\PaintingMotive;
use pocketmine\entity\object\PrimedTNT;
use pocketmine\entity\projectile\Arrow;
use pocketmine\entity\projectile\Egg;
use pocketmine\entity\projectile\EnderPearl;
use pocketmine\entity\projectile\ExperienceBottle;
use pocketmine\entity\projectile\Snowball;
use pocketmine\entity\projectile\SplashPotion;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityDespawnEvent;
use pocketmine\event\entity\EntityLevelChangeEvent;
use pocketmine\event\entity\EntityMotionEvent;
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\event\entity\EntitySpawnEvent;
use pocketmine\event\entity\EntityTeleportEvent;
use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\level\Location;
use pocketmine\level\Position;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector2;
use pocketmine\math\Vector3;
use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\SetActorDataPacket;
use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
use pocketmine\Player;
use pocketmine\plugin\Plugin;
use pocketmine\Server;
use pocketmine\timings\Timings;
use pocketmine\timings\TimingsHandler;
use function abs;
use function assert;
use function cos;
use function count;
use function current;
use function deg2rad;
use function floor;
use function get_class;
use function in_array;
use function is_a;
use function is_array;
use function is_infinite;
use function is_nan;
use function lcg_value;
use function reset;
use function sin;
use const M_PI_2;

abstract class Entity extends Location implements Metadatable, EntityIds{

	public const MOTION_THRESHOLD = 0.00001;

	public const NETWORK_ID = -1;

	public const DATA_TYPE_BYTE = 0;
	public const DATA_TYPE_SHORT = 1;
	public const DATA_TYPE_INT = 2;
	public const DATA_TYPE_FLOAT = 3;
	public const DATA_TYPE_STRING = 4;
	public const DATA_TYPE_COMPOUND_TAG = 5;
	public const DATA_TYPE_POS = 6;
	public const DATA_TYPE_LONG = 7;
	public const DATA_TYPE_VECTOR3F = 8;

	/*
	 * Readers beware: this isn't a nice list. Some of the properties have different types for different entities, and
	 * are used for entirely different things.
	 */
	public const DATA_FLAGS = 0;
	public const DATA_HEALTH = 1; //int (minecart/boat)
	public const DATA_VARIANT = 2; //int
	public const DATA_COLOR = 3, DATA_COLOUR = 3; //byte
	public const DATA_NAMETAG = 4; //string
	public const DATA_OWNER_EID = 5; //long
	public const DATA_TARGET_EID = 6; //long
	public const DATA_AIR = 7; //short
	public const DATA_POTION_COLOR = 8; //int (ARGB!)
	public const DATA_POTION_AMBIENT = 9; //byte
	/* 10 (byte) */
	public const DATA_HURT_TIME = 11; //int (minecart/boat)
	public const DATA_HURT_DIRECTION = 12; //int (minecart/boat)
	public const DATA_PADDLE_TIME_LEFT = 13; //float
	public const DATA_PADDLE_TIME_RIGHT = 14; //float
	public const DATA_EXPERIENCE_VALUE = 15; //int (xp orb)
	public const DATA_MINECART_DISPLAY_BLOCK = 16; //int (id | (data << 16))
	public const DATA_HORSE_FLAGS = 16; //int
	/* 16 (byte) used by wither skull */
	public const DATA_MINECART_DISPLAY_OFFSET = 17; //int
	public const DATA_SHOOTER_ID = 17; //long (used by arrows)
	public const DATA_MINECART_HAS_DISPLAY = 18; //byte (must be 1 for minecart to show block inside)
	public const DATA_HORSE_TYPE = 19; //byte
	/* 20 (unknown)
	 * 21 (unknown) */
	public const DATA_CHARGE_AMOUNT = 22; //int8, used for ghasts and also crossbow charging
	public const DATA_ENDERMAN_HELD_ITEM_ID = 23; //short
	public const DATA_ENTITY_AGE = 24; //short
	/* 25 (int) used by horse, (byte) used by witch */
	public const DATA_PLAYER_FLAGS = 26; //byte
	public const DATA_PLAYER_INDEX = 27; //int, used for marker colours and agent nametag colours
	public const DATA_PLAYER_BED_POSITION = 28; //blockpos
	public const DATA_FIREBALL_POWER_X = 29; //float
	public const DATA_FIREBALL_POWER_Y = 30;
	public const DATA_FIREBALL_POWER_Z = 31;
	/* 32 (unknown)
	 * 33 (float) fishing bobber
	 * 34 (float) fishing bobber
	 * 35 (float) fishing bobber */
	public const DATA_POTION_AUX_VALUE = 36; //short
	public const DATA_LEAD_HOLDER_EID = 37; //long
	public const DATA_SCALE = 38; //float
	public const DATA_HAS_NPC_COMPONENT = 39; //byte (???)
	public const DATA_NPC_SKIN_INDEX = 40; //string
	public const DATA_NPC_ACTIONS = 41; //string (maybe JSON blob?)
	public const DATA_MAX_AIR = 42; //short
	public const DATA_MARK_VARIANT = 43; //int
	public const DATA_CONTAINER_TYPE = 44; //byte (ContainerComponent)
	public const DATA_CONTAINER_BASE_SIZE = 45; //int (ContainerComponent)
	public const DATA_CONTAINER_EXTRA_SLOTS_PER_STRENGTH = 46; //int (used for llamas, inventory size is baseSize + thisProp * strength)
	public const DATA_BLOCK_TARGET = 47; //block coords (ender crystal)
	public const DATA_WITHER_INVULNERABLE_TICKS = 48; //int
	public const DATA_WITHER_TARGET_1 = 49; //long
	public const DATA_WITHER_TARGET_2 = 50; //long
	public const DATA_WITHER_TARGET_3 = 51; //long
	/* 52 (short) */
	public const DATA_BOUNDING_BOX_WIDTH = 53; //float
	public const DATA_BOUNDING_BOX_HEIGHT = 54; //float
	public const DATA_FUSE_LENGTH = 55; //int
	public const DATA_RIDER_SEAT_POSITION = 56; //vector3f
	public const DATA_RIDER_ROTATION_LOCKED = 57; //byte
	public const DATA_RIDER_MAX_ROTATION = 58; //float
	public const DATA_RIDER_MIN_ROTATION = 59; //float
	public const DATA_AREA_EFFECT_CLOUD_RADIUS = 60; //float
	public const DATA_AREA_EFFECT_CLOUD_WAITING = 61; //int
	public const DATA_AREA_EFFECT_CLOUD_PARTICLE_ID = 62; //int
	/* 63 (int) shulker-related */
	public const DATA_SHULKER_ATTACH_FACE = 64; //byte
	/* 65 (short) shulker-related */
	public const DATA_SHULKER_ATTACH_POS = 66; //block coords
	public const DATA_TRADING_PLAYER_EID = 67; //long

	/* 69 (byte) command-block */
	public const DATA_COMMAND_BLOCK_COMMAND = 70; //string
	public const DATA_COMMAND_BLOCK_LAST_OUTPUT = 71; //string
	public const DATA_COMMAND_BLOCK_TRACK_OUTPUT = 72; //byte
	public const DATA_CONTROLLING_RIDER_SEAT_NUMBER = 73; //byte
	public const DATA_STRENGTH = 74; //int
	public const DATA_MAX_STRENGTH = 75; //int
	/* 76 (int) */
	public const DATA_LIMITED_LIFE = 77;
	public const DATA_ARMOR_STAND_POSE_INDEX = 78; //int
	public const DATA_ENDER_CRYSTAL_TIME_OFFSET = 79; //int
	public const DATA_ALWAYS_SHOW_NAMETAG = 80; //byte: -1 = default, 0 = only when looked at, 1 = always
	public const DATA_COLOR_2 = 81; //byte
	/* 82 (unknown) */
	public const DATA_SCORE_TAG = 83; //string
	public const DATA_BALLOON_ATTACHED_ENTITY = 84; //int64, entity unique ID of owner
	public const DATA_PUFFERFISH_SIZE = 85; //byte
	public const DATA_BOAT_BUBBLE_TIME = 86; //int (time in bubble column)
	public const DATA_PLAYER_AGENT_EID = 87; //long
	/* 88 (float) related to panda sitting
	 * 89 (float) related to panda sitting */
	public const DATA_EAT_COUNTER = 90; //int (used by pandas)
	public const DATA_FLAGS2 = 91; //long (extended data flags)
	/* 92 (float) related to panda lying down
	 * 93 (float) related to panda lying down */
	public const DATA_AREA_EFFECT_CLOUD_DURATION = 94; //int
	public const DATA_AREA_EFFECT_CLOUD_SPAWN_TIME = 95; //int
	public const DATA_AREA_EFFECT_CLOUD_RADIUS_PER_TICK = 96; //float, usually negative
	public const DATA_AREA_EFFECT_CLOUD_RADIUS_CHANGE_ON_PICKUP = 97; //float
	public const DATA_AREA_EFFECT_CLOUD_PICKUP_COUNT = 98; //int
	public const DATA_INTERACTIVE_TAG = 99; //string (button text)
	public const DATA_TRADE_TIER = 100; //int
	public const DATA_MAX_TRADE_TIER = 101; //int
	public const DATA_TRADE_XP = 102; //int
	public const DATA_SKIN_ID = 103; //int ???
	/* 104 (int) related to wither */
	public const DATA_COMMAND_BLOCK_TICK_DELAY = 105; //int
	public const DATA_COMMAND_BLOCK_EXECUTE_ON_FIRST_TICK = 106; //byte
	public const DATA_AMBIENT_SOUND_INTERVAL_MIN = 107; //float
	public const DATA_AMBIENT_SOUND_INTERVAL_RANGE = 108; //float
	public const DATA_AMBIENT_SOUND_EVENT = 109; //string

	public const DATA_FLAG_ONFIRE = 0;
	public const DATA_FLAG_SNEAKING = 1;
	public const DATA_FLAG_RIDING = 2;
	public const DATA_FLAG_SPRINTING = 3;
	public const DATA_FLAG_ACTION = 4;
	public const DATA_FLAG_INVISIBLE = 5;
	public const DATA_FLAG_TEMPTED = 6;
	public const DATA_FLAG_INLOVE = 7;
	public const DATA_FLAG_SADDLED = 8;
	public const DATA_FLAG_POWERED = 9;
	public const DATA_FLAG_IGNITED = 10;
	public const DATA_FLAG_BABY = 11;
	public const DATA_FLAG_CONVERTING = 12;
	public const DATA_FLAG_CRITICAL = 13;
	public const DATA_FLAG_CAN_SHOW_NAMETAG = 14;
	public const DATA_FLAG_ALWAYS_SHOW_NAMETAG = 15;
	public const DATA_FLAG_IMMOBILE = 16, DATA_FLAG_NO_AI = 16;
	public const DATA_FLAG_SILENT = 17;
	public const DATA_FLAG_WALLCLIMBING = 18;
	public const DATA_FLAG_CAN_CLIMB = 19;
	public const DATA_FLAG_SWIMMER = 20;
	public const DATA_FLAG_CAN_FLY = 21;
	public const DATA_FLAG_WALKER = 22;
	public const DATA_FLAG_RESTING = 23;
	public const DATA_FLAG_SITTING = 24;
	public const DATA_FLAG_ANGRY = 25;
	public const DATA_FLAG_INTERESTED = 26;
	public const DATA_FLAG_CHARGED = 27;
	public const DATA_FLAG_TAMED = 28;
	public const DATA_FLAG_ORPHANED = 29;
	public const DATA_FLAG_LEASHED = 30;
	public const DATA_FLAG_SHEARED = 31;
	public const DATA_FLAG_GLIDING = 32;
	public const DATA_FLAG_ELDER = 33;
	public const DATA_FLAG_MOVING = 34;
	public const DATA_FLAG_BREATHING = 35;
	public const DATA_FLAG_CHESTED = 36;
	public const DATA_FLAG_STACKABLE = 37;
	public const DATA_FLAG_SHOWBASE = 38;
	public const DATA_FLAG_REARING = 39;
	public const DATA_FLAG_VIBRATING = 40;
	public const DATA_FLAG_IDLING = 41;
	public const DATA_FLAG_EVOKER_SPELL = 42;
	public const DATA_FLAG_CHARGE_ATTACK = 43;
	public const DATA_FLAG_WASD_CONTROLLED = 44;
	public const DATA_FLAG_CAN_POWER_JUMP = 45;
	public const DATA_FLAG_LINGER = 46;
	public const DATA_FLAG_HAS_COLLISION = 47;
	public const DATA_FLAG_AFFECTED_BY_GRAVITY = 48;
	public const DATA_FLAG_FIRE_IMMUNE = 49;
	public const DATA_FLAG_DANCING = 50;
	public const DATA_FLAG_ENCHANTED = 51;
	public const DATA_FLAG_SHOW_TRIDENT_ROPE = 52; // tridents show an animated rope when enchanted with loyalty after they are thrown and return to their owner. To be combined with DATA_OWNER_EID
	public const DATA_FLAG_CONTAINER_PRIVATE = 53; //inventory is private, doesn't drop contents when killed if true
	public const DATA_FLAG_TRANSFORMING = 54;
	public const DATA_FLAG_SPIN_ATTACK = 55;
	public const DATA_FLAG_SWIMMING = 56;
	public const DATA_FLAG_BRIBED = 57; //dolphins have this set when they go to find treasure for the player
	public const DATA_FLAG_PREGNANT = 58;
	public const DATA_FLAG_LAYING_EGG = 59;
	public const DATA_FLAG_RIDER_CAN_PICK = 60; //???
	public const DATA_FLAG_TRANSITION_SITTING = 61;
	public const DATA_FLAG_EATING = 62;
	public const DATA_FLAG_LAYING_DOWN = 63;
	public const DATA_FLAG_SNEEZING = 64;
	public const DATA_FLAG_TRUSTING = 65;
	public const DATA_FLAG_ROLLING = 66;
	public const DATA_FLAG_SCARED = 67;
	public const DATA_FLAG_IN_SCAFFOLDING = 68;
	public const DATA_FLAG_OVER_SCAFFOLDING = 69;
	public const DATA_FLAG_FALL_THROUGH_SCAFFOLDING = 70;
	public const DATA_FLAG_BLOCKING = 71; //shield
	public const DATA_FLAG_DISABLE_BLOCKING = 72;
	//73 is set when a player is attacked while using shield, unclear on purpose
	//74 related to shield usage, needs further investigation
	public const DATA_FLAG_SLEEPING = 75;
	//76 related to sleeping, unclear usage
	public const DATA_FLAG_TRADE_INTEREST = 77;
	public const DATA_FLAG_DOOR_BREAKER = 78; //...
	public const DATA_FLAG_BREAKING_OBSTRUCTION = 79;
	public const DATA_FLAG_DOOR_OPENER = 80; //...
	public const DATA_FLAG_ILLAGER_CAPTAIN = 81;
	public const DATA_FLAG_STUNNED = 82;
	public const DATA_FLAG_ROARING = 83;
	public const DATA_FLAG_DELAYED_ATTACKING = 84;
	public const DATA_FLAG_AVOIDING_MOBS = 85;
	//86 used by RangedAttackGoal
	//87 used by NearestAttackableTargetGoal

	public const DATA_PLAYER_FLAG_SLEEP = 1;
	public const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK

	/** @var int */
	public static $entityCount = 1;
	/**
	 * @var string[]
	 * @phpstan-var array<int|string, class-string<Entity>>
	 */
	private static $knownEntities = [];
	/**
	 * @var string[][]
	 * @phpstan-var array<class-string<Entity>, list<string>>
	 */
	private static $saveNames = [];

	/**
	 * Called on server startup to register default entity types.
	 */
	public static function init() : void{
		//define legacy save IDs first - use them for saving for maximum compatibility with Minecraft PC
		//TODO: index them by version to allow proper multi-save compatibility

		Entity::registerEntity(Arrow::class, false, ['Arrow', 'minecraft:arrow']);
		Entity::registerEntity(Egg::class, false, ['Egg', 'minecraft:egg']);
		Entity::registerEntity(EnderPearl::class, false, ['ThrownEnderpearl', 'minecraft:ender_pearl']);
		Entity::registerEntity(ExperienceBottle::class, false, ['ThrownExpBottle', 'minecraft:xp_bottle']);
		Entity::registerEntity(ExperienceOrb::class, false, ['XPOrb', 'minecraft:xp_orb']);
		Entity::registerEntity(FallingBlock::class, false, ['FallingSand', 'minecraft:falling_block']);
		Entity::registerEntity(ItemEntity::class, false, ['Item', 'minecraft:item']);
		Entity::registerEntity(Painting::class, false, ['Painting', 'minecraft:painting']);
		Entity::registerEntity(PrimedTNT::class, false, ['PrimedTnt', 'PrimedTNT', 'minecraft:tnt']);
		Entity::registerEntity(Snowball::class, false, ['Snowball', 'minecraft:snowball']);
		Entity::registerEntity(SplashPotion::class, false, ['ThrownPotion', 'minecraft:potion', 'thrownpotion']);
		Entity::registerEntity(Squid::class, false, ['Squid', 'minecraft:squid']);
		Entity::registerEntity(Villager::class, false, ['Villager', 'minecraft:villager']);
		Entity::registerEntity(Zombie::class, false, ['Zombie', 'minecraft:zombie']);

		Entity::registerEntity(Human::class, true);

		Attribute::init();
		Effect::init();
		PaintingMotive::init();
	}

	/**
	 * Creates an entity with the specified type, level and NBT, with optional additional arguments to pass to the
	 * entity's constructor
	 *
	 * @param int|string  $type
	 * @param mixed       ...$args
	 */
	public static function createEntity($type, Level $level, CompoundTag $nbt, ...$args) : ?Entity{
		if(isset(self::$knownEntities[$type])){
			$class = self::$knownEntities[$type];
			/** @see Entity::__construct() */
			return new $class($level, $nbt, ...$args);
		}

		return null;
	}

	/**
	 * Registers an entity type into the index.
	 *
	 * @param string   $className Class that extends Entity
	 * @param bool     $force Force registration even if the entity does not have a valid network ID
	 * @param string[] $saveNames An array of save names which this entity might be saved under. Defaults to the short name of the class itself if empty.
	 * @phpstan-param class-string<Entity> $className
	 *
	 * NOTE: The first save name in the $saveNames array will be used when saving the entity to disk. The reflection
	 * name of the class will be appended to the end and only used if no other save names are specified.
	 */
	public static function registerEntity(string $className, bool $force = false, array $saveNames = []) : bool{
		$class = new \ReflectionClass($className);
		if(is_a($className, Entity::class, true) and !$class->isAbstract()){
			if($className::NETWORK_ID !== -1){
				self::$knownEntities[$className::NETWORK_ID] = $className;
			}elseif(!$force){
				return false;
			}

			$shortName = $class->getShortName();
			if(!in_array($shortName, $saveNames, true)){
				$saveNames[] = $shortName;
			}

			foreach($saveNames as $name){
				self::$knownEntities[$name] = $className;
			}

			self::$saveNames[$className] = $saveNames;

			return true;
		}

		return false;
	}

	/**
	 * Helper function which creates minimal NBT needed to spawn an entity.
	 */
	public static function createBaseNBT(Vector3 $pos, ?Vector3 $motion = null, float $yaw = 0.0, float $pitch = 0.0) : CompoundTag{
		return new CompoundTag("", [
			new ListTag("Pos", [
				new DoubleTag("", $pos->x),
				new DoubleTag("", $pos->y),
				new DoubleTag("", $pos->z)
			]),
			new ListTag("Motion", [
				new DoubleTag("", $motion !== null ? $motion->x : 0.0),
				new DoubleTag("", $motion !== null ? $motion->y : 0.0),
				new DoubleTag("", $motion !== null ? $motion->z : 0.0)
			]),
			new ListTag("Rotation", [
				new FloatTag("", $yaw),
				new FloatTag("", $pitch)
			])
		]);
	}

	/** @var Player[] */
	protected $hasSpawned = [];

	/** @var int */
	protected $id;

	/** @var DataPropertyManager */
	protected $propertyManager;

	/** @var Chunk|null */
	public $chunk;

	/** @var EntityDamageEvent|null */
	protected $lastDamageCause = null;

	/** @var Block[]|null */
	protected $blocksAround = null;

	/** @var float */
	public $lastX;
	/** @var float */
	public $lastY;
	/** @var float */
	public $lastZ;

	/** @var Vector3 */
	protected $motion;
	/** @var Vector3 */
	protected $lastMotion;
	/** @var bool */
	protected $forceMovementUpdate = false;

	/** @var Vector3 */
	public $temporalVector;

	/** @var float */
	public $lastYaw;
	/** @var float */
	public $lastPitch;

	/** @var AxisAlignedBB */
	public $boundingBox;
	/** @var bool */
	public $onGround;

	/** @var float */
	public $eyeHeight = null;

	/** @var float */
	public $height;
	/** @var float */
	public $width;

	/** @var float */
	protected $baseOffset = 0.0;

	/** @var float */
	private $health = 20.0;
	/** @var int */
	private $maxHealth = 20;

	/** @var float */
	protected $ySize = 0.0;
	/** @var float */
	protected $stepHeight = 0.0;
	/** @var bool */
	public $keepMovement = false;

	/** @var float */
	public $fallDistance = 0.0;
	/** @var int */
	public $ticksLived = 0;
	/** @var int */
	public $lastUpdate;
	/** @var int */
	protected $fireTicks = 0;
	/** @var CompoundTag */
	public $namedtag;
	/** @var bool */
	public $canCollide = true;

	/** @var bool */
	protected $isStatic = false;

	/** @var bool */
	private $savedWithChunk = true;

	/** @var bool */
	public $isCollided = false;
	/** @var bool */
	public $isCollidedHorizontally = false;
	/** @var bool */
	public $isCollidedVertically = false;

	/** @var int */
	public $noDamageTicks;
	/** @var bool */
	protected $justCreated = true;
	/** @var bool */
	private $invulnerable;

	/** @var AttributeMap */
	protected $attributeMap;

	/** @var float */
	protected $gravity;
	/** @var float */
	protected $drag;

	/** @var Server */
	protected $server;

	/** @var bool */
	protected $closed = false;
	/** @var bool */
	private $needsDespawn = false;

	/** @var TimingsHandler */
	protected $timings;

	/** @var bool */
	protected $constructed = false;

	/** @var bool */
	private $closeInFlight = false;

	public function __construct(Level $level, CompoundTag $nbt){
		$this->constructed = true;
		$this->timings = Timings::getEntityTimings($this);

		$this->temporalVector = new Vector3();

		if($this->eyeHeight === null){
			$this->eyeHeight = $this->height / 2 + 0.1;
		}

		$this->id = Entity::$entityCount++;
		$this->namedtag = $nbt;
		$this->server = $level->getServer();

		/** @var float[] $pos */
		$pos = $this->namedtag->getListTag("Pos")->getAllValues();
		/** @var float[] $rotation */
		$rotation = $this->namedtag->getListTag("Rotation")->getAllValues();

		parent::__construct($pos[0], $pos[1], $pos[2], $rotation[0], $rotation[1], $level);
		assert(!is_nan($this->x) and !is_infinite($this->x) and !is_nan($this->y) and !is_infinite($this->y) and !is_nan($this->z) and !is_infinite($this->z));

		$this->boundingBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0);
		$this->recalculateBoundingBox();

		$this->chunk = $this->level->getChunkAtPosition($this, false);
		if($this->chunk === null){
			throw new \InvalidStateException("Cannot create entities in unloaded chunks");
		}

		$this->motion = new Vector3(0, 0, 0);
		if($this->namedtag->hasTag("Motion", ListTag::class)){
			/** @var float[] $motion */
			$motion = $this->namedtag->getListTag("Motion")->getAllValues();
			$this->setMotion($this->temporalVector->setComponents(...$motion));
		}

		$this->resetLastMovements();

		$this->fallDistance = $this->namedtag->getFloat("FallDistance", 0.0);

		$this->propertyManager = new DataPropertyManager();

		$this->propertyManager->setLong(self::DATA_FLAGS, 0);
		$this->propertyManager->setShort(self::DATA_MAX_AIR, 400);
		$this->propertyManager->setString(self::DATA_NAMETAG, "");
		$this->propertyManager->setLong(self::DATA_LEAD_HOLDER_EID, -1);
		$this->propertyManager->setFloat(self::DATA_SCALE, 1);
		$this->propertyManager->setFloat(self::DATA_BOUNDING_BOX_WIDTH, $this->width);
		$this->propertyManager->setFloat(self::DATA_BOUNDING_BOX_HEIGHT, $this->height);

		$this->fireTicks = $this->namedtag->getShort("Fire", 0);
		if($this->isOnFire()){
			$this->setGenericFlag(self::DATA_FLAG_ONFIRE);
		}

		$this->propertyManager->setShort(self::DATA_AIR, $this->namedtag->getShort("Air", 300));
		$this->onGround = $this->namedtag->getByte("OnGround", 0) !== 0;
		$this->invulnerable = $this->namedtag->getByte("Invulnerable", 0) !== 0;

		$this->attributeMap = new AttributeMap();
		$this->addAttributes();

		$this->setGenericFlag(self::DATA_FLAG_AFFECTED_BY_GRAVITY, true);
		$this->setGenericFlag(self::DATA_FLAG_HAS_COLLISION, true);

		$this->initEntity();
		$this->propertyManager->clearDirtyProperties(); //Prevents resending properties that were set during construction

		$this->chunk->addEntity($this);
		$this->level->addEntity($this);

		$this->lastUpdate = $this->server->getTick();
		(new EntitySpawnEvent($this))->call();

		$this->scheduleUpdate();

	}

	public function getNameTag() : string{
		return $this->propertyManager->getString(self::DATA_NAMETAG);
	}

	public function isNameTagVisible() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_CAN_SHOW_NAMETAG);
	}

	public function isNameTagAlwaysVisible() : bool{
		return $this->propertyManager->getByte(self::DATA_ALWAYS_SHOW_NAMETAG) === 1;
	}

	public function setNameTag(string $name) : void{
		$this->propertyManager->setString(self::DATA_NAMETAG, $name);
	}

	public function setNameTagVisible(bool $value = true) : void{
		$this->setGenericFlag(self::DATA_FLAG_CAN_SHOW_NAMETAG, $value);
	}

	public function setNameTagAlwaysVisible(bool $value = true) : void{
		$this->propertyManager->setByte(self::DATA_ALWAYS_SHOW_NAMETAG, $value ? 1 : 0);
	}

	public function getScoreTag() : ?string{
		return $this->propertyManager->getString(self::DATA_SCORE_TAG);
	}

	public function setScoreTag(string $score) : void{
		$this->propertyManager->setString(self::DATA_SCORE_TAG, $score);
	}

	public function getScale() : float{
		return $this->propertyManager->getFloat(self::DATA_SCALE);
	}

	public function setScale(float $value) : void{
		if($value <= 0){
			throw new \InvalidArgumentException("Scale must be greater than 0");
		}
		$multiplier = $value / $this->getScale();

		$this->width *= $multiplier;
		$this->height *= $multiplier;
		$this->eyeHeight *= $multiplier;

		$this->recalculateBoundingBox();

		$this->propertyManager->setFloat(self::DATA_SCALE, $value);
	}

	public function getBoundingBox() : AxisAlignedBB{
		return $this->boundingBox;
	}

	protected function recalculateBoundingBox() : void{
		$halfWidth = $this->width / 2;

		$this->boundingBox->setBounds(
			$this->x - $halfWidth,
			$this->y,
			$this->z - $halfWidth,
			$this->x + $halfWidth,
			$this->y + $this->height,
			$this->z + $halfWidth
		);
	}

	public function isSneaking() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_SNEAKING);
	}

	public function setSneaking(bool $value = true) : void{
		$this->setGenericFlag(self::DATA_FLAG_SNEAKING, $value);
	}

	public function isSprinting() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_SPRINTING);
	}

	public function setSprinting(bool $value = true) : void{
		if($value !== $this->isSprinting()){
			$this->setGenericFlag(self::DATA_FLAG_SPRINTING, $value);
			$attr = $this->attributeMap->getAttribute(Attribute::MOVEMENT_SPEED);
			$attr->setValue($value ? ($attr->getValue() * 1.3) : ($attr->getValue() / 1.3), false, true);
		}
	}

	public function isImmobile() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_IMMOBILE);
	}

	public function setImmobile(bool $value = true) : void{
		$this->setGenericFlag(self::DATA_FLAG_IMMOBILE, $value);
	}

	public function isInvisible() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_INVISIBLE);
	}

	public function setInvisible(bool $value = true) : void{
		$this->setGenericFlag(self::DATA_FLAG_INVISIBLE, $value);
	}

	/**
	 * Returns whether the entity is able to climb blocks such as ladders or vines.
	 */
	public function canClimb() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_CAN_CLIMB);
	}

	/**
	 * Sets whether the entity is able to climb climbable blocks.
	 */
	public function setCanClimb(bool $value = true) : void{
		$this->setGenericFlag(self::DATA_FLAG_CAN_CLIMB, $value);
	}

	/**
	 * Returns whether this entity is climbing a block. By default this is only true if the entity is climbing a ladder or vine or similar block.
	 */
	public function canClimbWalls() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_WALLCLIMBING);
	}

	/**
	 * Sets whether the entity is climbing a block. If true, the entity can climb anything.
	 */
	public function setCanClimbWalls(bool $value = true) : void{
		$this->setGenericFlag(self::DATA_FLAG_WALLCLIMBING, $value);
	}

	/**
	 * Returns the entity ID of the owning entity, or null if the entity doesn't have an owner.
	 */
	public function getOwningEntityId() : ?int{
		return $this->propertyManager->getLong(self::DATA_OWNER_EID);
	}

	/**
	 * Returns the owning entity, or null if the entity was not found.
	 */
	public function getOwningEntity() : ?Entity{
		$eid = $this->getOwningEntityId();
		if($eid !== null){
			return $this->server->findEntity($eid);
		}

		return null;
	}

	/**
	 * Sets the owner of the entity. Passing null will remove the current owner.
	 *
	 * @throws \InvalidArgumentException if the supplied entity is not valid
	 */
	public function setOwningEntity(?Entity $owner) : void{
		if($owner === null){
			$this->propertyManager->removeProperty(self::DATA_OWNER_EID);
		}elseif($owner->closed){
			throw new \InvalidArgumentException("Supplied owning entity is garbage and cannot be used");
		}else{
			$this->propertyManager->setLong(self::DATA_OWNER_EID, $owner->getId());
		}
	}

	/**
	 * Returns the entity ID of the entity's target, or null if it doesn't have a target.
	 */
	public function getTargetEntityId() : ?int{
		return $this->propertyManager->getLong(self::DATA_TARGET_EID);
	}

	/**
	 * Returns the entity's target entity, or null if not found.
	 * This is used for things like hostile mobs attacking entities, and for fishing rods reeling hit entities in.
	 */
	public function getTargetEntity() : ?Entity{
		$eid = $this->getTargetEntityId();
		if($eid !== null){
			return $this->server->findEntity($eid);
		}

		return null;
	}

	/**
	 * Sets the entity's target entity. Passing null will remove the current target.
	 *
	 * @throws \InvalidArgumentException if the target entity is not valid
	 */
	public function setTargetEntity(?Entity $target) : void{
		if($target === null){
			$this->propertyManager->removeProperty(self::DATA_TARGET_EID);
		}elseif($target->closed){
			throw new \InvalidArgumentException("Supplied target entity is garbage and cannot be used");
		}else{
			$this->propertyManager->setLong(self::DATA_TARGET_EID, $target->getId());
		}
	}

	/**
	 * Returns whether this entity will be saved when its chunk is unloaded.
	 */
	public function canSaveWithChunk() : bool{
		return $this->savedWithChunk;
	}

	/**
	 * Sets whether this entity will be saved when its chunk is unloaded. This can be used to prevent the entity being
	 * saved to disk.
	 */
	public function setCanSaveWithChunk(bool $value) : void{
		$this->savedWithChunk = $value;
	}

	/**
	 * Returns the short save name
	 */
	public function getSaveId() : string{
		if(!isset(self::$saveNames[static::class])){
			throw new \InvalidStateException("Entity is not registered");
		}
		reset(self::$saveNames[static::class]);
		return current(self::$saveNames[static::class]);
	}

	public function saveNBT() : void{
		if(!($this instanceof Player)){
			$this->namedtag->setString("id", $this->getSaveId(), true);

			if($this->getNameTag() !== ""){
				$this->namedtag->setString("CustomName", $this->getNameTag());
				$this->namedtag->setByte("CustomNameVisible", $this->isNameTagVisible() ? 1 : 0);
			}else{
				$this->namedtag->removeTag("CustomName", "CustomNameVisible");
			}
		}

		$this->namedtag->setTag(new ListTag("Pos", [
			new DoubleTag("", $this->x),
			new DoubleTag("", $this->y),
			new DoubleTag("", $this->z)
		]));

		$this->namedtag->setTag(new ListTag("Motion", [
			new DoubleTag("", $this->motion->x),
			new DoubleTag("", $this->motion->y),
			new DoubleTag("", $this->motion->z)
		]));

		$this->namedtag->setTag(new ListTag("Rotation", [
			new FloatTag("", $this->yaw),
			new FloatTag("", $this->pitch)
		]));

		$this->namedtag->setFloat("FallDistance", $this->fallDistance);
		$this->namedtag->setShort("Fire", $this->fireTicks);
		$this->namedtag->setShort("Air", $this->propertyManager->getShort(self::DATA_AIR));
		$this->namedtag->setByte("OnGround", $this->onGround ? 1 : 0);
		$this->namedtag->setByte("Invulnerable", $this->invulnerable ? 1 : 0);
	}

	protected function initEntity() : void{
		if($this->namedtag->hasTag("CustomName", StringTag::class)){
			$this->setNameTag($this->namedtag->getString("CustomName"));

			if($this->namedtag->hasTag("CustomNameVisible", StringTag::class)){
				//Older versions incorrectly saved this as a string (see 890f72dbf23a77f294169b79590770470041adc4)
				$this->setNameTagVisible($this->namedtag->getString("CustomNameVisible") !== "");
				$this->namedtag->removeTag("CustomNameVisible");
			}else{
				$this->setNameTagVisible($this->namedtag->getByte("CustomNameVisible", 1) !== 0);
			}
		}
	}

	protected function addAttributes() : void{

	}

	public function attack(EntityDamageEvent $source) : void{
		$source->call();
		if($source->isCancelled()){
			return;
		}

		$this->setLastDamageCause($source);

		$this->setHealth($this->getHealth() - $source->getFinalDamage());
	}

	public function heal(EntityRegainHealthEvent $source) : void{
		$source->call();
		if($source->isCancelled()){
			return;
		}

		$this->setHealth($this->getHealth() + $source->getAmount());
	}

	public function kill() : void{
		$this->health = 0;
		$this->scheduleUpdate();
	}

	/**
	 * Called to tick entities while dead. Returns whether the entity should be flagged for despawn yet.
	 */
	protected function onDeathUpdate(int $tickDiff) : bool{
		return true;
	}

	public function isAlive() : bool{
		return $this->health > 0;
	}

	public function getHealth() : float{
		return $this->health;
	}

	/**
	 * Sets the health of the Entity. This won't send any update to the players
	 */
	public function setHealth(float $amount) : void{
		if($amount == $this->health){
			return;
		}

		if($amount <= 0){
			if($this->isAlive()){
				$this->health = 0;
				$this->kill();
			}
		}elseif($amount <= $this->getMaxHealth() or $amount < $this->health){
			$this->health = $amount;
		}else{
			$this->health = $this->getMaxHealth();
		}
	}

	public function getMaxHealth() : int{
		return $this->maxHealth;
	}

	public function setMaxHealth(int $amount) : void{
		$this->maxHealth = $amount;
	}

	public function setLastDamageCause(EntityDamageEvent $type) : void{
		$this->lastDamageCause = $type;
	}

	public function getLastDamageCause() : ?EntityDamageEvent{
		return $this->lastDamageCause;
	}

	public function getAttributeMap() : AttributeMap{
		return $this->attributeMap;
	}

	public function getDataPropertyManager() : DataPropertyManager{
		return $this->propertyManager;
	}

	public function entityBaseTick(int $tickDiff = 1) : bool{
		//TODO: check vehicles

		$this->justCreated = false;

		$changedProperties = $this->propertyManager->getDirty();
		if(count($changedProperties) > 0){
			$this->sendData($this->hasSpawned, $changedProperties);
			$this->propertyManager->clearDirtyProperties();
		}

		$hasUpdate = false;

		$this->checkBlockCollision();

		if($this->y <= -16 and $this->isAlive()){
			$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10);
			$this->attack($ev);
			$hasUpdate = true;
		}

		if($this->isOnFire() and $this->doOnFireTick($tickDiff)){
			$hasUpdate = true;
		}

		if($this->noDamageTicks > 0){
			$this->noDamageTicks -= $tickDiff;
			if($this->noDamageTicks < 0){
				$this->noDamageTicks = 0;
			}
		}

		$this->ticksLived += $tickDiff;

		return $hasUpdate;
	}

	public function isOnFire() : bool{
		return $this->fireTicks > 0;
	}

	public function setOnFire(int $seconds) : void{
		$ticks = $seconds * 20;
		if($ticks > $this->getFireTicks()){
			$this->setFireTicks($ticks);
		}

		$this->setGenericFlag(self::DATA_FLAG_ONFIRE, $this->isOnFire());
	}

	public function getFireTicks() : int{
		return $this->fireTicks;
	}

	/**
	 * @throws \InvalidArgumentException
	 */
	public function setFireTicks(int $fireTicks) : void{
		if($fireTicks < 0 or $fireTicks > 0x7fff){
			throw new \InvalidArgumentException("Fire ticks must be in range 0 ... " . 0x7fff . ", got $fireTicks");
		}
		$this->fireTicks = $fireTicks;
	}

	public function extinguish() : void{
		$this->fireTicks = 0;
		$this->setGenericFlag(self::DATA_FLAG_ONFIRE, false);
	}

	public function isFireProof() : bool{
		return false;
	}

	protected function doOnFireTick(int $tickDiff = 1) : bool{
		if($this->isFireProof() and $this->fireTicks > 1){
			$this->fireTicks = 1;
		}else{
			$this->fireTicks -= $tickDiff;
		}

		if(($this->fireTicks % 20 === 0) or $tickDiff > 20){
			$this->dealFireDamage();
		}

		if(!$this->isOnFire()){
			$this->extinguish();
		}else{
			return true;
		}

		return false;
	}

	/**
	 * Called to deal damage to entities when they are on fire.
	 */
	protected function dealFireDamage() : void{
		$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FIRE_TICK, 1);
		$this->attack($ev);
	}

	public function canCollideWith(Entity $entity) : bool{
		return !$this->justCreated and $entity !== $this;
	}

	public function canBeCollidedWith() : bool{
		return $this->isAlive();
	}

	protected function updateMovement(bool $teleport = false) : void{
		$diffPosition = ($this->x - $this->lastX) ** 2 + ($this->y - $this->lastY) ** 2 + ($this->z - $this->lastZ) ** 2;
		$diffRotation = ($this->yaw - $this->lastYaw) ** 2 + ($this->pitch - $this->lastPitch) ** 2;

		$diffMotion = $this->motion->subtract($this->lastMotion)->lengthSquared();

		$still = $this->motion->lengthSquared() == 0.0;
		$wasStill = $this->lastMotion->lengthSquared() == 0.0;
		if($wasStill !== $still){
			//TODO: hack for client-side AI interference: prevent client sided movement when motion is 0
			$this->setImmobile($still);
		}

		if($teleport or $diffPosition > 0.0001 or $diffRotation > 1.0 or (!$wasStill and $still)){
			$this->lastX = $this->x;
			$this->lastY = $this->y;
			$this->lastZ = $this->z;

			$this->lastYaw = $this->yaw;
			$this->lastPitch = $this->pitch;

			$this->broadcastMovement($teleport);
		}

		if($diffMotion > 0.0025 or $wasStill !== $still){ //0.05 ** 2
			$this->lastMotion = clone $this->motion;

			$this->broadcastMotion();
		}
	}

	public function getOffsetPosition(Vector3 $vector3) : Vector3{
		return new Vector3($vector3->x, $vector3->y + $this->baseOffset, $vector3->z);
	}

	protected function broadcastMovement(bool $teleport = false) : void{
		$pk = new MoveActorAbsolutePacket();
		$pk->entityRuntimeId = $this->id;
		$pk->position = $this->getOffsetPosition($this);

		//this looks very odd but is correct as of 1.5.0.7
		//for arrows this is actually x/y/z rotation
		//for mobs x and z are used for pitch and yaw, and y is used for headyaw
		$pk->xRot = $this->pitch;
		$pk->yRot = $this->yaw; //TODO: head yaw
		$pk->zRot = $this->yaw;

		if($teleport){
			$pk->flags |= MoveActorAbsolutePacket::FLAG_TELEPORT;
		}

		$this->level->broadcastPacketToViewers($this, $pk);
	}

	protected function broadcastMotion() : void{
		$pk = new SetActorMotionPacket();
		$pk->entityRuntimeId = $this->id;
		$pk->motion = $this->getMotion();

		$this->level->broadcastPacketToViewers($this, $pk);
	}

	protected function applyDragBeforeGravity() : bool{
		return false;
	}

	protected function applyGravity() : void{
		$this->motion->y -= $this->gravity;
	}

	protected function tryChangeMovement() : void{
		$friction = 1 - $this->drag;

		if($this->applyDragBeforeGravity()){
			$this->motion->y *= $friction;
		}

		$this->applyGravity();

		if(!$this->applyDragBeforeGravity()){
			$this->motion->y *= $friction;
		}

		if($this->onGround){
			$friction *= $this->level->getBlockAt((int) floor($this->x), (int) floor($this->y - 1), (int) floor($this->z))->getFrictionFactor();
		}

		$this->motion->x *= $friction;
		$this->motion->z *= $friction;
	}

	protected function checkObstruction(float $x, float $y, float $z) : bool{
		if(count($this->level->getCollisionCubes($this, $this->getBoundingBox(), false)) === 0){
			return false;
		}

		$floorX = (int) floor($x);
		$floorY = (int) floor($y);
		$floorZ = (int) floor($z);

		$diffX = $x - $floorX;
		$diffY = $y - $floorY;
		$diffZ = $z - $floorZ;

		if(BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY, $floorZ)]){
			$westNonSolid  = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX - 1, $floorY, $floorZ)];
			$eastNonSolid  = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX + 1, $floorY, $floorZ)];
			$downNonSolid  = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY - 1, $floorZ)];
			$upNonSolid    = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY + 1, $floorZ)];
			$northNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY, $floorZ - 1)];
			$southNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY, $floorZ + 1)];

			$direction = -1;
			$limit = 9999;

			if($westNonSolid){
				$limit = $diffX;
				$direction = Vector3::SIDE_WEST;
			}

			if($eastNonSolid and 1 - $diffX < $limit){
				$limit = 1 - $diffX;
				$direction = Vector3::SIDE_EAST;
			}

			if($downNonSolid and $diffY < $limit){
				$limit = $diffY;
				$direction = Vector3::SIDE_DOWN;
			}

			if($upNonSolid and 1 - $diffY < $limit){
				$limit = 1 - $diffY;
				$direction = Vector3::SIDE_UP;
			}

			if($northNonSolid and $diffZ < $limit){
				$limit = $diffZ;
				$direction = Vector3::SIDE_NORTH;
			}

			if($southNonSolid and 1 - $diffZ < $limit){
				$direction = Vector3::SIDE_SOUTH;
			}

			$force = lcg_value() * 0.2 + 0.1;

			if($direction === Vector3::SIDE_WEST){
				$this->motion->x = -$force;

				return true;
			}

			if($direction === Vector3::SIDE_EAST){
				$this->motion->x = $force;

				return true;
			}

			if($direction === Vector3::SIDE_DOWN){
				$this->motion->y = -$force;

				return true;
			}

			if($direction === Vector3::SIDE_UP){
				$this->motion->y = $force;

				return true;
			}

			if($direction === Vector3::SIDE_NORTH){
				$this->motion->z = -$force;

				return true;
			}

			if($direction === Vector3::SIDE_SOUTH){
				$this->motion->z = $force;

				return true;
			}
		}

		return false;
	}

	public function getDirection() : ?int{
		$rotation = ($this->yaw - 90) % 360;
		if($rotation < 0){
			$rotation += 360.0;
		}
		if((0 <= $rotation and $rotation < 45) or (315 <= $rotation and $rotation < 360)){
			return 2; //North
		}elseif(45 <= $rotation and $rotation < 135){
			return 3; //East
		}elseif(135 <= $rotation and $rotation < 225){
			return 0; //South
		}elseif(225 <= $rotation and $rotation < 315){
			return 1; //West
		}else{
			return null;
		}
	}

	public function getDirectionVector() : Vector3{
		$y = -sin(deg2rad($this->pitch));
		$xz = cos(deg2rad($this->pitch));
		$x = -$xz * sin(deg2rad($this->yaw));
		$z = $xz * cos(deg2rad($this->yaw));

		return $this->temporalVector->setComponents($x, $y, $z)->normalize();
	}

	public function getDirectionPlane() : Vector2{
		return (new Vector2(-cos(deg2rad($this->yaw) - M_PI_2), -sin(deg2rad($this->yaw) - M_PI_2)))->normalize();
	}

	public function onUpdate(int $currentTick) : bool{
		if($this->closed){
			return false;
		}

		$tickDiff = $currentTick - $this->lastUpdate;
		if($tickDiff <= 0){
			if(!$this->justCreated){
				$this->server->getLogger()->debug("Expected tick difference of at least 1, got $tickDiff for " . get_class($this));
			}

			return true;
		}

		$this->lastUpdate = $currentTick;

		if(!$this->isAlive()){
			if($this->onDeathUpdate($tickDiff)){
				$this->flagForDespawn();
			}

			return true;
		}

		$this->timings->startTiming();

		if($this->hasMovementUpdate()){
			$this->tryChangeMovement();

			if(abs($this->motion->x) <= self::MOTION_THRESHOLD){
				$this->motion->x = 0;
			}
			if(abs($this->motion->y) <= self::MOTION_THRESHOLD){
				$this->motion->y = 0;
			}
			if(abs($this->motion->z) <= self::MOTION_THRESHOLD){
				$this->motion->z = 0;
			}

			if($this->motion->x != 0 or $this->motion->y != 0 or $this->motion->z != 0){
				$this->move($this->motion->x, $this->motion->y, $this->motion->z);
			}

			$this->forceMovementUpdate = false;
		}

		$this->updateMovement();

		Timings::$timerEntityBaseTick->startTiming();
		$hasUpdate = $this->entityBaseTick($tickDiff);
		Timings::$timerEntityBaseTick->stopTiming();

		$this->timings->stopTiming();

		//if($this->isStatic())
		return ($hasUpdate or $this->hasMovementUpdate());
		//return !($this instanceof Player);
	}

	final public function scheduleUpdate() : void{
		if($this->closed){
			throw new \InvalidStateException("Cannot schedule update on garbage entity " . get_class($this));
		}
		$this->level->updateEntities[$this->id] = $this;
	}

	public function onNearbyBlockChange() : void{
		$this->setForceMovementUpdate();
		$this->scheduleUpdate();
	}

	/**
	 * Flags the entity as needing a movement update on the next tick. Setting this forces a movement update even if the
	 * entity's motion is zero. Used to trigger movement updates when blocks change near entities.
	 */
	final public function setForceMovementUpdate(bool $value = true) : void{
		$this->forceMovementUpdate = $value;

		$this->blocksAround = null;
	}

	/**
	 * Returns whether the entity needs a movement update on the next tick.
	 */
	public function hasMovementUpdate() : bool{
		return (
			$this->forceMovementUpdate or
			$this->motion->x != 0 or
			$this->motion->y != 0 or
			$this->motion->z != 0 or
			!$this->onGround
		);
	}

	public function canTriggerWalking() : bool{
		return true;
	}

	public function resetFallDistance() : void{
		$this->fallDistance = 0.0;
	}

	protected function updateFallState(float $distanceThisTick, bool $onGround) : void{
		if($onGround){
			if($this->fallDistance > 0){
				$this->fall($this->fallDistance);
				$this->resetFallDistance();
			}
		}elseif($distanceThisTick < 0){
			$this->fallDistance -= $distanceThisTick;
		}
	}

	/**
	 * Called when a falling entity hits the ground.
	 */
	public function fall(float $fallDistance) : void{

	}

	public function getEyeHeight() : float{
		return $this->eyeHeight;
	}

	public function onCollideWithPlayer(Player $player) : void{

	}

	public function isUnderwater() : bool{
		$block = $this->level->getBlockAt((int) floor($this->x), (int) floor($y = ($this->y + $this->getEyeHeight())), (int) floor($this->z));

		if($block instanceof Water){
			$f = ($block->y + 1) - ($block->getFluidHeightPercent() - 0.1111111);
			return $y < $f;
		}

		return false;
	}

	public function isInsideOfSolid() : bool{
		$block = $this->level->getBlockAt((int) floor($this->x), (int) floor($y = ($this->y + $this->getEyeHeight())), (int) floor($this->z));

		return $block->isSolid() and !$block->isTransparent() and $block->collidesWithBB($this->getBoundingBox());
	}

	public function fastMove(float $dx, float $dy, float $dz) : bool{
		$this->blocksAround = null;

		if($dx == 0 and $dz == 0 and $dy == 0){
			return true;
		}

		Timings::$entityMoveTimer->startTiming();

		$newBB = $this->boundingBox->offsetCopy($dx, $dy, $dz);

		$list = $this->level->getCollisionCubes($this, $newBB, false);

		if(count($list) === 0){
			$this->boundingBox = $newBB;
		}

		$this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2;
		$this->y = $this->boundingBox->minY - $this->ySize;
		$this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2;

		$this->checkChunks();

		if(!$this->onGround or $dy != 0){
			$bb = clone $this->boundingBox;
			$bb->minY -= 0.75;
			$this->onGround = false;

			if(count($this->level->getCollisionBlocks($bb)) > 0){
				$this->onGround = true;
			}
		}
		$this->isCollided = $this->onGround;
		$this->updateFallState($dy, $this->onGround);

		Timings::$entityMoveTimer->stopTiming();

		return true;
	}

	public function move(float $dx, float $dy, float $dz) : void{
		$this->blocksAround = null;

		Timings::$entityMoveTimer->startTiming();

		$movX = $dx;
		$movY = $dy;
		$movZ = $dz;

		if($this->keepMovement){
			$this->boundingBox->offset($dx, $dy, $dz);
		}else{
			$this->ySize *= 0.4;

			/*
			if($this->isColliding){ //With cobweb?
				$this->isColliding = false;
				$dx *= 0.25;
				$dy *= 0.05;
				$dz *= 0.25;
				$this->motionX = 0;
				$this->motionY = 0;
				$this->motionZ = 0;
			}
			*/

			$axisalignedbb = clone $this->boundingBox;

			/*$sneakFlag = $this->onGround and $this instanceof Player;

			if($sneakFlag){
				for($mov = 0.05; $dx != 0.0 and count($this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, -1, 0))) === 0; $movX = $dx){
					if($dx < $mov and $dx >= -$mov){
						$dx = 0;
					}elseif($dx > 0){
						$dx -= $mov;
					}else{
						$dx += $mov;
					}
				}

				for(; $dz != 0.0 and count($this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, -1, $dz))) === 0; $movZ = $dz){
					if($dz < $mov and $dz >= -$mov){
						$dz = 0;
					}elseif($dz > 0){
						$dz -= $mov;
					}else{
						$dz += $mov;
					}
				}

				//TODO: big messy loop
			}*/

			assert(abs($dx) <= 20 and abs($dy) <= 20 and abs($dz) <= 20, "Movement distance is excessive: dx=$dx, dy=$dy, dz=$dz");

			//TODO: bad hack here will cause unexpected behaviour under heavy lag
			$list = $this->level->getCollisionCubes($this, $this->level->getTickRateTime() > 50 ? $this->boundingBox->offsetCopy($dx, $dy, $dz) : $this->boundingBox->addCoord($dx, $dy, $dz), false);

			foreach($list as $bb){
				$dy = $bb->calculateYOffset($this->boundingBox, $dy);
			}

			$this->boundingBox->offset(0, $dy, 0);

			$fallingFlag = ($this->onGround or ($dy != $movY and $movY < 0));

			foreach($list as $bb){
				$dx = $bb->calculateXOffset($this->boundingBox, $dx);
			}

			$this->boundingBox->offset($dx, 0, 0);

			foreach($list as $bb){
				$dz = $bb->calculateZOffset($this->boundingBox, $dz);
			}

			$this->boundingBox->offset(0, 0, $dz);

			if($this->stepHeight > 0 and $fallingFlag and $this->ySize < 0.05 and ($movX != $dx or $movZ != $dz)){
				$cx = $dx;
				$cy = $dy;
				$cz = $dz;
				$dx = $movX;
				$dy = $this->stepHeight;
				$dz = $movZ;

				$axisalignedbb1 = clone $this->boundingBox;

				$this->boundingBox->setBB($axisalignedbb);

				$list = $this->level->getCollisionCubes($this, $this->boundingBox->addCoord($dx, $dy, $dz), false);

				foreach($list as $bb){
					$dy = $bb->calculateYOffset($this->boundingBox, $dy);
				}

				$this->boundingBox->offset(0, $dy, 0);

				foreach($list as $bb){
					$dx = $bb->calculateXOffset($this->boundingBox, $dx);
				}

				$this->boundingBox->offset($dx, 0, 0);

				foreach($list as $bb){
					$dz = $bb->calculateZOffset($this->boundingBox, $dz);
				}

				$this->boundingBox->offset(0, 0, $dz);

				if(($cx ** 2 + $cz ** 2) >= ($dx ** 2 + $dz ** 2)){
					$dx = $cx;
					$dy = $cy;
					$dz = $cz;
					$this->boundingBox->setBB($axisalignedbb1);
				}else{
					$this->ySize += 0.5; //FIXME: this should be the height of the block it walked up, not fixed 0.5
				}
			}
		}

		$this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2;
		$this->y = $this->boundingBox->minY - $this->ySize;
		$this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2;

		$this->checkChunks();
		$this->checkBlockCollision();
		$this->checkGroundState($movX, $movY, $movZ, $dx, $dy, $dz);
		$this->updateFallState($dy, $this->onGround);

		if($movX != $dx){
			$this->motion->x = 0;
		}

		if($movY != $dy){
			$this->motion->y = 0;
		}

		if($movZ != $dz){
			$this->motion->z = 0;
		}

		//TODO: vehicle collision events (first we need to spawn them!)

		Timings::$entityMoveTimer->stopTiming();
	}

	protected function checkGroundState(float $movX, float $movY, float $movZ, float $dx, float $dy, float $dz) : void{
		$this->isCollidedVertically = $movY != $dy;
		$this->isCollidedHorizontally = ($movX != $dx or $movZ != $dz);
		$this->isCollided = ($this->isCollidedHorizontally or $this->isCollidedVertically);
		$this->onGround = ($movY != $dy and $movY < 0);
	}

	/**
	 * @deprecated WARNING: Despite what its name implies, this function DOES NOT return all the blocks around the entity.
	 * Instead, it returns blocks which have reactions for an entity intersecting with them.
	 *
	 * @return Block[]
	 */
	public function getBlocksAround() : array{
		if($this->blocksAround === null){
			$inset = 0.001; //Offset against floating-point errors

			$minX = (int) floor($this->boundingBox->minX + $inset);
			$minY = (int) floor($this->boundingBox->minY + $inset);
			$minZ = (int) floor($this->boundingBox->minZ + $inset);
			$maxX = (int) floor($this->boundingBox->maxX - $inset);
			$maxY = (int) floor($this->boundingBox->maxY - $inset);
			$maxZ = (int) floor($this->boundingBox->maxZ - $inset);

			$this->blocksAround = [];

			for($z = $minZ; $z <= $maxZ; ++$z){
				for($x = $minX; $x <= $maxX; ++$x){
					for($y = $minY; $y <= $maxY; ++$y){
						$block = $this->level->getBlockAt($x, $y, $z);
						if($block->hasEntityCollision()){
							$this->blocksAround[] = $block;
						}
					}
				}
			}
		}

		return $this->blocksAround;
	}

	/**
	 * Returns whether this entity can be moved by currents in liquids.
	 */
	public function canBeMovedByCurrents() : bool{
		return true;
	}

	protected function checkBlockCollision() : void{
		$vector = $this->temporalVector->setComponents(0, 0, 0);

		foreach($this->getBlocksAround() as $block){
			$block->onEntityCollide($this);
			$block->addVelocityToEntity($this, $vector);
		}

		if($vector->lengthSquared() > 0){
			$vector = $vector->normalize();
			$d = 0.014;
			$this->motion->x += $vector->x * $d;
			$this->motion->y += $vector->y * $d;
			$this->motion->z += $vector->z * $d;
		}
	}

	public function getPosition() : Position{
		return $this->asPosition();
	}

	public function getLocation() : Location{
		return $this->asLocation();
	}

	public function setPosition(Vector3 $pos) : bool{
		if($this->closed){
			return false;
		}

		if($pos instanceof Position and $pos->level !== null and $pos->level !== $this->level){
			if(!$this->switchLevel($pos->getLevel())){
				return false;
			}
		}

		$this->x = $pos->x;
		$this->y = $pos->y;
		$this->z = $pos->z;

		$this->recalculateBoundingBox();

		$this->blocksAround = null;

		$this->checkChunks();

		return true;
	}

	public function setRotation(float $yaw, float $pitch) : void{
		$this->yaw = $yaw;
		$this->pitch = $pitch;
		$this->scheduleUpdate();
	}

	public function setPositionAndRotation(Vector3 $pos, float $yaw, float $pitch) : bool{
		if($this->setPosition($pos)){
			$this->setRotation($yaw, $pitch);

			return true;
		}

		return false;
	}

	protected function checkChunks() : void{
		$chunkX = $this->getFloorX() >> 4;
		$chunkZ = $this->getFloorZ() >> 4;
		if($this->chunk === null or ($this->chunk->getX() !== $chunkX or $this->chunk->getZ() !== $chunkZ)){
			if($this->chunk !== null){
				$this->chunk->removeEntity($this);
			}
			$this->chunk = $this->level->getChunk($chunkX, $chunkZ, true);

			if(!$this->justCreated){
				$newChunk = $this->level->getViewersForPosition($this);
				foreach($this->hasSpawned as $player){
					if(!isset($newChunk[$player->getLoaderId()])){
						$this->despawnFrom($player);
					}else{
						unset($newChunk[$player->getLoaderId()]);
					}
				}
				foreach($newChunk as $player){
					$this->spawnTo($player);
				}
			}

			if($this->chunk === null){
				return;
			}

			$this->chunk->addEntity($this);
		}
	}

	protected function resetLastMovements() : void{
		list($this->lastX, $this->lastY, $this->lastZ) = [$this->x, $this->y, $this->z];
		list($this->lastYaw, $this->lastPitch) = [$this->yaw, $this->pitch];
		$this->lastMotion = clone $this->motion;
	}

	public function getMotion() : Vector3{
		return clone $this->motion;
	}

	public function setMotion(Vector3 $motion) : bool{
		if(!$this->justCreated){
			$ev = new EntityMotionEvent($this, $motion);
			$ev->call();
			if($ev->isCancelled()){
				return false;
			}
		}

		$this->motion = clone $motion;

		if(!$this->justCreated){
			$this->updateMovement();
		}

		return true;
	}

	public function isOnGround() : bool{
		return $this->onGround;
	}

	/**
	 * @param Vector3|Position|Location $pos
	 */
	public function teleport(Vector3 $pos, ?float $yaw = null, ?float $pitch = null) : bool{
		if($pos instanceof Location){
			$yaw = $yaw ?? $pos->yaw;
			$pitch = $pitch ?? $pos->pitch;
		}
		$from = Position::fromObject($this, $this->level);
		$to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->level);
		$ev = new EntityTeleportEvent($this, $from, $to);
		$ev->call();
		if($ev->isCancelled()){
			return false;
		}
		$this->ySize = 0;
		$pos = $ev->getTo();

		$this->setMotion($this->temporalVector->setComponents(0, 0, 0));
		if($this->setPositionAndRotation($pos, $yaw ?? $this->yaw, $pitch ?? $this->pitch)){
			$this->resetFallDistance();
			$this->onGround = true;

			$this->updateMovement(true);

			return true;
		}

		return false;
	}

	protected function switchLevel(Level $targetLevel) : bool{
		if($this->closed){
			return false;
		}

		if($this->isValid()){
			$ev = new EntityLevelChangeEvent($this, $this->level, $targetLevel);
			$ev->call();
			if($ev->isCancelled()){
				return false;
			}

			$this->level->removeEntity($this);
			if($this->chunk !== null){
				$this->chunk->removeEntity($this);
			}
			$this->despawnFromAll();
		}

		$this->setLevel($targetLevel);
		$this->level->addEntity($this);
		$this->chunk = null;

		return true;
	}

	public function getId() : int{
		return $this->id;
	}

	/**
	 * @return Player[]
	 */
	public function getViewers() : array{
		return $this->hasSpawned;
	}

	/**
	 * Called by spawnTo() to send whatever packets needed to spawn the entity to the client.
	 */
	protected function sendSpawnPacket(Player $player) : void{
		$pk = new AddActorPacket();
		$pk->entityRuntimeId = $this->getId();
		$pk->type = static::NETWORK_ID;
		$pk->position = $this->asVector3();
		$pk->motion = $this->getMotion();
		$pk->yaw = $this->yaw;
		$pk->headYaw = $this->yaw; //TODO
		$pk->pitch = $this->pitch;
		$pk->attributes = $this->attributeMap->getAll();
		$pk->metadata = $this->propertyManager->getAll();

		$player->dataPacket($pk);
	}

	public function spawnTo(Player $player) : void{
		if(!isset($this->hasSpawned[$player->getLoaderId()]) and $this->chunk !== null and isset($player->usedChunks[((($this->chunk->getX()) & 0xFFFFFFFF) << 32) | (( $this->chunk->getZ()) & 0xFFFFFFFF)])){
			$this->hasSpawned[$player->getLoaderId()] = $player;

			$this->sendSpawnPacket($player);
		}
	}

	public function spawnToAll() : void{
		if($this->chunk === null or $this->closed){
			return;
		}
		foreach($this->level->getViewersForPosition($this) as $player){
			if($player->isOnline()){
				$this->spawnTo($player);
			}
		}
	}

	public function respawnToAll() : void{
		foreach($this->hasSpawned as $key => $player){
			unset($this->hasSpawned[$key]);
			$this->spawnTo($player);
		}
	}

	/**
	 * @deprecated WARNING: This function DOES NOT permanently hide the entity from the player. As soon as the entity or
	 * player moves, the player will once again be able to see the entity.
	 */
	public function despawnFrom(Player $player, bool $send = true) : void{
		if(isset($this->hasSpawned[$player->getLoaderId()])){
			if($send){
				$pk = new RemoveActorPacket();
				$pk->entityUniqueId = $this->id;
				$player->dataPacket($pk);
			}
			unset($this->hasSpawned[$player->getLoaderId()]);
		}
	}

	/**
	 * @deprecated WARNING: This function DOES NOT permanently hide the entity from viewers. As soon as the entity or
	 * player moves, viewers will once again be able to see the entity.
	 */
	public function despawnFromAll() : void{
		foreach($this->hasSpawned as $player){
			$this->despawnFrom($player);
		}
	}

	/**
	 * Flags the entity to be removed from the world on the next tick.
	 */
	public function flagForDespawn() : void{
		$this->needsDespawn = true;
		$this->scheduleUpdate();
	}

	public function isFlaggedForDespawn() : bool{
		return $this->needsDespawn;
	}

	/**
	 * Returns whether the entity has been "closed".
	 */
	public function isClosed() : bool{
		return $this->closed;
	}

	/**
	 * Closes the entity and frees attached references.
	 *
	 * WARNING: Entities are unusable after this has been executed!
	 */
	public function close() : void{
		if($this->closeInFlight){
			return;
		}

		if(!$this->closed){
			$this->closeInFlight = true;
			(new EntityDespawnEvent($this))->call();
			$this->closed = true;

			$this->despawnFromAll();
			$this->hasSpawned = [];

			if($this->chunk !== null){
				$this->chunk->removeEntity($this);
				$this->chunk = null;
			}

			if($this->isValid()){
				$this->level->removeEntity($this);
				$this->setLevel(null);
			}

			$this->namedtag = null;
			$this->lastDamageCause = null;
			$this->closeInFlight = false;
		}
	}

	public function setDataFlag(int $propertyId, int $flagId, bool $value = true, int $propertyType = self::DATA_TYPE_LONG) : void{
		if($this->getDataFlag($propertyId, $flagId) !== $value){
			$flags = (int) $this->propertyManager->getPropertyValue($propertyId, $propertyType);
			$flags ^= 1 << $flagId;
			$this->propertyManager->setPropertyValue($propertyId, $propertyType, $flags);
		}
	}

	public function getDataFlag(int $propertyId, int $flagId) : bool{
		return (((int) $this->propertyManager->getPropertyValue($propertyId, -1)) & (1 << $flagId)) > 0;
	}

	/**
	 * Wrapper around {@link Entity#getDataFlag} for generic data flag reading.
	 */
	public function getGenericFlag(int $flagId) : bool{
		return $this->getDataFlag($flagId >= 64 ? self::DATA_FLAGS2 : self::DATA_FLAGS, $flagId % 64);
	}

	/**
	 * Wrapper around {@link Entity#setDataFlag} for generic data flag setting.
	 */
	public function setGenericFlag(int $flagId, bool $value = true) : void{
		$this->setDataFlag($flagId >= 64 ? self::DATA_FLAGS2 : self::DATA_FLAGS, $flagId % 64, $value, self::DATA_TYPE_LONG);
	}

	/**
	 * @param Player[]|Player $player
	 * @param mixed[][]       $data Properly formatted entity data, defaults to everything
	 * @phpstan-param array<int, array{0: int, 1: mixed}> $data
	 */
	public function sendData($player, ?array $data = null) : void{
		if(!is_array($player)){
			$player = [$player];
		}

		$pk = new SetActorDataPacket();
		$pk->entityRuntimeId = $this->getId();
		$pk->metadata = $data ?? $this->propertyManager->getAll();

		foreach($player as $p){
			if($p === $this){
				continue;
			}
			$p->dataPacket(clone $pk);
		}

		if($this instanceof Player){
			$this->dataPacket($pk);
		}
	}

	/**
	 * @param Player[]|null $players
	 */
	public function broadcastEntityEvent(int $eventId, ?int $eventData = null, ?array $players = null) : void{
		$pk = new ActorEventPacket();
		$pk->entityRuntimeId = $this->id;
		$pk->event = $eventId;
		$pk->data = $eventData ?? 0;

		$this->server->broadcastPacket($players ?? $this->getViewers(), $pk);
	}

	public function __destruct(){
		$this->close();
	}

	public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
		$this->server->getEntityMetadata()->setMetadata($this, $metadataKey, $newMetadataValue);
	}

	public function getMetadata(string $metadataKey){
		return $this->server->getEntityMetadata()->getMetadata($this, $metadataKey);
	}

	public function hasMetadata(string $metadataKey) : bool{
		return $this->server->getEntityMetadata()->hasMetadata($this, $metadataKey);
	}

	public function removeMetadata(string $metadataKey, Plugin $owningPlugin){
		$this->server->getEntityMetadata()->removeMetadata($this, $metadataKey, $owningPlugin);
	}

	public function __toString(){
		return (new \ReflectionClass($this))->getShortName() . "(" . $this->getId() . ")";
	}

	/**
	 * TODO: remove this BC hack in 4.0
	 *
	 * @param string $name
	 *
	 * @return mixed
	 * @throws \ErrorException
	 */
	public function __get($name){
		if($name === "fireTicks"){
			return $this->fireTicks;
		}
		throw new \ErrorException("Undefined property: " . get_class($this) . "::\$" . $name);
	}

	/**
	 * TODO: remove this BC hack in 4.0
	 *
	 * @param string $name
	 * @param mixed $value
	 *
	 * @return void
	 * @throws \ErrorException
	 * @throws \InvalidArgumentException
	 */
	public function __set($name, $value){
		if($name === "fireTicks"){
			$this->setFireTicks($value);
		}else{
			throw new \ErrorException("Undefined property: " . get_class($this) . "::\$" . $name);
		}
	}

	/**
	 * TODO: remove this BC hack in 4.0
	 *
	 * @param string $name
	 *
	 * @return bool
	 */
	public function __isset($name){
		return $name === "fireTicks";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level;

use pocketmine\math\Vector3;

class Location extends Position{

	/** @var float */
	public $yaw;
	/** @var float */
	public $pitch;

	/**
	 * @param float|int $x
	 * @param float|int $y
	 * @param float|int $z
	 * @param float     $yaw
	 * @param float     $pitch
	 */
	public function __construct($x = 0, $y = 0, $z = 0, $yaw = 0.0, $pitch = 0.0, Level $level = null){
		$this->yaw = $yaw;
		$this->pitch = $pitch;
		parent::__construct($x, $y, $z, $level);
	}

	/**
	 * @param float      $yaw   default 0.0
	 * @param float      $pitch default 0.0
	 */
	public static function fromObject(Vector3 $pos, Level $level = null, $yaw = 0.0, $pitch = 0.0) : Location{
		return new Location($pos->x, $pos->y, $pos->z, $yaw, $pitch, $level ?? (($pos instanceof Position) ? $pos->level : null));
	}

	/**
	 * Return a Location instance
	 */
	public function asLocation() : Location{
		return new Location($this->x, $this->y, $this->z, $this->yaw, $this->pitch, $this->level);
	}

	/**
	 * @return float
	 */
	public function getYaw(){
		return $this->yaw;
	}

	/**
	 * @return float
	 */
	public function getPitch(){
		return $this->pitch;
	}

	public function __toString(){
		return "Location (level=" . ($this->isValid() ? $this->getLevel()->getName() : "null") . ", x=$this->x, y=$this->y, z=$this->z, yaw=$this->yaw, pitch=$this->pitch)";
	}

	public function equals(Vector3 $v) : bool{
		if($v instanceof Location){
			return parent::equals($v) and $v->yaw == $this->yaw and $v->pitch == $this->pitch;
		}
		return parent::equals($v);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level;

use pocketmine\math\Vector3;
use pocketmine\utils\MainLogger;
use function assert;

class Position extends Vector3{

	/** @var Level|null */
	public $level = null;

	/**
	 * @param float|int $x
	 * @param float|int $y
	 * @param float|int $z
	 */
	public function __construct($x = 0, $y = 0, $z = 0, Level $level = null){
		parent::__construct($x, $y, $z);
		$this->setLevel($level);
	}

	/**
	 * @return Position
	 */
	public static function fromObject(Vector3 $pos, Level $level = null){
		return new Position($pos->x, $pos->y, $pos->z, $level);
	}

	/**
	 * Return a Position instance
	 */
	public function asPosition() : Position{
		return new Position($this->x, $this->y, $this->z, $this->level);
	}

	/**
	 * Returns the target Level, or null if the target is not valid.
	 * If a reference exists to a Level which is closed, the reference will be destroyed and null will be returned.
	 *
	 * @return Level|null
	 */
	public function getLevel(){
		if($this->level !== null and $this->level->isClosed()){
			MainLogger::getLogger()->debug("Position was holding a reference to an unloaded world");
			$this->level = null;
		}

		return $this->level;
	}

	/**
	 * Sets the target Level of the position.
	 *
	 * @return $this
	 *
	 * @throws \InvalidArgumentException if the specified Level has been closed
	 */
	public function setLevel(Level $level = null){
		if($level !== null and $level->isClosed()){
			throw new \InvalidArgumentException("Specified world has been unloaded and cannot be used");
		}

		$this->level = $level;
		return $this;
	}

	/**
	 * Checks if this object has a valid reference to a loaded Level
	 */
	public function isValid() : bool{
		if($this->level !== null and $this->level->isClosed()){
			$this->level = null;

			return false;
		}

		return $this->level !== null;
	}

	/**
	 * Returns a side Vector
	 *
	 * @return Position
	 */
	public function getSide(int $side, int $step = 1){
		assert($this->isValid());

		return Position::fromObject(parent::getSide($side, $step), $this->level);
	}

	public function __toString(){
		return "Position(level=" . ($this->isValid() ? $this->getLevel()->getName() : "null") . ",x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")";
	}

	public function equals(Vector3 $v) : bool{
		if($v instanceof Position){
			return parent::equals($v) and $v->getLevel() === $this->getLevel();
		}
		return parent::equals($v);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\math;

use function abs;
use function ceil;
use function floor;
use function max;
use function round;
use function sqrt;
use const PHP_ROUND_HALF_UP;

class Vector3{

	public const SIDE_DOWN = 0;
	public const SIDE_UP = 1;
	public const SIDE_NORTH = 2;
	public const SIDE_SOUTH = 3;
	public const SIDE_WEST = 4;
	public const SIDE_EAST = 5;

	/** @var float|int */
	public $x;
	/** @var float|int */
	public $y;
	/** @var float|int */
	public $z;

	/**
	 * WARNING: THIS IS NOT TYPE SAFE!
	 * This is intentionally not typehinted because things using this as an int-vector will crash and burn if everything
	 * gets converted to floating-point numbers.
	 *
	 * TODO: typehint this once int-vectors and float-vectors are separated
	 *
	 * @param float|int $x
	 * @param float|int $y
	 * @param float|int $z
	 */
	public function __construct($x = 0, $y = 0, $z = 0){
		$this->x = $x;
		$this->y = $y;
		$this->z = $z;
	}

	/**
	 * @return float|int
	 */
	public function getX(){
		return $this->x;
	}

	/**
	 * @return float|int
	 */
	public function getY(){
		return $this->y;
	}

	/**
	 * @return float|int
	 */
	public function getZ(){
		return $this->z;
	}

	public function getFloorX() : int{
		return (int) floor($this->x);
	}

	public function getFloorY() : int{
		return (int) floor($this->y);
	}

	public function getFloorZ() : int{
		return (int) floor($this->z);
	}

	/**
	 * @param Vector3|float $x
	 * @param float         $y
	 * @param float         $z
	 *
	 * @return Vector3
	 */
	public function add($x, $y = 0, $z = 0) : Vector3{
		if($x instanceof Vector3){
			return new Vector3($this->x + $x->x, $this->y + $x->y, $this->z + $x->z);
		}else{
			return new Vector3($this->x + $x, $this->y + $y, $this->z + $z);
		}
	}

	/**
	 * @param Vector3|float $x
	 * @param float         $y
	 * @param float         $z
	 *
	 * @return Vector3
	 */
	public function subtract($x, $y = 0, $z = 0) : Vector3{
		if($x instanceof Vector3){
			return $this->add(-$x->x, -$x->y, -$x->z);
		}else{
			return $this->add(-$x, -$y, -$z);
		}
	}

	public function multiply(float $number) : Vector3{
		return new Vector3($this->x * $number, $this->y * $number, $this->z * $number);
	}

	public function divide(float $number) : Vector3{
		return new Vector3($this->x / $number, $this->y / $number, $this->z / $number);
	}

	public function ceil() : Vector3{
		return new Vector3((int) ceil($this->x), (int) ceil($this->y), (int) ceil($this->z));
	}

	public function floor() : Vector3{
		return new Vector3((int) floor($this->x), (int) floor($this->y), (int) floor($this->z));
	}

	public function round(int $precision = 0, int $mode = PHP_ROUND_HALF_UP) : Vector3{
		return $precision > 0 ?
			new Vector3(round($this->x, $precision, $mode), round($this->y, $precision, $mode), round($this->z, $precision, $mode)) :
			new Vector3((int) round($this->x, $precision, $mode), (int) round($this->y, $precision, $mode), (int) round($this->z, $precision, $mode));
	}

	public function abs() : Vector3{
		return new Vector3(abs($this->x), abs($this->y), abs($this->z));
	}

	/**
	 * @param int $side
	 * @param int $step
	 *
	 * @return Vector3
	 */
	public function getSide(int $side, int $step = 1){
		switch($side){
			case Vector3::SIDE_DOWN:
				return new Vector3($this->x, $this->y - $step, $this->z);
			case Vector3::SIDE_UP:
				return new Vector3($this->x, $this->y + $step, $this->z);
			case Vector3::SIDE_NORTH:
				return new Vector3($this->x, $this->y, $this->z - $step);
			case Vector3::SIDE_SOUTH:
				return new Vector3($this->x, $this->y, $this->z + $step);
			case Vector3::SIDE_WEST:
				return new Vector3($this->x - $step, $this->y, $this->z);
			case Vector3::SIDE_EAST:
				return new Vector3($this->x + $step, $this->y, $this->z);
			default:
				return $this;
		}
	}

	/**
	 * @param int $step
	 *
	 * @return Vector3
	 */
	public function down(int $step = 1){
		return $this->getSide(self::SIDE_DOWN, $step);
	}

	/**
	 * @param int $step
	 *
	 * @return Vector3
	 */
	public function up(int $step = 1){
		return $this->getSide(self::SIDE_UP, $step);
	}

	/**
	 * @param int $step
	 *
	 * @return Vector3
	 */
	public function north(int $step = 1){
		return $this->getSide(self::SIDE_NORTH, $step);
	}

	/**
	 * @param int $step
	 *
	 * @return Vector3
	 */
	public function south(int $step = 1){
		return $this->getSide(self::SIDE_SOUTH, $step);
	}

	/**
	 * @param int $step
	 *
	 * @return Vector3
	 */
	public function west(int $step = 1){
		return $this->getSide(self::SIDE_WEST, $step);
	}

	/**
	 * @param int $step
	 *
	 * @return Vector3
	 */
	public function east(int $step = 1){
		return $this->getSide(self::SIDE_EAST, $step);
	}

	/**
	 * Return a Vector3 instance
	 *
	 * @return Vector3
	 */
	public function asVector3() : Vector3{
		return new Vector3($this->x, $this->y, $this->z);
	}

	/**
	 * Returns the Vector3 side number opposite the specified one
	 *
	 * @param int $side 0-5 one of the Vector3::SIDE_* constants
	 * @return int
	 *
	 * @throws \InvalidArgumentException if an invalid side is supplied
	 */
	public static function getOppositeSide(int $side) : int{
		if($side >= 0 and $side <= 5){
			return $side ^ 0x01;
		}

		throw new \InvalidArgumentException("Invalid side $side given to getOppositeSide");
	}

	public function distance(Vector3 $pos) : float{
		return sqrt($this->distanceSquared($pos));
	}

	public function distanceSquared(Vector3 $pos) : float{
		return (($this->x - $pos->x) ** 2) + (($this->y - $pos->y) ** 2) + (($this->z - $pos->z) ** 2);
	}

	/**
	 * @param Vector3|Vector2|float $x
	 * @param float                 $z
	 */
	public function maxPlainDistance($x, $z = 0) : float{
		if($x instanceof Vector3){
			return $this->maxPlainDistance($x->x, $x->z);
		}elseif($x instanceof Vector2){
			return $this->maxPlainDistance($x->x, $x->y);
		}else{
			return max(abs($this->x - $x), abs($this->z - $z));
		}
	}

	public function length() : float{
		return sqrt($this->lengthSquared());
	}

	public function lengthSquared() : float{
		return $this->x * $this->x + $this->y * $this->y + $this->z * $this->z;
	}

	/**
	 * @return Vector3
	 */
	public function normalize() : Vector3{
		$len = $this->lengthSquared();
		if($len > 0){
			return $this->divide(sqrt($len));
		}

		return new Vector3(0, 0, 0);
	}

	public function dot(Vector3 $v) : float{
		return $this->x * $v->x + $this->y * $v->y + $this->z * $v->z;
	}

	public function cross(Vector3 $v) : Vector3{
		return new Vector3(
			$this->y * $v->z - $this->z * $v->y,
			$this->z * $v->x - $this->x * $v->z,
			$this->x * $v->y - $this->y * $v->x
		);
	}

	public function equals(Vector3 $v) : bool{
		return $this->x == $v->x and $this->y == $v->y and $this->z == $v->z;
	}

	/**
	 * Returns a new vector with x value equal to the second parameter, along the line between this vector and the
	 * passed in vector, or null if not possible.
	 *
	 * @param Vector3 $v
	 * @param float   $x
	 *
	 * @return Vector3|null
	 */
	public function getIntermediateWithXValue(Vector3 $v, float $x) : ?Vector3{
		$xDiff = $v->x - $this->x;
		$yDiff = $v->y - $this->y;
		$zDiff = $v->z - $this->z;

		if(($xDiff * $xDiff) < 0.0000001){
			return null;
		}

		$f = ($x - $this->x) / $xDiff;

		if($f < 0 or $f > 1){
			return null;
		}else{
			return new Vector3($x, $this->y + $yDiff * $f, $this->z + $zDiff * $f);
		}
	}

	/**
	 * Returns a new vector with y value equal to the second parameter, along the line between this vector and the
	 * passed in vector, or null if not possible.
	 *
	 * @param Vector3 $v
	 * @param float   $y
	 *
	 * @return Vector3|null
	 */
	public function getIntermediateWithYValue(Vector3 $v, float $y) : ?Vector3{
		$xDiff = $v->x - $this->x;
		$yDiff = $v->y - $this->y;
		$zDiff = $v->z - $this->z;

		if(($yDiff * $yDiff) < 0.0000001){
			return null;
		}

		$f = ($y - $this->y) / $yDiff;

		if($f < 0 or $f > 1){
			return null;
		}else{
			return new Vector3($this->x + $xDiff * $f, $y, $this->z + $zDiff * $f);
		}
	}

	/**
	 * Returns a new vector with z value equal to the second parameter, along the line between this vector and the
	 * passed in vector, or null if not possible.
	 *
	 * @param Vector3 $v
	 * @param float   $z
	 *
	 * @return Vector3|null
	 */
	public function getIntermediateWithZValue(Vector3 $v, float $z) : ?Vector3{
		$xDiff = $v->x - $this->x;
		$yDiff = $v->y - $this->y;
		$zDiff = $v->z - $this->z;

		if(($zDiff * $zDiff) < 0.0000001){
			return null;
		}

		$f = ($z - $this->z) / $zDiff;

		if($f < 0 or $f > 1){
			return null;
		}else{
			return new Vector3($this->x + $xDiff * $f, $this->y + $yDiff * $f, $z);
		}
	}

	/**
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return $this
	 */
	public function setComponents($x, $y, $z){
		$this->x = $x;
		$this->y = $y;
		$this->z = $z;
		return $this;
	}

	public function __toString(){
		return "Vector3(x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")";
	}

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\projectile;

use pocketmine\block\Block;
use pocketmine\entity\Entity;
use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\event\inventory\InventoryPickupArrowEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\math\RayTraceResult;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\Player;
use function mt_rand;
use function sqrt;

class Arrow extends Projectile{
	public const NETWORK_ID = self::ARROW;

	public const PICKUP_NONE = 0;
	public const PICKUP_ANY = 1;
	public const PICKUP_CREATIVE = 2;

	private const TAG_PICKUP = "pickup"; //TAG_Byte

	public $width = 0.25;
	public $height = 0.25;

	protected $gravity = 0.05;
	protected $drag = 0.01;

	/** @var float */
	protected $damage = 2.0;

	/** @var int */
	protected $pickupMode = self::PICKUP_ANY;

	/** @var float */
	protected $punchKnockback = 0.0;

	/** @var int */
	protected $collideTicks = 0;

	public function __construct(Level $level, CompoundTag $nbt, ?Entity $shootingEntity = null, bool $critical = false){
		parent::__construct($level, $nbt, $shootingEntity);
		$this->setCritical($critical);
	}

	protected function initEntity() : void{
		parent::initEntity();

		$this->pickupMode = $this->namedtag->getByte(self::TAG_PICKUP, self::PICKUP_ANY, true);
		$this->collideTicks = $this->namedtag->getShort("life", $this->collideTicks);
	}

	public function saveNBT() : void{
		parent::saveNBT();

		$this->namedtag->setByte(self::TAG_PICKUP, $this->pickupMode, true);
		$this->namedtag->setShort("life", $this->collideTicks);
	}

	public function isCritical() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_CRITICAL);
	}

	public function setCritical(bool $value = true) : void{
		$this->setGenericFlag(self::DATA_FLAG_CRITICAL, $value);
	}

	public function getResultDamage() : int{
		$base = parent::getResultDamage();
		if($this->isCritical()){
			return ($base + mt_rand(0, (int) ($base / 2) + 1));
		}else{
			return $base;
		}
	}

	public function getPunchKnockback() : float{
		return $this->punchKnockback;
	}

	public function setPunchKnockback(float $punchKnockback) : void{
		$this->punchKnockback = $punchKnockback;
	}

	public function entityBaseTick(int $tickDiff = 1) : bool{
		if($this->closed){
			return false;
		}

		$hasUpdate = parent::entityBaseTick($tickDiff);

		if($this->blockHit !== null){
			$this->collideTicks += $tickDiff;
			if($this->collideTicks > 1200){
				$this->flagForDespawn();
				$hasUpdate = true;
			}
		}else{
			$this->collideTicks = 0;
		}

		return $hasUpdate;
	}

	protected function onHit(ProjectileHitEvent $event) : void{
		$this->setCritical(false);
		$this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_BOW_HIT);
	}

	protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{
		parent::onHitBlock($blockHit, $hitResult);
		$this->broadcastEntityEvent(ActorEventPacket::ARROW_SHAKE, 7); //7 ticks
	}

	protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : void{
		parent::onHitEntity($entityHit, $hitResult);
		if($this->punchKnockback > 0){
			$horizontalSpeed = sqrt($this->motion->x ** 2 + $this->motion->z ** 2);
			if($horizontalSpeed > 0){
				$multiplier = $this->punchKnockback * 0.6 / $horizontalSpeed;
				$entityHit->setMotion($entityHit->getMotion()->add($this->motion->x * $multiplier, 0.1, $this->motion->z * $multiplier));
			}
		}
	}

	public function getPickupMode() : int{
		return $this->pickupMode;
	}

	public function setPickupMode(int $pickupMode) : void{
		$this->pickupMode = $pickupMode;
	}

	public function onCollideWithPlayer(Player $player) : void{
		if($this->blockHit === null){
			return;
		}

		$item = ItemFactory::get(Item::ARROW, 0, 1);

		$playerInventory = $player->getInventory();
		if($player->isSurvival() and !$playerInventory->canAddItem($item)){
			return;
		}

		$ev = new InventoryPickupArrowEvent($playerInventory, $this);
		if($this->pickupMode === self::PICKUP_NONE or ($this->pickupMode === self::PICKUP_CREATIVE and !$player->isCreative())){
			$ev->setCancelled();
		}

		$ev->call();
		if($ev->isCancelled()){
			return;
		}

		$pk = new TakeItemActorPacket();
		$pk->eid = $player->getId();
		$pk->target = $this->getId();
		$this->server->broadcastPacket($this->getViewers(), $pk);

		$playerInventory->addItem(clone $item);
		$this->flagForDespawn();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\projectile;

use pocketmine\block\Block;
use pocketmine\entity\Entity;
use pocketmine\entity\Living;
use pocketmine\event\entity\EntityCombustByEntityEvent;
use pocketmine\event\entity\EntityDamageByChildEntityEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ProjectileHitBlockEvent;
use pocketmine\event\entity\ProjectileHitEntityEvent;
use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\level\Level;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\math\VoxelRayTrace;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\timings\Timings;
use function assert;
use function atan2;
use function ceil;
use function sqrt;
use const M_PI;
use const PHP_INT_MAX;

abstract class Projectile extends Entity{

	/** @var float */
	protected $damage = 0.0;

	/** @var Vector3|null */
	protected $blockHit;
	/** @var int|null */
	protected $blockHitId;
	/** @var int|null */
	protected $blockHitData;

	public function __construct(Level $level, CompoundTag $nbt, ?Entity $shootingEntity = null){
		parent::__construct($level, $nbt);
		if($shootingEntity !== null){
			$this->setOwningEntity($shootingEntity);
		}
	}

	public function attack(EntityDamageEvent $source) : void{
		if($source->getCause() === EntityDamageEvent::CAUSE_VOID){
			parent::attack($source);
		}
	}

	protected function initEntity() : void{
		parent::initEntity();

		$this->setMaxHealth(1);
		$this->setHealth(1);
		$this->damage = $this->namedtag->getDouble("damage", $this->damage);

		do{
			$blockHit = null;
			$blockId = null;
			$blockData = null;

			if($this->namedtag->hasTag("tileX", IntTag::class) and $this->namedtag->hasTag("tileY", IntTag::class) and $this->namedtag->hasTag("tileZ", IntTag::class)){
				$blockHit = new Vector3($this->namedtag->getInt("tileX"), $this->namedtag->getInt("tileY"), $this->namedtag->getInt("tileZ"));
			}else{
				break;
			}

			if($this->namedtag->hasTag("blockId", IntTag::class)){
				$blockId = $this->namedtag->getInt("blockId");
			}else{
				break;
			}

			if($this->namedtag->hasTag("blockData", ByteTag::class)){
				$blockData = $this->namedtag->getByte("blockData");
			}else{
				break;
			}

			$this->blockHit = $blockHit;
			$this->blockHitId = $blockId;
			$this->blockHitData = $blockData;
		}while(false);
	}

	public function canCollideWith(Entity $entity) : bool{
		return $entity instanceof Living and !$this->onGround;
	}

	public function canBeCollidedWith() : bool{
		return false;
	}

	/**
	 * Returns the base damage applied on collision. This is multiplied by the projectile's speed to give a result
	 * damage.
	 */
	public function getBaseDamage() : float{
		return $this->damage;
	}

	/**
	 * Sets the base amount of damage applied by the projectile.
	 */
	public function setBaseDamage(float $damage) : void{
		$this->damage = $damage;
	}

	/**
	 * Returns the amount of damage this projectile will deal to the entity it hits.
	 */
	public function getResultDamage() : int{
		return (int) ceil($this->motion->length() * $this->damage);
	}

	public function saveNBT() : void{
		parent::saveNBT();

		$this->namedtag->setDouble("damage", $this->damage);

		if($this->blockHit !== null){
			$this->namedtag->setInt("tileX", $this->blockHit->x);
			$this->namedtag->setInt("tileY", $this->blockHit->y);
			$this->namedtag->setInt("tileZ", $this->blockHit->z);

			//we intentionally use different ones to PC because we don't have stringy IDs
			$this->namedtag->setInt("blockId", $this->blockHitId);
			$this->namedtag->setByte("blockData", $this->blockHitData);
		}
	}

	protected function applyDragBeforeGravity() : bool{
		return true;
	}

	public function onNearbyBlockChange() : void{
		if($this->blockHit !== null){
			$blockIn = $this->level->getBlockAt($this->blockHit->x, $this->blockHit->y, $this->blockHit->z);
			if($blockIn->getId() !== $this->blockHitId or $blockIn->getDamage() !== $this->blockHitData){
				$this->blockHit = $this->blockHitId = $this->blockHitData = null;
			}
		}

		parent::onNearbyBlockChange();
	}

	public function hasMovementUpdate() : bool{
		return $this->blockHit === null and parent::hasMovementUpdate();
	}

	public function move(float $dx, float $dy, float $dz) : void{
		$this->blocksAround = null;

		Timings::$entityMoveTimer->startTiming();

		$start = $this->asVector3();
		$end = $start->add($this->motion);

		$blockHit = null;
		$entityHit = null;
		$hitResult = null;

		foreach(VoxelRayTrace::betweenPoints($start, $end) as $vector3){
			$block = $this->level->getBlockAt($vector3->x, $vector3->y, $vector3->z);

			$blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end);
			if($blockHitResult !== null){
				$end = $blockHitResult->hitVector;
				$blockHit = $block;
				$hitResult = $blockHitResult;
				break;
			}
		}

		$entityDistance = PHP_INT_MAX;

		$newDiff = $end->subtract($start);
		foreach($this->level->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){
			if($entity->getId() === $this->getOwningEntityId() and $this->ticksLived < 5){
				continue;
			}

			$entityBB = $entity->boundingBox->expandedCopy(0.3, 0.3, 0.3);
			$entityHitResult = $entityBB->calculateIntercept($start, $end);

			if($entityHitResult === null){
				continue;
			}

			$distance = $this->distanceSquared($entityHitResult->hitVector);

			if($distance < $entityDistance){
				$entityDistance = $distance;
				$entityHit = $entity;
				$hitResult = $entityHitResult;
				$end = $entityHitResult->hitVector;
			}
		}

		$this->x = $end->x;
		$this->y = $end->y;
		$this->z = $end->z;
		$this->recalculateBoundingBox();

		if($hitResult !== null){
			/** @var ProjectileHitEvent|null $ev */
			$ev = null;
			if($entityHit !== null){
				$ev = new ProjectileHitEntityEvent($this, $hitResult, $entityHit);
			}elseif($blockHit !== null){
				$ev = new ProjectileHitBlockEvent($this, $hitResult, $blockHit);
			}else{
				assert(false, "unknown hit type");
			}

			if($ev !== null){
				$ev->call();
				$this->onHit($ev);

				if($ev instanceof ProjectileHitEntityEvent){
					$this->onHitEntity($ev->getEntityHit(), $ev->getRayTraceResult());
				}elseif($ev instanceof ProjectileHitBlockEvent){
					$this->onHitBlock($ev->getBlockHit(), $ev->getRayTraceResult());
				}
			}

			$this->isCollided = $this->onGround = true;
			$this->motion->x = $this->motion->y = $this->motion->z = 0;
		}else{
			$this->isCollided = $this->onGround = false;
			$this->blockHit = $this->blockHitId = $this->blockHitData = null;

			//recompute angles...
			$f = sqrt(($this->motion->x ** 2) + ($this->motion->z ** 2));
			$this->yaw = (atan2($this->motion->x, $this->motion->z) * 180 / M_PI);
			$this->pitch = (atan2($this->motion->y, $f) * 180 / M_PI);
		}

		$this->checkChunks();
		$this->checkBlockCollision();

		Timings::$entityMoveTimer->stopTiming();
	}

	/**
	 * Called by move() when raytracing blocks to discover whether the block should be considered as a point of impact.
	 * This can be overridden by other projectiles to allow altering the blocks which are collided with (for example
	 * some projectiles collide with any non-air block).
	 *
	 * @return RayTraceResult|null the result of the ray trace if successful, or null if no interception is found.
	 */
	protected function calculateInterceptWithBlock(Block $block, Vector3 $start, Vector3 $end) : ?RayTraceResult{
		return $block->calculateIntercept($start, $end);
	}

	/**
	 * Called when the projectile hits something. Override this to perform non-target-specific effects when the
	 * projectile hits something.
	 */
	protected function onHit(ProjectileHitEvent $event) : void{

	}

	/**
	 * Called when the projectile collides with an Entity.
	 */
	protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : void{
		$damage = $this->getResultDamage();

		if($damage >= 0){
			if($this->getOwningEntity() === null){
				$ev = new EntityDamageByEntityEvent($this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
			}else{
				$ev = new EntityDamageByChildEntityEvent($this->getOwningEntity(), $this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
			}

			$entityHit->attack($ev);

			if($this->isOnFire()){
				$ev = new EntityCombustByEntityEvent($this, $entityHit, 5);
				$ev->call();
				if(!$ev->isCancelled()){
					$entityHit->setOnFire($ev->getDuration());
				}
			}
		}

		$this->flagForDespawn();
	}

	/**
	 * Called when the projectile collides with a Block.
	 */
	protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{
		$this->blockHit = $blockHit->asVector3();
		$this->blockHitId = $blockHit->getId();
		$this->blockHitData = $blockHit->getDamage();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\projectile;

use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\particle\ItemBreakParticle;

class Egg extends Throwable{
	public const NETWORK_ID = self::EGG;

	//TODO: spawn chickens on collision

	protected function onHit(ProjectileHitEvent $event) : void{
		for($i = 0; $i < 6; ++$i){
			$this->level->addParticle(new ItemBreakParticle($this, ItemFactory::get(Item::EGG)));
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\projectile;

use pocketmine\block\Block;
use pocketmine\math\RayTraceResult;

abstract class Throwable extends Projectile{

	public $width = 0.25;
	public $height = 0.25;

	protected $gravity = 0.03;
	protected $drag = 0.01;

	protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{
		parent::onHitBlock($blockHit, $hitResult);
		$this->flagForDespawn();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\projectile;

use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\level\sound\EndermanTeleportSound;
use pocketmine\network\mcpe\protocol\LevelEventPacket;

class EnderPearl extends Throwable{
	public const NETWORK_ID = self::ENDER_PEARL;

	protected function onHit(ProjectileHitEvent $event) : void{
		$owner = $this->getOwningEntity();
		if($owner !== null){
			//TODO: check end gateways (when they are added)
			//TODO: spawn endermites at origin

			$this->level->broadcastLevelEvent($owner, LevelEventPacket::EVENT_PARTICLE_ENDERMAN_TELEPORT);
			$this->level->addSound(new EndermanTeleportSound($owner));
			$owner->teleport($event->getRayTraceResult()->getHitVector());
			$this->level->addSound(new EndermanTeleportSound($owner));

			$owner->attack(new EntityDamageEvent($owner, EntityDamageEvent::CAUSE_FALL, 5));
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\projectile;

use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\utils\Color;
use function mt_rand;

class ExperienceBottle extends Throwable{
	public const NETWORK_ID = self::XP_BOTTLE;

	protected $gravity = 0.07;

	public function getResultDamage() : int{
		return -1;
	}

	public function onHit(ProjectileHitEvent $event) : void{
		$this->level->broadcastLevelEvent($this, LevelEventPacket::EVENT_PARTICLE_SPLASH, (new Color(0x38, 0x5d, 0xc6))->toARGB());
		$this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_GLASS);

		$this->level->dropExperience($this, mt_rand(3, 11));
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\object;

use pocketmine\entity\Entity;
use pocketmine\entity\Human;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\Player;
use function sqrt;

class ExperienceOrb extends Entity{
	public const NETWORK_ID = self::XP_ORB;

	public const TAG_VALUE_PC = "Value"; //short
	public const TAG_VALUE_PE = "experience value"; //int (WTF?)

	/**
	 * Max distance an orb will follow a player across.
	 */
	public const MAX_TARGET_DISTANCE = 8.0;

	/**
	 * Split sizes used for dropping experience orbs.
	 */
	public const ORB_SPLIT_SIZES = [2477, 1237, 617, 307, 149, 73, 37, 17, 7, 3, 1]; //This is indexed biggest to smallest so that we can return as soon as we found the biggest value.

	/**
	 * Returns the largest size of normal XP orb that will be spawned for the specified amount of XP. Used to split XP
	 * up into multiple orbs when an amount of XP is dropped.
	 */
	public static function getMaxOrbSize(int $amount) : int{
		foreach(self::ORB_SPLIT_SIZES as $split){
			if($amount >= $split){
				return $split;
			}
		}

		return 1;
	}

	/**
	 * Splits the specified amount of XP into an array of acceptable XP orb sizes.
	 *
	 * @return int[]
	 */
	public static function splitIntoOrbSizes(int $amount) : array{
		$result = [];

		while($amount > 0){
			$size = self::getMaxOrbSize($amount);
			$result[] = $size;
			$amount -= $size;
		}

		return $result;
	}

	public $height = 0.25;
	public $width = 0.25;

	public $gravity = 0.04;
	public $drag = 0.02;

	/** @var int */
	protected $age = 0;

	/**
	 * @var int
	 * Ticker used for determining interval in which to look for new target players.
	 */
	protected $lookForTargetTime = 0;

	/**
	 * @var int|null
	 * Runtime entity ID of the player this XP orb is targeting.
	 */
	protected $targetPlayerRuntimeId = null;

	protected function initEntity() : void{
		parent::initEntity();

		$this->age = $this->namedtag->getShort("Age", 0);

		$value = 0;
		if($this->namedtag->hasTag(self::TAG_VALUE_PC, ShortTag::class)){ //PC
			$value = $this->namedtag->getShort(self::TAG_VALUE_PC);
		}elseif($this->namedtag->hasTag(self::TAG_VALUE_PE, IntTag::class)){ //PE save format
			$value = $this->namedtag->getInt(self::TAG_VALUE_PE);
		}

		$this->setXpValue($value);
	}

	public function saveNBT() : void{
		parent::saveNBT();

		$this->namedtag->setShort("Age", $this->age);

		$this->namedtag->setShort(self::TAG_VALUE_PC, $this->getXpValue());
		$this->namedtag->setInt(self::TAG_VALUE_PE, $this->getXpValue());
	}

	public function getXpValue() : int{
		return $this->propertyManager->getInt(self::DATA_EXPERIENCE_VALUE) ?? 0;
	}

	public function setXpValue(int $amount) : void{
		if($amount <= 0){
			throw new \InvalidArgumentException("XP amount must be greater than 0, got $amount");
		}
		$this->propertyManager->setInt(self::DATA_EXPERIENCE_VALUE, $amount);
	}

	public function hasTargetPlayer() : bool{
		return $this->targetPlayerRuntimeId !== null;
	}

	public function getTargetPlayer() : ?Human{
		if($this->targetPlayerRuntimeId === null){
			return null;
		}

		$entity = $this->level->getEntity($this->targetPlayerRuntimeId);
		if($entity instanceof Human){
			return $entity;
		}

		return null;
	}

	public function setTargetPlayer(?Human $player) : void{
		$this->targetPlayerRuntimeId = $player !== null ? $player->getId() : null;
	}

	public function entityBaseTick(int $tickDiff = 1) : bool{
		$hasUpdate = parent::entityBaseTick($tickDiff);

		$this->age += $tickDiff;
		if($this->age > 6000){
			$this->flagForDespawn();
			return true;
		}

		$currentTarget = $this->getTargetPlayer();
		if($currentTarget !== null and (!$currentTarget->isAlive() or $currentTarget->distanceSquared($this) > self::MAX_TARGET_DISTANCE ** 2)){
			$currentTarget = null;
		}

		if($this->lookForTargetTime >= 20){
			if($currentTarget === null){
				$newTarget = $this->level->getNearestEntity($this, self::MAX_TARGET_DISTANCE, Human::class);

				if($newTarget instanceof Human and !($newTarget instanceof Player and $newTarget->isSpectator())){
					$currentTarget = $newTarget;
				}
			}

			$this->lookForTargetTime = 0;
		}else{
			$this->lookForTargetTime += $tickDiff;
		}

		$this->setTargetPlayer($currentTarget);

		if($currentTarget !== null){
			$vector = $currentTarget->add(0, $currentTarget->getEyeHeight() / 2, 0)->subtract($this)->divide(self::MAX_TARGET_DISTANCE);

			$distance = $vector->lengthSquared();
			if($distance < 1){
				$diff = $vector->normalize()->multiply(0.2 * (1 - sqrt($distance)) ** 2);

				$this->motion->x += $diff->x;
				$this->motion->y += $diff->y;
				$this->motion->z += $diff->z;
			}

			if($currentTarget->canPickupXp() and $this->boundingBox->intersectsWith($currentTarget->getBoundingBox())){
				$this->flagForDespawn();

				$currentTarget->onPickupXp($this->getXpValue());
			}
		}

		return $hasUpdate;
	}

	protected function tryChangeMovement() : void{
		$this->checkObstruction($this->x, $this->y, $this->z);
		parent::tryChangeMovement();
	}

	public function canBeCollidedWith() : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\object;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\block\Fallable;
use pocketmine\entity\Entity;
use pocketmine\event\entity\EntityBlockChangeEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\ItemFactory;
use pocketmine\level\Position;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\IntTag;
use function abs;
use function get_class;

class FallingBlock extends Entity{
	public const NETWORK_ID = self::FALLING_BLOCK;

	public $width = 0.98;
	public $height = 0.98;

	protected $baseOffset = 0.49;

	protected $gravity = 0.04;
	protected $drag = 0.02;

	/** @var Block */
	protected $block;

	public $canCollide = false;

	protected function initEntity() : void{
		parent::initEntity();

		$blockId = 0;

		//TODO: 1.8+ save format
		if($this->namedtag->hasTag("TileID", IntTag::class)){
			$blockId = $this->namedtag->getInt("TileID");
		}elseif($this->namedtag->hasTag("Tile", ByteTag::class)){
			$blockId = $this->namedtag->getByte("Tile");
			$this->namedtag->removeTag("Tile");
		}

		if($blockId === 0){
			throw new \UnexpectedValueException("Invalid " . get_class($this) . " entity: block ID is 0 or missing");
		}

		$damage = $this->namedtag->getByte("Data", 0);

		$this->block = BlockFactory::get($blockId, $damage);

		$this->propertyManager->setInt(self::DATA_VARIANT, $this->block->getRuntimeId());
	}

	public function canCollideWith(Entity $entity) : bool{
		return false;
	}

	public function canBeMovedByCurrents() : bool{
		return false;
	}

	public function attack(EntityDamageEvent $source) : void{
		if($source->getCause() === EntityDamageEvent::CAUSE_VOID){
			parent::attack($source);
		}
	}

	public function entityBaseTick(int $tickDiff = 1) : bool{
		if($this->closed){
			return false;
		}

		$hasUpdate = parent::entityBaseTick($tickDiff);

		if(!$this->isFlaggedForDespawn()){
			$pos = Position::fromObject($this->add(-$this->width / 2, $this->height, -$this->width / 2)->floor(), $this->getLevel());

			$this->block->position($pos);

			$blockTarget = null;
			if($this->block instanceof Fallable){
				$blockTarget = $this->block->tickFalling();
			}

			if($this->onGround or $blockTarget !== null){
				$this->flagForDespawn();

				$block = $this->level->getBlock($pos);
				if(($block->isTransparent() and !$block->canBeReplaced()) or ($this->onGround and abs($this->y - $this->getFloorY()) > 0.001)){
					//FIXME: anvils are supposed to destroy torches
					$this->getLevel()->dropItem($this, ItemFactory::get($this->getBlock(), $this->getDamage()));
				}else{
					$ev = new EntityBlockChangeEvent($this, $block, $blockTarget ?? $this->block);
					$ev->call();
					if(!$ev->isCancelled()){
						$this->getLevel()->setBlock($pos, $ev->getTo(), true);
					}
				}
				$hasUpdate = true;
			}
		}

		return $hasUpdate;
	}

	public function getBlock() : int{
		return $this->block->getId();
	}

	public function getDamage() : int{
		return $this->block->getDamage();
	}

	public function saveNBT() : void{
		parent::saveNBT();
		$this->namedtag->setInt("TileID", $this->block->getId(), true);
		$this->namedtag->setByte("Data", $this->block->getDamage());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\object;

use pocketmine\entity\Entity;
use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent;
use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\Player;
use function get_class;

class ItemEntity extends Entity{
	public const NETWORK_ID = self::ITEM;

	/** @var string */
	protected $owner = "";
	/** @var string */
	protected $thrower = "";
	/** @var int */
	protected $pickupDelay = 0;
	/** @var Item */
	protected $item;

	public $width = 0.25;
	public $height = 0.25;
	protected $baseOffset = 0.125;

	protected $gravity = 0.04;
	protected $drag = 0.02;

	public $canCollide = false;

	/** @var int */
	protected $age = 0;

	protected function initEntity() : void{
		parent::initEntity();

		$this->setMaxHealth(5);
		$this->setHealth($this->namedtag->getShort("Health", (int) $this->getHealth()));
		$this->age = $this->namedtag->getShort("Age", $this->age);
		$this->pickupDelay = $this->namedtag->getShort("PickupDelay", $this->pickupDelay);
		$this->owner = $this->namedtag->getString("Owner", $this->owner);
		$this->thrower = $this->namedtag->getString("Thrower", $this->thrower);

		$itemTag = $this->namedtag->getCompoundTag("Item");
		if($itemTag === null){
			throw new \UnexpectedValueException("Invalid " . get_class($this) . " entity: expected \"Item\" NBT tag not found");
		}

		$this->item = Item::nbtDeserialize($itemTag);
		if($this->item->isNull()){
			throw new \UnexpectedValueException("Item for " . get_class($this) . " is invalid");
		}

		(new ItemSpawnEvent($this))->call();
	}

	public function entityBaseTick(int $tickDiff = 1) : bool{
		if($this->closed){
			return false;
		}

		$hasUpdate = parent::entityBaseTick($tickDiff);

		if(!$this->isFlaggedForDespawn() and $this->pickupDelay > -1 and $this->pickupDelay < 32767){ //Infinite delay
			$this->pickupDelay -= $tickDiff;
			if($this->pickupDelay < 0){
				$this->pickupDelay = 0;
			}

			$this->age += $tickDiff;
			if($this->age > 6000){
				$ev = new ItemDespawnEvent($this);
				$ev->call();
				if($ev->isCancelled()){
					$this->age = 0;
				}else{
					$this->flagForDespawn();
					$hasUpdate = true;
				}
			}
		}

		return $hasUpdate;
	}

	protected function tryChangeMovement() : void{
		$this->checkObstruction($this->x, $this->y, $this->z);
		parent::tryChangeMovement();
	}

	protected function applyDragBeforeGravity() : bool{
		return true;
	}

	public function saveNBT() : void{
		parent::saveNBT();
		$this->namedtag->setTag($this->item->nbtSerialize(-1, "Item"));
		$this->namedtag->setShort("Health", (int) $this->getHealth());
		$this->namedtag->setShort("Age", $this->age);
		$this->namedtag->setShort("PickupDelay", $this->pickupDelay);
		if($this->owner !== null){
			$this->namedtag->setString("Owner", $this->owner);
		}
		if($this->thrower !== null){
			$this->namedtag->setString("Thrower", $this->thrower);
		}
	}

	public function getItem() : Item{
		return $this->item;
	}

	public function canCollideWith(Entity $entity) : bool{
		return false;
	}

	public function canBeCollidedWith() : bool{
		return false;
	}

	public function getPickupDelay() : int{
		return $this->pickupDelay;
	}

	public function setPickupDelay(int $delay) : void{
		$this->pickupDelay = $delay;
	}

	public function getOwner() : string{
		return $this->owner;
	}

	public function setOwner(string $owner) : void{
		$this->owner = $owner;
	}

	public function getThrower() : string{
		return $this->thrower;
	}

	public function setThrower(string $thrower) : void{
		$this->thrower = $thrower;
	}

	protected function sendSpawnPacket(Player $player) : void{
		$pk = new AddItemActorPacket();
		$pk->entityRuntimeId = $this->getId();
		$pk->position = $this->asVector3();
		$pk->motion = $this->getMotion();
		$pk->item = $this->getItem();
		$pk->metadata = $this->propertyManager->getAll();

		$player->dataPacket($pk);
	}

	public function onCollideWithPlayer(Player $player) : void{
		if($this->getPickupDelay() !== 0){
			return;
		}

		$item = $this->getItem();
		$playerInventory = $player->getInventory();

		if($player->isSurvival() and !$playerInventory->canAddItem($item)){
			return;
		}

		$ev = new InventoryPickupItemEvent($playerInventory, $this);
		$ev->call();
		if($ev->isCancelled()){
			return;
		}

		switch($item->getId()){
			case Item::WOOD:
				$player->awardAchievement("mineWood");
				break;
			case Item::DIAMOND:
				$player->awardAchievement("diamond");
				break;
		}

		$pk = new TakeItemActorPacket();
		$pk->eid = $player->getId();
		$pk->target = $this->getId();
		$this->server->broadcastPacket($this->getViewers(), $pk);

		$playerInventory->addItem(clone $item);
		$this->flagForDespawn();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\object;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\entity\Entity;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\level\particle\DestroyBlockParticle;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\AddPaintingPacket;
use pocketmine\Player;
use function ceil;

class Painting extends Entity{
	public const NETWORK_ID = self::PAINTING;

	/** @var float */
	protected $gravity = 0.0;
	/** @var float */
	protected $drag = 1.0;

	//these aren't accurate, but it doesn't matter since they aren't used (vanilla PC does something similar)
	/** @var float */
	public $height = 0.5;
	/** @var float */
	public $width = 0.5;

	/** @var Vector3 */
	protected $blockIn;
	/** @var int */
	protected $direction = 0;
	/** @var string */
	protected $motive;

	public function __construct(Level $level, CompoundTag $nbt){
		$this->motive = $nbt->getString("Motive");
		$this->blockIn = new Vector3($nbt->getInt("TileX"), $nbt->getInt("TileY"), $nbt->getInt("TileZ"));
		if($nbt->hasTag("Direction", ByteTag::class)){
			$this->direction = $nbt->getByte("Direction");
		}elseif($nbt->hasTag("Facing", ByteTag::class)){
			$this->direction = $nbt->getByte("Facing");
		}
		parent::__construct($level, $nbt);
	}

	protected function initEntity() : void{
		$this->setMaxHealth(1);
		$this->setHealth(1);
		parent::initEntity();
	}

	public function saveNBT() : void{
		parent::saveNBT();
		$this->namedtag->setInt("TileX", (int) $this->blockIn->x);
		$this->namedtag->setInt("TileY", (int) $this->blockIn->y);
		$this->namedtag->setInt("TileZ", (int) $this->blockIn->z);

		$this->namedtag->setByte("Facing", $this->direction);
		$this->namedtag->setByte("Direction", $this->direction); //Save both for full compatibility

		$this->namedtag->setString("Motive", $this->motive);
	}

	public function kill() : void{
		if(!$this->isAlive()){
			return;
		}
		parent::kill();

		$drops = true;

		if($this->lastDamageCause instanceof EntityDamageByEntityEvent){
			$killer = $this->lastDamageCause->getDamager();
			if($killer instanceof Player and $killer->isCreative()){
				$drops = false;
			}
		}

		if($drops){
			//non-living entities don't have a way to create drops generically yet
			$this->level->dropItem($this, ItemFactory::get(Item::PAINTING));
		}
		$this->level->addParticle(new DestroyBlockParticle($this->add(0.5, 0.5, 0.5), BlockFactory::get(Block::PLANKS)));
	}

	protected function recalculateBoundingBox() : void{
		static $directions = [
			0 => Vector3::SIDE_SOUTH,
			1 => Vector3::SIDE_WEST,
			2 => Vector3::SIDE_NORTH,
			3 => Vector3::SIDE_EAST
		];

		$facing = $directions[$this->direction];

		$this->boundingBox->setBB(self::getPaintingBB($this->blockIn->getSide($facing), $facing, $this->getMotive()));
	}

	public function onNearbyBlockChange() : void{
		parent::onNearbyBlockChange();

		static $directions = [
			0 => Vector3::SIDE_SOUTH,
			1 => Vector3::SIDE_WEST,
			2 => Vector3::SIDE_NORTH,
			3 => Vector3::SIDE_EAST
		];

		$face = $directions[$this->direction];
		if(!self::canFit($this->level, $this->blockIn->getSide($face), $face, false, $this->getMotive())){
			$this->kill();
		}
	}

	public function hasMovementUpdate() : bool{
		return false;
	}

	protected function updateMovement(bool $teleport = false) : void{

	}

	public function canBeCollidedWith() : bool{
		return false;
	}

	protected function sendSpawnPacket(Player $player) : void{
		$pk = new AddPaintingPacket();
		$pk->entityRuntimeId = $this->getId();
		$pk->position = new Vector3(
			($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
			($this->boundingBox->minY + $this->boundingBox->maxY) / 2,
			($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2
		);
		$pk->direction = $this->direction;
		$pk->title = $this->motive;

		$player->dataPacket($pk);
	}

	/**
	 * Returns the painting motive (which image is displayed on the painting)
	 */
	public function getMotive() : PaintingMotive{
		return PaintingMotive::getMotiveByName($this->motive);
	}

	public function getDirection() : ?int{
		return $this->direction;
	}

	/**
	 * Returns the bounding-box a painting with the specified motive would have at the given position and direction.
	 */
	private static function getPaintingBB(Vector3 $blockIn, int $facing, PaintingMotive $motive) : AxisAlignedBB{
		$width = $motive->getWidth();
		$height = $motive->getHeight();

		$horizontalStart = (int) (ceil($width / 2) - 1);
		$verticalStart = (int) (ceil($height / 2) - 1);

		$thickness = 1 / 16;

		$minX = $maxX = 0;
		$minZ = $maxZ = 0;

		$minY = -$verticalStart;
		$maxY = $minY + $height;

		switch($facing){
			case Vector3::SIDE_NORTH:
				$minZ = 1 - $thickness;
				$maxZ = 1;
				$maxX = $horizontalStart + 1;
				$minX = $maxX - $width;
				break;
			case Vector3::SIDE_SOUTH:
				$minZ = 0;
				$maxZ = $thickness;
				$minX = -$horizontalStart;
				$maxX = $minX + $width;
				break;
			case Vector3::SIDE_WEST:
				$minX = 1 - $thickness;
				$maxX = 1;
				$minZ = -$horizontalStart;
				$maxZ = $minZ + $width;
				break;
			case Vector3::SIDE_EAST:
				$minX = 0;
				$maxX = $thickness;
				$maxZ = $horizontalStart + 1;
				$minZ = $maxZ - $width;
				break;
		}

		return new AxisAlignedBB(
			$blockIn->x + $minX,
			$blockIn->y + $minY,
			$blockIn->z + $minZ,
			$blockIn->x + $maxX,
			$blockIn->y + $maxY,
			$blockIn->z + $maxZ
		);
	}

	/**
	 * Returns whether a painting with the specified motive can be placed at the given position.
	 */
	public static function canFit(Level $level, Vector3 $blockIn, int $facing, bool $checkOverlap, PaintingMotive $motive) : bool{
		$width = $motive->getWidth();
		$height = $motive->getHeight();

		$horizontalStart = (int) (ceil($width / 2) - 1);
		$verticalStart = (int) (ceil($height / 2) - 1);

		switch($facing){
			case Vector3::SIDE_NORTH:
				$rotatedFace = Vector3::SIDE_WEST;
				break;
			case Vector3::SIDE_WEST:
				$rotatedFace = Vector3::SIDE_SOUTH;
				break;
			case Vector3::SIDE_SOUTH:
				$rotatedFace = Vector3::SIDE_EAST;
				break;
			case Vector3::SIDE_EAST:
				$rotatedFace = Vector3::SIDE_NORTH;
				break;
			default:
				return false;
		}

		$oppositeSide = Vector3::getOppositeSide($facing);

		$startPos = $blockIn->asVector3()->getSide(Vector3::getOppositeSide($rotatedFace), $horizontalStart)->getSide(Vector3::SIDE_DOWN, $verticalStart);

		for($w = 0; $w < $width; ++$w){
			for($h = 0; $h < $height; ++$h){
				$pos = $startPos->getSide($rotatedFace, $w)->getSide(Vector3::SIDE_UP, $h);

				$block = $level->getBlockAt($pos->x, $pos->y, $pos->z);
				if($block->isSolid() or !$block->getSide($oppositeSide)->isSolid()){
					return false;
				}
			}
		}

		if($checkOverlap){
			$bb = self::getPaintingBB($blockIn, $facing, $motive);

			foreach($level->getNearbyEntities($bb) as $entity){
				if($entity instanceof self){
					return false;
				}
			}
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\object;

use pocketmine\entity\Entity;
use pocketmine\entity\Explosive;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ExplosionPrimeEvent;
use pocketmine\level\Explosion;
use pocketmine\level\Position;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\network\mcpe\protocol\LevelEventPacket;

class PrimedTNT extends Entity implements Explosive{
	public const NETWORK_ID = self::TNT;

	public $width = 0.98;
	public $height = 0.98;

	protected $baseOffset = 0.49;

	protected $gravity = 0.04;
	protected $drag = 0.02;

	/** @var int */
	protected $fuse;

	public $canCollide = false;

	public function attack(EntityDamageEvent $source) : void{
		if($source->getCause() === EntityDamageEvent::CAUSE_VOID){
			parent::attack($source);
		}
	}

	protected function initEntity() : void{
		parent::initEntity();

		if($this->namedtag->hasTag("Fuse", ShortTag::class)){
			$this->fuse = $this->namedtag->getShort("Fuse");
		}else{
			$this->fuse = 80;
		}

		$this->setGenericFlag(self::DATA_FLAG_IGNITED, true);
		$this->propertyManager->setInt(self::DATA_FUSE_LENGTH, $this->fuse);

		$this->level->broadcastLevelEvent($this, LevelEventPacket::EVENT_SOUND_IGNITE);
	}

	public function canCollideWith(Entity $entity) : bool{
		return false;
	}

	public function saveNBT() : void{
		parent::saveNBT();
		$this->namedtag->setShort("Fuse", $this->fuse, true); //older versions incorrectly saved this as a byte
	}

	public function entityBaseTick(int $tickDiff = 1) : bool{
		if($this->closed){
			return false;
		}

		$hasUpdate = parent::entityBaseTick($tickDiff);

		if($this->fuse % 5 === 0){ //don't spam it every tick, it's not necessary
			$this->propertyManager->setInt(self::DATA_FUSE_LENGTH, $this->fuse);
		}

		if(!$this->isFlaggedForDespawn()){
			$this->fuse -= $tickDiff;

			if($this->fuse <= 0){
				$this->flagForDespawn();
				$this->explode();
			}
		}

		return $hasUpdate or $this->fuse >= 0;
	}

	public function explode() : void{
		$ev = new ExplosionPrimeEvent($this, 4);
		$ev->call();
		if(!$ev->isCancelled()){
			$explosion = new Explosion(Position::fromObject($this->add(0, $this->height / 2, 0), $this->level), $ev->getForce(), $this);
			if($ev->isBlockBreaking()){
				$explosion->explodeA();
			}
			$explosion->explodeB();
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

interface Explosive{

	/**
	 * @return void
	 */
	public function explode();
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\projectile;

use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\level\particle\SnowballPoofParticle;

class Snowball extends Throwable{
	public const NETWORK_ID = self::SNOWBALL;

	protected function onHit(ProjectileHitEvent $event) : void{
		for($i = 0; $i < 6; ++$i){
			$this->level->addParticle(new SnowballPoofParticle($this));
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\projectile;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\entity\EffectInstance;
use pocketmine\entity\Living;
use pocketmine\event\entity\ProjectileHitBlockEvent;
use pocketmine\event\entity\ProjectileHitEntityEvent;
use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\item\Potion;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\utils\Color;
use function count;
use function round;
use function sqrt;

class SplashPotion extends Throwable{

	public const NETWORK_ID = self::SPLASH_POTION;

	protected $gravity = 0.05;
	protected $drag = 0.01;

	protected function initEntity() : void{
		parent::initEntity();

		$this->setPotionId($this->namedtag->getShort("PotionId", 0));
	}

	public function saveNBT() : void{
		parent::saveNBT();
		$this->namedtag->setShort("PotionId", $this->getPotionId());
	}

	public function getResultDamage() : int{
		return -1; //no damage
	}

	protected function onHit(ProjectileHitEvent $event) : void{
		$effects = $this->getPotionEffects();
		$hasEffects = true;

		if(count($effects) === 0){
			$colors = [
				new Color(0x38, 0x5d, 0xc6) //Default colour for splash water bottle and similar with no effects.
			];
			$hasEffects = false;
		}else{
			$colors = [];
			foreach($effects as $effect){
				$level = $effect->getEffectLevel();
				for($j = 0; $j < $level; ++$j){
					$colors[] = $effect->getColor();
				}
			}
		}

		$this->level->broadcastLevelEvent($this, LevelEventPacket::EVENT_PARTICLE_SPLASH, Color::mix(...$colors)->toARGB());
		$this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_GLASS);

		if($hasEffects){
			if(!$this->willLinger()){
				foreach($this->level->getNearbyEntities($this->boundingBox->expandedCopy(4.125, 2.125, 4.125), $this) as $entity){
					if($entity instanceof Living and $entity->isAlive()){
						$distanceSquared = $entity->add(0, $entity->getEyeHeight(), 0)->distanceSquared($this);
						if($distanceSquared > 16){ //4 blocks
							continue;
						}

						$distanceMultiplier = 1 - (sqrt($distanceSquared) / 4);
						if($event instanceof ProjectileHitEntityEvent and $entity === $event->getEntityHit()){
							$distanceMultiplier = 1.0;
						}

						foreach($this->getPotionEffects() as $effect){
							//getPotionEffects() is used to get COPIES to avoid accidentally modifying the same effect instance already applied to another entity

							if(!$effect->getType()->isInstantEffect()){
								$newDuration = (int) round($effect->getDuration() * 0.75 * $distanceMultiplier);
								if($newDuration < 20){
									continue;
								}
								$effect->setDuration($newDuration);
								$entity->addEffect($effect);
							}else{
								$effect->getType()->applyEffect($entity, $effect, $distanceMultiplier, $this, $this->getOwningEntity());
							}
						}
					}
				}
			}else{
				//TODO: lingering potions
			}
		}elseif($event instanceof ProjectileHitBlockEvent and $this->getPotionId() === Potion::WATER){
			$blockIn = $event->getBlockHit()->getSide($event->getRayTraceResult()->getHitFace());

			if($blockIn->getId() === Block::FIRE){
				$this->level->setBlock($blockIn, BlockFactory::get(Block::AIR));
			}
			foreach($blockIn->getHorizontalSides() as $horizontalSide){
				if($horizontalSide->getId() === Block::FIRE){
					$this->level->setBlock($horizontalSide, BlockFactory::get(Block::AIR));
				}
			}
		}
	}

	/**
	 * Returns the meta value of the potion item that this splash potion corresponds to. This decides what effects will be applied to the entity when it collides with its target.
	 */
	public function getPotionId() : int{
		return $this->propertyManager->getShort(self::DATA_POTION_AUX_VALUE) ?? 0;
	}

	public function setPotionId(int $id) : void{
		$this->propertyManager->setShort(self::DATA_POTION_AUX_VALUE, $id);
	}

	/**
	 * Returns whether this splash potion will create an area-effect cloud when it lands.
	 */
	public function willLinger() : bool{
		return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_LINGER);
	}

	/**
	 * Sets whether this splash potion will create an area-effect-cloud when it lands.
	 */
	public function setLinger(bool $value = true) : void{
		$this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_LINGER, $value);
	}

	/**
	 * @return EffectInstance[]
	 */
	public function getPotionEffects() : array{
		return Potion::getPotionEffectsById($this->getPotionId());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use function atan2;
use function mt_rand;
use function sqrt;
use const M_PI;

class Squid extends WaterAnimal{
	public const NETWORK_ID = self::SQUID;

	public $width = 0.95;
	public $height = 0.95;

	/** @var Vector3|null */
	public $swimDirection = null;
	/** @var float */
	public $swimSpeed = 0.1;

	/** @var int */
	private $switchDirectionTicker = 0;

	public function initEntity() : void{
		$this->setMaxHealth(10);
		parent::initEntity();
	}

	public function getName() : string{
		return "Squid";
	}

	public function attack(EntityDamageEvent $source) : void{
		parent::attack($source);
		if($source->isCancelled()){
			return;
		}

		if($source instanceof EntityDamageByEntityEvent){
			$this->swimSpeed = mt_rand(150, 350) / 2000;
			$e = $source->getDamager();
			if($e !== null){
				$this->swimDirection = (new Vector3($this->x - $e->x, $this->y - $e->y, $this->z - $e->z))->normalize();
			}

			$this->broadcastEntityEvent(ActorEventPacket::SQUID_INK_CLOUD);
		}
	}

	private function generateRandomDirection() : Vector3{
		return new Vector3(mt_rand(-1000, 1000) / 1000, mt_rand(-500, 500) / 1000, mt_rand(-1000, 1000) / 1000);
	}

	public function entityBaseTick(int $tickDiff = 1) : bool{
		if($this->closed){
			return false;
		}

		if(++$this->switchDirectionTicker === 100){
			$this->switchDirectionTicker = 0;
			if(mt_rand(0, 100) < 50){
				$this->swimDirection = null;
			}
		}

		$hasUpdate = parent::entityBaseTick($tickDiff);

		if($this->isAlive()){

			if($this->y > 62 and $this->swimDirection !== null){
				$this->swimDirection->y = -0.5;
			}

			$inWater = $this->isUnderwater();
			if(!$inWater){
				$this->swimDirection = null;
			}elseif($this->swimDirection !== null){
				if($this->motion->lengthSquared() <= $this->swimDirection->lengthSquared()){
					$this->motion = $this->swimDirection->multiply($this->swimSpeed);
				}
			}else{
				$this->swimDirection = $this->generateRandomDirection();
				$this->swimSpeed = mt_rand(50, 100) / 2000;
			}

			$f = sqrt(($this->motion->x ** 2) + ($this->motion->z ** 2));
			$this->yaw = (-atan2($this->motion->x, $this->motion->z) * 180 / M_PI);
			$this->pitch = (-atan2($f, $this->motion->y) * 180 / M_PI);
		}

		return $hasUpdate;
	}

	protected function applyGravity() : void{
		if(!$this->isUnderwater()){
			parent::applyGravity();
		}
	}

	public function getDrops() : array{
		return [
			ItemFactory::get(Item::DYE, 0, mt_rand(1, 3))
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use pocketmine\event\entity\EntityDamageEvent;

abstract class WaterAnimal extends Creature implements Ageable{

	public function isBaby() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_BABY);
	}

	public function canBreathe() : bool{
		return $this->isUnderwater();
	}

	public function onAirExpired() : void{
		$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 2);
		$this->attack($ev);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

abstract class Creature extends Living{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use pocketmine\block\Block;
use pocketmine\event\entity\EntityDamageByChildEntityEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityDeathEvent;
use pocketmine\event\entity\EntityEffectAddEvent;
use pocketmine\event\entity\EntityEffectRemoveEvent;
use pocketmine\inventory\ArmorInventory;
use pocketmine\inventory\ArmorInventoryEventProcessor;
use pocketmine\item\Armor;
use pocketmine\item\Consumable;
use pocketmine\item\Durable;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\Item;
use pocketmine\item\MaybeConsumable;
use pocketmine\math\Vector3;
use pocketmine\math\VoxelRayTrace;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\MobEffectPacket;
use pocketmine\Player;
use pocketmine\timings\Timings;
use pocketmine\utils\Binary;
use pocketmine\utils\Color;
use function abs;
use function array_shift;
use function atan2;
use function ceil;
use function count;
use function floor;
use function lcg_value;
use function max;
use function min;
use function mt_getrandmax;
use function mt_rand;
use function sqrt;
use const M_PI;

abstract class Living extends Entity implements Damageable{

	protected $gravity = 0.08;
	protected $drag = 0.02;

	/** @var int */
	protected $attackTime = 0;

	/** @var int */
	public $deadTicks = 0;
	/** @var int */
	protected $maxDeadTicks = 25;

	/** @var float */
	protected $jumpVelocity = 0.42;

	/** @var EffectInstance[] */
	protected $effects = [];

	/** @var ArmorInventory */
	protected $armorInventory;

	abstract public function getName() : string;

	protected function initEntity() : void{
		parent::initEntity();

		$this->armorInventory = new ArmorInventory($this);
		//TODO: load/save armor inventory contents
		$this->armorInventory->setEventProcessor(new ArmorInventoryEventProcessor($this));

		$health = $this->getMaxHealth();

		if($this->namedtag->hasTag("HealF", FloatTag::class)){
			$health = $this->namedtag->getFloat("HealF");
			$this->namedtag->removeTag("HealF");
		}elseif($this->namedtag->hasTag("Health")){
			$healthTag = $this->namedtag->getTag("Health");
			$health = (float) $healthTag->getValue(); //Older versions of PocketMine-MP incorrectly saved this as a short instead of a float
			if(!($healthTag instanceof FloatTag)){
				$this->namedtag->removeTag("Health");
			}
		}

		$this->setHealth($health);

		/** @var CompoundTag[]|ListTag|null $activeEffectsTag */
		$activeEffectsTag = $this->namedtag->getListTag("ActiveEffects");
		if($activeEffectsTag !== null){
			foreach($activeEffectsTag as $e){
				$effect = Effect::getEffect($e->getByte("Id"));
				if($effect === null){
					continue;
				}

				$this->addEffect(new EffectInstance(
					$effect,
					$e->getInt("Duration"),
					Binary::unsignByte($e->getByte("Amplifier")),
					$e->getByte("ShowParticles", 1) !== 0,
					$e->getByte("Ambient", 0) !== 0
				));
			}
		}
	}

	protected function addAttributes() : void{
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::HEALTH));
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::FOLLOW_RANGE));
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::KNOCKBACK_RESISTANCE));
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::MOVEMENT_SPEED));
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::ATTACK_DAMAGE));
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::ABSORPTION));
	}

	public function setHealth(float $amount) : void{
		$wasAlive = $this->isAlive();
		parent::setHealth($amount);
		$this->attributeMap->getAttribute(Attribute::HEALTH)->setValue(ceil($this->getHealth()), true);
		if($this->isAlive() and !$wasAlive){
			$this->broadcastEntityEvent(ActorEventPacket::RESPAWN);
		}
	}

	public function getMaxHealth() : int{
		return (int) $this->attributeMap->getAttribute(Attribute::HEALTH)->getMaxValue();
	}

	public function setMaxHealth(int $amount) : void{
		$this->attributeMap->getAttribute(Attribute::HEALTH)->setMaxValue($amount)->setDefaultValue($amount);
	}

	public function getAbsorption() : float{
		return $this->attributeMap->getAttribute(Attribute::ABSORPTION)->getValue();
	}

	public function setAbsorption(float $absorption) : void{
		$this->attributeMap->getAttribute(Attribute::ABSORPTION)->setValue($absorption);
	}

	public function saveNBT() : void{
		parent::saveNBT();
		$this->namedtag->setFloat("Health", $this->getHealth(), true);

		if(count($this->effects) > 0){
			$effects = [];
			foreach($this->effects as $effect){
				$effects[] = new CompoundTag("", [
					new ByteTag("Id", $effect->getId()),
					new ByteTag("Amplifier", Binary::signByte($effect->getAmplifier())),
					new IntTag("Duration", $effect->getDuration()),
					new ByteTag("Ambient", $effect->isAmbient() ? 1 : 0),
					new ByteTag("ShowParticles", $effect->isVisible() ? 1 : 0)
				]);
			}

			$this->namedtag->setTag(new ListTag("ActiveEffects", $effects));
		}else{
			$this->namedtag->removeTag("ActiveEffects");
		}
	}

	public function hasLineOfSight(Entity $entity) : bool{
		//TODO: head height
		return true;
		//return $this->getLevel()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null;
	}

	/**
	 * Returns an array of Effects currently active on the mob.
	 * @return EffectInstance[]
	 */
	public function getEffects() : array{
		return $this->effects;
	}

	/**
	 * Removes all effects from the mob.
	 */
	public function removeAllEffects() : void{
		foreach($this->effects as $effect){
			$this->removeEffect($effect->getId());
		}
	}

	/**
	 * Removes the effect with the specified ID from the mob.
	 */
	public function removeEffect(int $effectId) : void{
		if(isset($this->effects[$effectId])){
			$effect = $this->effects[$effectId];
			$hasExpired = $effect->hasExpired();
			$ev = new EntityEffectRemoveEvent($this, $effect);
			$ev->call();
			if($ev->isCancelled()){
				if($hasExpired and !$ev->getEffect()->hasExpired()){ //altered duration of an expired effect to make it not get removed
					$this->sendEffectAdd($ev->getEffect(), true);
				}
				return;
			}

			unset($this->effects[$effectId]);
			$effect->getType()->remove($this, $effect);
			$this->sendEffectRemove($effect);

			$this->recalculateEffectColor();
		}
	}

	/**
	 * Returns the effect instance active on this entity with the specified ID, or null if the mob does not have the
	 * effect.
	 */
	public function getEffect(int $effectId) : ?EffectInstance{
		return $this->effects[$effectId] ?? null;
	}

	/**
	 * Returns whether the specified effect is active on the mob.
	 */
	public function hasEffect(int $effectId) : bool{
		return isset($this->effects[$effectId]);
	}

	/**
	 * Returns whether the mob has any active effects.
	 */
	public function hasEffects() : bool{
		return count($this->effects) > 0;
	}

	/**
	 * Adds an effect to the mob.
	 * If a weaker effect of the same type is already applied, it will be replaced.
	 * If a weaker or equal-strength effect is already applied but has a shorter duration, it will be replaced.
	 *
	 * @return bool whether the effect has been successfully applied.
	 */
	public function addEffect(EffectInstance $effect) : bool{
		$oldEffect = null;
		$cancelled = false;

		if(isset($this->effects[$effect->getId()])){
			$oldEffect = $this->effects[$effect->getId()];
			if(
				abs($effect->getAmplifier()) < $oldEffect->getAmplifier()
				or (abs($effect->getAmplifier()) === abs($oldEffect->getAmplifier()) and $effect->getDuration() < $oldEffect->getDuration())
			){
				$cancelled = true;
			}
		}

		$ev = new EntityEffectAddEvent($this, $effect, $oldEffect);
		$ev->setCancelled($cancelled);

		$ev->call();
		if($ev->isCancelled()){
			return false;
		}

		if($oldEffect !== null){
			$oldEffect->getType()->remove($this, $oldEffect);
		}

		$effect->getType()->add($this, $effect);
		$this->sendEffectAdd($effect, $oldEffect !== null);

		$this->effects[$effect->getId()] = $effect;

		$this->recalculateEffectColor();

		return true;
	}

	/**
	 * Recalculates the mob's potion bubbles colour based on the active effects.
	 */
	protected function recalculateEffectColor() : void{
		/** @var Color[] $colors */
		$colors = [];
		$ambient = true;
		foreach($this->effects as $effect){
			if($effect->isVisible() and $effect->getType()->hasBubbles()){
				$level = $effect->getEffectLevel();
				$color = $effect->getColor();
				for($i = 0; $i < $level; ++$i){
					$colors[] = $color;
				}

				if(!$effect->isAmbient()){
					$ambient = false;
				}
			}
		}

		if(count($colors) > 0){
			$this->propertyManager->setInt(Entity::DATA_POTION_COLOR, Color::mix(...$colors)->toARGB());
			$this->propertyManager->setByte(Entity::DATA_POTION_AMBIENT, $ambient ? 1 : 0);
		}else{
			$this->propertyManager->setInt(Entity::DATA_POTION_COLOR, 0);
			$this->propertyManager->setByte(Entity::DATA_POTION_AMBIENT, 0);
		}
	}

	/**
	 * Sends the mob's potion effects to the specified player.
	 */
	public function sendPotionEffects(Player $player) : void{
		foreach($this->effects as $effect){
			$pk = new MobEffectPacket();
			$pk->entityRuntimeId = $this->id;
			$pk->effectId = $effect->getId();
			$pk->amplifier = $effect->getAmplifier();
			$pk->particles = $effect->isVisible();
			$pk->duration = $effect->getDuration();
			$pk->eventId = MobEffectPacket::EVENT_ADD;

			$player->dataPacket($pk);
		}
	}

	protected function sendEffectAdd(EffectInstance $effect, bool $replacesOldEffect) : void{

	}

	protected function sendEffectRemove(EffectInstance $effect) : void{

	}

	/**
	 * Causes the mob to consume the given Consumable object, applying applicable effects, health bonuses, food bonuses,
	 * etc.
	 */
	public function consumeObject(Consumable $consumable) : bool{
		if($consumable instanceof MaybeConsumable and !$consumable->canBeConsumed()){
			return false;
		}

		foreach($consumable->getAdditionalEffects() as $effect){
			$this->addEffect($effect);
		}

		$consumable->onConsume($this);

		return true;
	}

	/**
	 * Returns the initial upwards velocity of a jumping entity in blocks/tick, including additional velocity due to effects.
	 */
	public function getJumpVelocity() : float{
		return $this->jumpVelocity + ($this->hasEffect(Effect::JUMP) ? ($this->getEffect(Effect::JUMP)->getEffectLevel() / 10) : 0);
	}

	/**
	 * Called when the entity jumps from the ground. This method adds upwards velocity to the entity.
	 */
	public function jump() : void{
		if($this->onGround){
			$this->motion->y = $this->getJumpVelocity(); //Y motion should already be 0 if we're jumping from the ground.
		}
	}

	public function fall(float $fallDistance) : void{
		$damage = ceil($fallDistance - 3 - ($this->hasEffect(Effect::JUMP) ? $this->getEffect(Effect::JUMP)->getEffectLevel() : 0));
		if($damage > 0){
			$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FALL, $damage);
			$this->attack($ev);
		}
	}

	/**
	 * Returns how many armour points this mob has. Armour points provide a percentage reduction to damage.
	 * For mobs which can wear armour, this should return the sum total of the armour points provided by their
	 * equipment.
	 */
	public function getArmorPoints() : int{
		$total = 0;
		foreach($this->armorInventory->getContents() as $item){
			$total += $item->getDefensePoints();
		}

		return $total;
	}

	/**
	 * Returns the highest level of the specified enchantment on any armour piece that the entity is currently wearing.
	 */
	public function getHighestArmorEnchantmentLevel(int $enchantmentId) : int{
		$result = 0;
		foreach($this->armorInventory->getContents() as $item){
			$result = max($result, $item->getEnchantmentLevel($enchantmentId));
		}

		return $result;
	}

	public function getArmorInventory() : ArmorInventory{
		return $this->armorInventory;
	}

	public function setOnFire(int $seconds) : void{
		parent::setOnFire($seconds - (int) min($seconds, $seconds * $this->getHighestArmorEnchantmentLevel(Enchantment::FIRE_PROTECTION) * 0.15));
	}

	/**
	 * Called prior to EntityDamageEvent execution to apply modifications to the event's damage, such as reduction due
	 * to effects or armour.
	 */
	public function applyDamageModifiers(EntityDamageEvent $source) : void{
		if($source->canBeReducedByArmor()){
			//MCPE uses the same system as PC did pre-1.9
			$source->setModifier(-$source->getFinalDamage() * $this->getArmorPoints() * 0.04, EntityDamageEvent::MODIFIER_ARMOR);
		}

		$cause = $source->getCause();
		if($this->hasEffect(Effect::DAMAGE_RESISTANCE) and $cause !== EntityDamageEvent::CAUSE_VOID and $cause !== EntityDamageEvent::CAUSE_SUICIDE){
			$source->setModifier(-$source->getFinalDamage() * min(1, 0.2 * $this->getEffect(Effect::DAMAGE_RESISTANCE)->getEffectLevel()), EntityDamageEvent::MODIFIER_RESISTANCE);
		}

		$totalEpf = 0;
		foreach($this->armorInventory->getContents() as $item){
			if($item instanceof Armor){
				$totalEpf += $item->getEnchantmentProtectionFactor($source);
			}
		}
		$source->setModifier(-$source->getFinalDamage() * min(ceil(min($totalEpf, 25) * (mt_rand(50, 100) / 100)), 20) * 0.04, EntityDamageEvent::MODIFIER_ARMOR_ENCHANTMENTS);

		$source->setModifier(-min($this->getAbsorption(), $source->getFinalDamage()), EntityDamageEvent::MODIFIER_ABSORPTION);
	}

	/**
	 * Called after EntityDamageEvent execution to apply post-hurt effects, such as reducing absorption or modifying
	 * armour durability.
	 * This will not be called by damage sources causing death.
	 */
	protected function applyPostDamageEffects(EntityDamageEvent $source) : void{
		$this->setAbsorption(max(0, $this->getAbsorption() + $source->getModifier(EntityDamageEvent::MODIFIER_ABSORPTION)));
		$this->damageArmor($source->getBaseDamage());

		if($source instanceof EntityDamageByEntityEvent){
			$damage = 0;
			foreach($this->armorInventory->getContents() as $k => $item){
				if($item instanceof Armor and ($thornsLevel = $item->getEnchantmentLevel(Enchantment::THORNS)) > 0){
					if(mt_rand(0, 99) < $thornsLevel * 15){
						$this->damageItem($item, 3);
						$damage += ($thornsLevel > 10 ? $thornsLevel - 10 : 1 + mt_rand(0, 3));
					}else{
						$this->damageItem($item, 1); //thorns causes an extra +1 durability loss even if it didn't activate
					}

					$this->armorInventory->setItem($k, $item);
				}
			}

			if($damage > 0){
				$source->getDamager()->attack(new EntityDamageByEntityEvent($this, $source->getDamager(), EntityDamageEvent::CAUSE_MAGIC, $damage));
			}
		}
	}

	/**
	 * Damages the worn armour according to the amount of damage given. Each 4 points (rounded down) deals 1 damage
	 * point to each armour piece, but never less than 1 total.
	 */
	public function damageArmor(float $damage) : void{
		$durabilityRemoved = (int) max(floor($damage / 4), 1);

		$armor = $this->armorInventory->getContents(true);
		foreach($armor as $item){
			if($item instanceof Armor){
				$this->damageItem($item, $durabilityRemoved);
			}
		}

		$this->armorInventory->setContents($armor);
	}

	private function damageItem(Durable $item, int $durabilityRemoved) : void{
		$item->applyDamage($durabilityRemoved);
		if($item->isBroken()){
			$this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_BREAK);
		}
	}

	public function attack(EntityDamageEvent $source) : void{
		if($this->noDamageTicks > 0){
			$source->setCancelled();
		}elseif($this->attackTime > 0){
			$lastCause = $this->getLastDamageCause();
			if($lastCause !== null and $lastCause->getBaseDamage() >= $source->getBaseDamage()){
				$source->setCancelled();
			}
		}

		if($this->hasEffect(Effect::FIRE_RESISTANCE) and (
				$source->getCause() === EntityDamageEvent::CAUSE_FIRE
				or $source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK
				or $source->getCause() === EntityDamageEvent::CAUSE_LAVA
			)
		){
			$source->setCancelled();
		}

		$this->applyDamageModifiers($source);

		if($source instanceof EntityDamageByEntityEvent and (
			$source->getCause() === EntityDamageEvent::CAUSE_BLOCK_EXPLOSION or
			$source->getCause() === EntityDamageEvent::CAUSE_ENTITY_EXPLOSION)
		){
			//TODO: knockback should not just apply for entity damage sources
			//this doesn't matter for TNT right now because the PrimedTNT entity is considered the source, not the block.
			$base = $source->getKnockBack();
			$source->setKnockBack($base - min($base, $base * $this->getHighestArmorEnchantmentLevel(Enchantment::BLAST_PROTECTION) * 0.15));
		}

		parent::attack($source);

		if($source->isCancelled()){
			return;
		}

		$this->attackTime = $source->getAttackCooldown();

		if($source instanceof EntityDamageByEntityEvent){
			$e = $source->getDamager();
			if($source instanceof EntityDamageByChildEntityEvent){
				$e = $source->getChild();
			}

			if($e !== null){
				if((
					$source->getCause() === EntityDamageEvent::CAUSE_PROJECTILE or
					$source->getCause() === EntityDamageEvent::CAUSE_ENTITY_ATTACK
				) and $e->isOnFire()){
					$this->setOnFire(2 * $this->level->getDifficulty());
				}

				$deltaX = $this->x - $e->x;
				$deltaZ = $this->z - $e->z;
				$this->knockBack($e, $source->getBaseDamage(), $deltaX, $deltaZ, $source->getKnockBack());
			}
		}

		if($this->isAlive()){
			$this->applyPostDamageEffects($source);
			$this->doHitAnimation();
		}
	}

	protected function doHitAnimation() : void{
		$this->broadcastEntityEvent(ActorEventPacket::HURT_ANIMATION);
	}

	public function knockBack(Entity $attacker, float $damage, float $x, float $z, float $base = 0.4) : void{
		$f = sqrt($x * $x + $z * $z);
		if($f <= 0){
			return;
		}
		if(mt_rand() / mt_getrandmax() > $this->getAttributeMap()->getAttribute(Attribute::KNOCKBACK_RESISTANCE)->getValue()){
			$f = 1 / $f;

			$motion = clone $this->motion;

			$motion->x /= 2;
			$motion->y /= 2;
			$motion->z /= 2;
			$motion->x += $x * $f * $base;
			$motion->y += $base;
			$motion->z += $z * $f * $base;

			if($motion->y > $base){
				$motion->y = $base;
			}

			$this->setMotion($motion);
		}
	}

	public function kill() : void{
		parent::kill();
		$this->onDeath();
		$this->startDeathAnimation();
	}

	protected function onDeath() : void{
		$ev = new EntityDeathEvent($this, $this->getDrops());
		$ev->call();
		foreach($ev->getDrops() as $item){
			$this->getLevel()->dropItem($this, $item);
		}

		//TODO: check death conditions (must have been damaged by player < 5 seconds from death)
		//TODO: allow this number to be manipulated during EntityDeathEvent
		$this->level->dropExperience($this, $this->getXpDropAmount());
	}

	protected function onDeathUpdate(int $tickDiff) : bool{
		if($this->deadTicks < $this->maxDeadTicks){
			$this->deadTicks += $tickDiff;
			if($this->deadTicks >= $this->maxDeadTicks){
				$this->endDeathAnimation();
			}
		}

		return $this->deadTicks >= $this->maxDeadTicks;
	}

	protected function startDeathAnimation() : void{
		$this->broadcastEntityEvent(ActorEventPacket::DEATH_ANIMATION);
	}

	protected function endDeathAnimation() : void{
		$this->despawnFromAll();
	}

	public function entityBaseTick(int $tickDiff = 1) : bool{
		Timings::$timerLivingEntityBaseTick->startTiming();

		$hasUpdate = parent::entityBaseTick($tickDiff);

		if($this->isAlive()){
			if($this->doEffectsTick($tickDiff)){
				$hasUpdate = true;
			}

			if($this->isInsideOfSolid()){
				$hasUpdate = true;
				$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 1);
				$this->attack($ev);
			}

			if($this->doAirSupplyTick($tickDiff)){
				$hasUpdate = true;
			}
		}

		if($this->attackTime > 0){
			$this->attackTime -= $tickDiff;
		}

		Timings::$timerLivingEntityBaseTick->stopTiming();

		return $hasUpdate;
	}

	protected function doEffectsTick(int $tickDiff = 1) : bool{
		foreach($this->effects as $instance){
			$type = $instance->getType();
			if($type->canTick($instance)){
				$type->applyEffect($this, $instance);
			}
			$instance->decreaseDuration($tickDiff);
			if($instance->hasExpired()){
				$this->removeEffect($instance->getId());
			}
		}

		return count($this->effects) > 0;
	}

	/**
	 * Ticks the entity's air supply, consuming it when underwater and regenerating it when out of water.
	 */
	protected function doAirSupplyTick(int $tickDiff) : bool{
		$ticks = $this->getAirSupplyTicks();
		$oldTicks = $ticks;
		if(!$this->canBreathe()){
			$this->setBreathing(false);

			if(($respirationLevel = $this->armorInventory->getHelmet()->getEnchantmentLevel(Enchantment::RESPIRATION)) <= 0 or
				lcg_value() <= (1 / ($respirationLevel + 1))
			){
				$ticks -= $tickDiff;
				if($ticks <= -20){
					$ticks = 0;
					$this->onAirExpired();
				}
			}
		}elseif(!$this->isBreathing()){
			if($ticks < ($max = $this->getMaxAirSupplyTicks())){
				$ticks += $tickDiff * 5;
			}
			if($ticks >= $max){
				$ticks = $max;
				$this->setBreathing(true);
			}
		}

		if($ticks !== $oldTicks){
			$this->setAirSupplyTicks($ticks);
		}

		return $ticks !== $oldTicks;
	}

	/**
	 * Returns whether the entity can currently breathe.
	 */
	public function canBreathe() : bool{
		return $this->hasEffect(Effect::WATER_BREATHING) or $this->hasEffect(Effect::CONDUIT_POWER) or !$this->isUnderwater();
	}

	/**
	 * Returns whether the entity is currently breathing or not. If this is false, the entity's air supply will be used.
	 */
	public function isBreathing() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_BREATHING);
	}

	/**
	 * Sets whether the entity is currently breathing. If false, it will cause the entity's air supply to be used.
	 * For players, this also shows the oxygen bar.
	 */
	public function setBreathing(bool $value = true) : void{
		$this->setGenericFlag(self::DATA_FLAG_BREATHING, $value);
	}

	/**
	 * Returns the number of ticks remaining in the entity's air supply. Note that the entity may survive longer than
	 * this amount of time without damage due to enchantments such as Respiration.
	 */
	public function getAirSupplyTicks() : int{
		return $this->propertyManager->getShort(self::DATA_AIR);
	}

	/**
	 * Sets the number of air ticks left in the entity's air supply.
	 */
	public function setAirSupplyTicks(int $ticks) : void{
		$this->propertyManager->setShort(self::DATA_AIR, $ticks);
	}

	/**
	 * Returns the maximum amount of air ticks the entity's air supply can contain.
	 */
	public function getMaxAirSupplyTicks() : int{
		return $this->propertyManager->getShort(self::DATA_MAX_AIR);
	}

	/**
	 * Sets the maximum amount of air ticks the air supply can hold.
	 */
	public function setMaxAirSupplyTicks(int $ticks) : void{
		$this->propertyManager->setShort(self::DATA_MAX_AIR, $ticks);
	}

	/**
	 * Called when the entity's air supply ticks reaches -20 or lower. The entity will usually take damage at this point
	 * and then the supply is reset to 0, so this method will be called roughly every second.
	 */
	public function onAirExpired() : void{
		$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_DROWNING, 2);
		$this->attack($ev);
	}

	/**
	 * @return Item[]
	 */
	public function getDrops() : array{
		return [];
	}

	/**
	 * Returns the amount of XP this mob will drop on death.
	 */
	public function getXpDropAmount() : int{
		return 0;
	}

	/**
	 * @param true[] $transparent
	 * @phpstan-param array<int, true> $transparent
	 *
	 * @return Block[]
	 */
	public function getLineOfSight(int $maxDistance, int $maxLength = 0, array $transparent = []) : array{
		if($maxDistance > 120){
			$maxDistance = 120;
		}

		if(count($transparent) === 0){
			$transparent = null;
		}

		$blocks = [];
		$nextIndex = 0;

		foreach(VoxelRayTrace::inDirection($this->add(0, $this->eyeHeight, 0), $this->getDirectionVector(), $maxDistance) as $vector3){
			$block = $this->level->getBlockAt($vector3->x, $vector3->y, $vector3->z);
			$blocks[$nextIndex++] = $block;

			if($maxLength !== 0 and count($blocks) > $maxLength){
				array_shift($blocks);
				--$nextIndex;
			}

			$id = $block->getId();

			if($transparent === null){
				if($id !== 0){
					break;
				}
			}else{
				if(!isset($transparent[$id])){
					break;
				}
			}
		}

		return $blocks;
	}

	/**
	 * @param true[] $transparent
	 * @phpstan-param array<int, true> $transparent
	 */
	public function getTargetBlock(int $maxDistance, array $transparent = []) : ?Block{
		$line = $this->getLineOfSight($maxDistance, 1, $transparent);
		if(count($line) > 0){
			return array_shift($line);
		}

		return null;
	}

	/**
	 * Changes the entity's yaw and pitch to make it look at the specified Vector3 position. For mobs, this will cause
	 * their heads to turn.
	 */
	public function lookAt(Vector3 $target) : void{
		$horizontal = sqrt(($target->x - $this->x) ** 2 + ($target->z - $this->z) ** 2);
		$vertical = $target->y - $this->y;
		$this->pitch = -atan2($vertical, $horizontal) / M_PI * 180; //negative is up, positive is down

		$xDist = $target->x - $this->x;
		$zDist = $target->z - $this->z;
		$this->yaw = atan2($zDist, $xDist) / M_PI * 180 - 90;
		if($this->yaw < 0){
			$this->yaw += 360.0;
		}
	}

	protected function sendSpawnPacket(Player $player) : void{
		parent::sendSpawnPacket($player);

		$this->armorInventory->sendContents($player);
	}

	public function close() : void{
		if(!$this->closed){
			if($this->armorInventory !== null){
				$this->armorInventory->removeAllViewers(true);
				$this->armorInventory = null;
			}
			parent::close();
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

interface Damageable{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

interface Ageable{
	public function isBaby() : bool;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

class Villager extends Creature implements NPC, Ageable{
	public const PROFESSION_FARMER = 0;
	public const PROFESSION_LIBRARIAN = 1;
	public const PROFESSION_PRIEST = 2;
	public const PROFESSION_BLACKSMITH = 3;
	public const PROFESSION_BUTCHER = 4;

	public const NETWORK_ID = self::VILLAGER;

	public $width = 0.6;
	public $height = 1.8;

	public function getName() : string{
		return "Villager";
	}

	protected function initEntity() : void{
		parent::initEntity();

		/** @var int $profession */
		$profession = $this->namedtag->getInt("Profession", self::PROFESSION_FARMER);

		if($profession > 4 or $profession < 0){
			$profession = self::PROFESSION_FARMER;
		}

		$this->setProfession($profession);
	}

	public function saveNBT() : void{
		parent::saveNBT();
		$this->namedtag->setInt("Profession", $this->getProfession());
	}

	/**
	 * Sets the villager profession
	 */
	public function setProfession(int $profession) : void{
		$this->propertyManager->setInt(self::DATA_VARIANT, $profession);
	}

	public function getProfession() : int{
		return $this->propertyManager->getInt(self::DATA_VARIANT);
	}

	public function isBaby() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_BABY);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

interface NPC{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use function mt_rand;

class Zombie extends Monster{
	public const NETWORK_ID = self::ZOMBIE;

	public $width = 0.6;
	public $height = 1.8;

	public function getName() : string{
		return "Zombie";
	}

	public function getDrops() : array{
		$drops = [
			ItemFactory::get(Item::ROTTEN_FLESH, 0, mt_rand(0, 2))
		];

		if(mt_rand(0, 199) < 5){
			switch(mt_rand(0, 2)){
				case 0:
					$drops[] = ItemFactory::get(Item::IRON_INGOT, 0, 1);
					break;
				case 1:
					$drops[] = ItemFactory::get(Item::CARROT, 0, 1);
					break;
				case 2:
					$drops[] = ItemFactory::get(Item::POTATO, 0, 1);
					break;
			}
		}

		return $drops;
	}

	public function getXpDropAmount() : int{
		//TODO: check for equipment and whether it's a baby
		return 5;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

abstract class Monster extends Creature{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use pocketmine\entity\projectile\ProjectileSource;
use pocketmine\entity\utils\ExperienceUtils;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\event\player\PlayerExhaustEvent;
use pocketmine\event\player\PlayerExperienceChangeEvent;
use pocketmine\inventory\EnderChestInventory;
use pocketmine\inventory\EntityInventoryEventProcessor;
use pocketmine\inventory\InventoryHolder;
use pocketmine\inventory\PlayerInventory;
use pocketmine\item\Consumable;
use pocketmine\item\Durable;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\FoodSource;
use pocketmine\item\Item;
use pocketmine\item\MaybeConsumable;
use pocketmine\item\Totem;
use pocketmine\level\Level;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteArrayTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\Player;
use pocketmine\utils\UUID;
use function array_filter;
use function array_merge;
use function array_rand;
use function array_values;
use function ceil;
use function count;
use function in_array;
use function max;
use function min;
use function mt_rand;
use function random_int;
use function strlen;
use const INT32_MAX;
use const INT32_MIN;

class Human extends Creature implements ProjectileSource, InventoryHolder{

	/** @var PlayerInventory */
	protected $inventory;

	/** @var EnderChestInventory */
	protected $enderChestInventory;

	/** @var UUID */
	protected $uuid;
	/** @var string */
	protected $rawUUID;

	public $width = 0.6;
	public $height = 1.8;
	public $eyeHeight = 1.62;

	/** @var Skin */
	protected $skin;

	/** @var int */
	protected $foodTickTimer = 0;

	/** @var int */
	protected $totalXp = 0;
	/** @var int */
	protected $xpSeed;
	/** @var int */
	protected $xpCooldown = 0;

	protected $baseOffset = 1.62;

	public function __construct(Level $level, CompoundTag $nbt){
		if($this->skin === null){
			$skinTag = $nbt->getCompoundTag("Skin");
			if($skinTag === null){
				throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
			}
			$this->skin = self::deserializeSkinNBT($skinTag); //this throws if the skin is invalid
		}

		parent::__construct($level, $nbt);
	}

	/**
	 * @throws \InvalidArgumentException
	 */
	protected static function deserializeSkinNBT(CompoundTag $skinTag) : Skin{
		$skin = new Skin(
			$skinTag->getString("Name"),
			$skinTag->hasTag("Data", StringTag::class) ? $skinTag->getString("Data") : $skinTag->getByteArray("Data"), //old data (this used to be saved as a StringTag in older versions of PM)
			$skinTag->getByteArray("CapeData", ""),
			$skinTag->getString("GeometryName", ""),
			$skinTag->getByteArray("GeometryData", "")
		);
		$skin->validate();
		return $skin;
	}

	/**
	 * @deprecated
	 *
	 * Checks the length of a supplied skin bitmap and returns whether the length is valid.
	 */
	public static function isValidSkin(string $skin) : bool{
		return in_array(strlen($skin), Skin::ACCEPTED_SKIN_SIZES, true);
	}

	public function getUniqueId() : ?UUID{
		return $this->uuid;
	}

	public function getRawUniqueId() : string{
		return $this->rawUUID;
	}

	/**
	 * Returns a Skin object containing information about this human's skin.
	 */
	public function getSkin() : Skin{
		return $this->skin;
	}

	/**
	 * Sets the human's skin. This will not send any update to viewers, you need to do that manually using
	 * {@link sendSkin}.
	 */
	public function setSkin(Skin $skin) : void{
		$skin->validate();
		$this->skin = $skin;
		$this->skin->debloatGeometryData();
	}

	/**
	 * Sends the human's skin to the specified list of players. If null is given for targets, the skin will be sent to
	 * all viewers.
	 *
	 * @param Player[]|null $targets
	 */
	public function sendSkin(?array $targets = null) : void{
		$pk = new PlayerSkinPacket();
		$pk->uuid = $this->getUniqueId();
		$pk->skin = SkinAdapterSingleton::get()->toSkinData($this->skin);
		$this->server->broadcastPacket($targets ?? $this->hasSpawned, $pk);
	}

	public function jump() : void{
		parent::jump();
		if($this->isSprinting()){
			$this->exhaust(0.8, PlayerExhaustEvent::CAUSE_SPRINT_JUMPING);
		}else{
			$this->exhaust(0.2, PlayerExhaustEvent::CAUSE_JUMPING);
		}
	}

	public function getFood() : float{
		return $this->attributeMap->getAttribute(Attribute::HUNGER)->getValue();
	}

	/**
	 * WARNING: This method does not check if full and may throw an exception if out of bounds.
	 * Use {@link Human::addFood()} for this purpose
	 *
	 * @throws \InvalidArgumentException
	 */
	public function setFood(float $new) : void{
		$attr = $this->attributeMap->getAttribute(Attribute::HUNGER);
		$old = $attr->getValue();
		$attr->setValue($new);

		// ranges: 18-20 (regen), 7-17 (none), 1-6 (no sprint), 0 (health depletion)
		foreach([17, 6, 0] as $bound){
			if(($old > $bound) !== ($new > $bound)){
				$this->foodTickTimer = 0;
				break;
			}
		}
	}

	public function getMaxFood() : float{
		return $this->attributeMap->getAttribute(Attribute::HUNGER)->getMaxValue();
	}

	public function addFood(float $amount) : void{
		$attr = $this->attributeMap->getAttribute(Attribute::HUNGER);
		$amount += $attr->getValue();
		$amount = max(min($amount, $attr->getMaxValue()), $attr->getMinValue());
		$this->setFood($amount);
	}

	/**
	 * Returns whether this Human may consume objects requiring hunger.
	 */
	public function isHungry() : bool{
		return $this->getFood() < $this->getMaxFood();
	}

	public function getSaturation() : float{
		return $this->attributeMap->getAttribute(Attribute::SATURATION)->getValue();
	}

	/**
	 * WARNING: This method does not check if saturated and may throw an exception if out of bounds.
	 * Use {@link Human::addSaturation()} for this purpose
	 *
	 * @throws \InvalidArgumentException
	 */
	public function setSaturation(float $saturation) : void{
		$this->attributeMap->getAttribute(Attribute::SATURATION)->setValue($saturation);
	}

	public function addSaturation(float $amount) : void{
		$attr = $this->attributeMap->getAttribute(Attribute::SATURATION);
		$attr->setValue($attr->getValue() + $amount, true);
	}

	public function getExhaustion() : float{
		return $this->attributeMap->getAttribute(Attribute::EXHAUSTION)->getValue();
	}

	/**
	 * WARNING: This method does not check if exhausted and does not consume saturation/food.
	 * Use {@link Human::exhaust()} for this purpose.
	 */
	public function setExhaustion(float $exhaustion) : void{
		$this->attributeMap->getAttribute(Attribute::EXHAUSTION)->setValue($exhaustion);
	}

	/**
	 * Increases a human's exhaustion level.
	 *
	 * @return float the amount of exhaustion level increased
	 */
	public function exhaust(float $amount, int $cause = PlayerExhaustEvent::CAUSE_CUSTOM) : float{
		$ev = new PlayerExhaustEvent($this, $amount, $cause);
		$ev->call();
		if($ev->isCancelled()){
			return 0.0;
		}

		$exhaustion = $this->getExhaustion();
		$exhaustion += $ev->getAmount();

		while($exhaustion >= 4.0){
			$exhaustion -= 4.0;

			$saturation = $this->getSaturation();
			if($saturation > 0){
				$saturation = max(0, $saturation - 1.0);
				$this->setSaturation($saturation);
			}else{
				$food = $this->getFood();
				if($food > 0){
					$food--;
					$this->setFood(max($food, 0));
				}
			}
		}
		$this->setExhaustion($exhaustion);

		return $ev->getAmount();
	}

	public function consumeObject(Consumable $consumable) : bool{
		if($consumable instanceof MaybeConsumable and !$consumable->canBeConsumed()){
			return false;
		}

		if($consumable instanceof FoodSource){
			if($consumable->requiresHunger() and !$this->isHungry()){
				return false;
			}

			$this->addFood($consumable->getFoodRestore());
			$this->addSaturation($consumable->getSaturationRestore());
		}

		return parent::consumeObject($consumable);
	}

	/**
	 * Returns the player's experience level.
	 */
	public function getXpLevel() : int{
		return (int) $this->attributeMap->getAttribute(Attribute::EXPERIENCE_LEVEL)->getValue();
	}

	/**
	 * Sets the player's experience level. This does not affect their total XP or their XP progress.
	 */
	public function setXpLevel(int $level) : bool{
		return $this->setXpAndProgress($level, null);
	}

	/**
	 * Adds a number of XP levels to the player.
	 */
	public function addXpLevels(int $amount, bool $playSound = true) : bool{
		$oldLevel = $this->getXpLevel();
		if($this->setXpLevel($oldLevel + $amount)){
			if($playSound){
				$newLevel = $this->getXpLevel();
				if((int) ($newLevel / 5) > (int) ($oldLevel / 5)){
					$this->playLevelUpSound($newLevel);
				}
			}

			return true;
		}

		return false;
	}

	/**
	 * Subtracts a number of XP levels from the player.
	 */
	public function subtractXpLevels(int $amount) : bool{
		return $this->addXpLevels(-$amount);
	}

	/**
	 * Returns a value between 0.0 and 1.0 to indicate how far through the current level the player is.
	 */
	public function getXpProgress() : float{
		return $this->attributeMap->getAttribute(Attribute::EXPERIENCE)->getValue();
	}

	/**
	 * Sets the player's progress through the current level to a value between 0.0 and 1.0.
	 */
	public function setXpProgress(float $progress) : bool{
		return $this->setXpAndProgress(null, $progress);
	}

	/**
	 * Returns the number of XP points the player has progressed into their current level.
	 */
	public function getRemainderXp() : int{
		return (int) (ExperienceUtils::getXpToCompleteLevel($this->getXpLevel()) * $this->getXpProgress());
	}

	/**
	 * Returns the amount of XP points the player currently has, calculated from their current level and progress
	 * through their current level. This will be reduced by enchanting deducting levels and is used to calculate the
	 * amount of XP the player drops on death.
	 */
	public function getCurrentTotalXp() : int{
		return ExperienceUtils::getXpToReachLevel($this->getXpLevel()) + $this->getRemainderXp();
	}

	/**
	 * Sets the current total of XP the player has, recalculating their XP level and progress.
	 * Note that this DOES NOT update the player's lifetime total XP.
	 */
	public function setCurrentTotalXp(int $amount) : bool{
		$newLevel = ExperienceUtils::getLevelFromXp($amount);

		return $this->setXpAndProgress((int) $newLevel, $newLevel - ((int) $newLevel));
	}

	/**
	 * Adds an amount of XP to the player, recalculating their XP level and progress. XP amount will be added to the
	 * player's lifetime XP.
	 *
	 * @param bool $playSound Whether to play level-up and XP gained sounds.
	 */
	public function addXp(int $amount, bool $playSound = true) : bool{
		$this->totalXp += $amount;

		$oldLevel = $this->getXpLevel();
		$oldTotal = $this->getCurrentTotalXp();

		if($this->setCurrentTotalXp($oldTotal + $amount)){
			if($playSound){
				$newLevel = $this->getXpLevel();
				if((int) ($newLevel / 5) > (int) ($oldLevel / 5)){
					$this->playLevelUpSound($newLevel);
				}elseif($this->getCurrentTotalXp() > $oldTotal){
					$this->level->broadcastLevelEvent($this, LevelEventPacket::EVENT_SOUND_ORB, mt_rand());
				}
			}

			return true;
		}

		return false;
	}

	private function playLevelUpSound(int $newLevel) : void{
		$volume = 0x10000000 * (min(30, $newLevel) / 5); //No idea why such odd numbers, but this works...
		$this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_LEVELUP, (int) $volume);
	}

	/**
	 * Takes an amount of XP from the player, recalculating their XP level and progress.
	 */
	public function subtractXp(int $amount) : bool{
		return $this->addXp(-$amount);
	}

	protected function setXpAndProgress(?int $level, ?float $progress) : bool{
		if(!$this->justCreated){
			$ev = new PlayerExperienceChangeEvent($this, $this->getXpLevel(), $this->getXpProgress(), $level, $progress);
			$ev->call();

			if($ev->isCancelled()){
				return false;
			}

			$level = $ev->getNewLevel();
			$progress = $ev->getNewProgress();
		}

		if($level !== null){
			$this->getAttributeMap()->getAttribute(Attribute::EXPERIENCE_LEVEL)->setValue($level);
		}

		if($progress !== null){
			$this->getAttributeMap()->getAttribute(Attribute::EXPERIENCE)->setValue($progress);
		}

		return true;
	}

	/**
	 * Returns the total XP the player has collected in their lifetime. Resets when the player dies.
	 * XP levels being removed in enchanting do not reduce this number.
	 */
	public function getLifetimeTotalXp() : int{
		return $this->totalXp;
	}

	/**
	 * Sets the lifetime total XP of the player. This does not recalculate their level or progress. Used for player
	 * score when they die. (TODO: add this when MCPE supports it)
	 */
	public function setLifetimeTotalXp(int $amount) : void{
		if($amount < 0){
			throw new \InvalidArgumentException("XP must be greater than 0");
		}

		$this->totalXp = $amount;
	}

	/**
	 * Returns whether the human can pickup XP orbs (checks cooldown time)
	 */
	public function canPickupXp() : bool{
		return $this->xpCooldown === 0;
	}

	public function onPickupXp(int $xpValue) : void{
		static $mainHandIndex = -1;

		//TODO: replace this with a more generic equipment getting/setting interface
		/** @var Durable[] $equipment */
		$equipment = [];

		if(($item = $this->inventory->getItemInHand()) instanceof Durable and $item->hasEnchantment(Enchantment::MENDING)){
			$equipment[$mainHandIndex] = $item;
		}
		//TODO: check offhand
		foreach($this->armorInventory->getContents() as $k => $armorItem){
			if($armorItem instanceof Durable and $armorItem->hasEnchantment(Enchantment::MENDING)){
				$equipment[$k] = $armorItem;
			}
		}

		if(count($equipment) > 0){
			$repairItem = $equipment[$k = array_rand($equipment)];
			if($repairItem->getDamage() > 0){
				$repairAmount = min($repairItem->getDamage(), $xpValue * 2);
				$repairItem->setDamage($repairItem->getDamage() - $repairAmount);
				$xpValue -= (int) ceil($repairAmount / 2);

				if($k === $mainHandIndex){
					$this->inventory->setItemInHand($repairItem);
				}else{
					$this->armorInventory->setItem($k, $repairItem);
				}
			}
		}

		$this->addXp($xpValue); //this will still get fired even if the value is 0 due to mending, to play sounds
		$this->resetXpCooldown();
	}

	/**
	 * Sets the duration in ticks until the human can pick up another XP orb.
	 */
	public function resetXpCooldown(int $value = 2) : void{
		$this->xpCooldown = $value;
	}

	public function getXpDropAmount() : int{
		//this causes some XP to be lost on death when above level 1 (by design), dropping at most enough points for
		//about 7.5 levels of XP.
		return min(100, 7 * $this->getXpLevel());
	}

	/**
	 * @return PlayerInventory
	 */
	public function getInventory(){
		return $this->inventory;
	}

	public function getEnderChestInventory() : EnderChestInventory{
		return $this->enderChestInventory;
	}

	/**
	 * For Human entities which are not players, sets their properties such as nametag, skin and UUID from NBT.
	 */
	protected function initHumanData() : void{
		if($this->namedtag->hasTag("NameTag", StringTag::class)){
			$this->setNameTag($this->namedtag->getString("NameTag"));
		}

		$this->uuid = UUID::fromData((string) $this->getId(), $this->skin->getSkinData(), $this->getNameTag());
	}

	protected function initEntity() : void{
		parent::initEntity();

		$this->setPlayerFlag(self::DATA_PLAYER_FLAG_SLEEP, false);
		$this->propertyManager->setBlockPos(self::DATA_PLAYER_BED_POSITION, null);

		$this->inventory = new PlayerInventory($this);
		$this->enderChestInventory = new EnderChestInventory();
		$this->initHumanData();

		$inventoryTag = $this->namedtag->getListTag("Inventory");
		if($inventoryTag !== null){
			$armorListener = $this->armorInventory->getEventProcessor();
			$this->armorInventory->setEventProcessor(null);

			/** @var CompoundTag $item */
			foreach($inventoryTag as $i => $item){
				$slot = $item->getByte("Slot");
				if($slot >= 0 and $slot < 9){ //Hotbar
					//Old hotbar saving stuff, ignore it
				}elseif($slot >= 100 and $slot < 104){ //Armor
					$this->armorInventory->setItem($slot - 100, Item::nbtDeserialize($item));
				}elseif($slot >= 9 and $slot < $this->inventory->getSize() + 9){
					$this->inventory->setItem($slot - 9, Item::nbtDeserialize($item));
				}
			}

			$this->armorInventory->setEventProcessor($armorListener);
		}

		$enderChestInventoryTag = $this->namedtag->getListTag("EnderChestInventory");
		if($enderChestInventoryTag !== null){
			/** @var CompoundTag $item */
			foreach($enderChestInventoryTag as $i => $item){
				$this->enderChestInventory->setItem($item->getByte("Slot"), Item::nbtDeserialize($item));
			}
		}

		$this->inventory->setHeldItemIndex($this->namedtag->getInt("SelectedInventorySlot", 0), false);

		$this->inventory->setEventProcessor(new EntityInventoryEventProcessor($this));

		$this->setFood((float) $this->namedtag->getInt("foodLevel", (int) $this->getFood(), true));
		$this->setExhaustion($this->namedtag->getFloat("foodExhaustionLevel", $this->getExhaustion(), true));
		$this->setSaturation($this->namedtag->getFloat("foodSaturationLevel", $this->getSaturation(), true));
		$this->foodTickTimer = $this->namedtag->getInt("foodTickTimer", $this->foodTickTimer, true);

		$this->setXpLevel($this->namedtag->getInt("XpLevel", $this->getXpLevel(), true));
		$this->setXpProgress($this->namedtag->getFloat("XpP", $this->getXpProgress(), true));
		$this->totalXp = $this->namedtag->getInt("XpTotal", $this->totalXp, true);

		if($this->namedtag->hasTag("XpSeed", IntTag::class)){
			$this->xpSeed = $this->namedtag->getInt("XpSeed");
		}else{
			$this->xpSeed = random_int(INT32_MIN, INT32_MAX);
		}
	}

	protected function addAttributes() : void{
		parent::addAttributes();

		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::SATURATION));
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXHAUSTION));
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::HUNGER));
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXPERIENCE_LEVEL));
		$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXPERIENCE));
	}

	public function entityBaseTick(int $tickDiff = 1) : bool{
		$hasUpdate = parent::entityBaseTick($tickDiff);

		$this->doFoodTick($tickDiff);

		if($this->xpCooldown > 0){
			$this->xpCooldown--;
		}

		return $hasUpdate;
	}

	protected function doFoodTick(int $tickDiff = 1) : void{
		if($this->isAlive()){
			$food = $this->getFood();
			$health = $this->getHealth();
			$difficulty = $this->level->getDifficulty();

			$this->foodTickTimer += $tickDiff;
			if($this->foodTickTimer >= 80){
				$this->foodTickTimer = 0;
			}

			if($difficulty === Level::DIFFICULTY_PEACEFUL and $this->foodTickTimer % 10 === 0){
				if($food < $this->getMaxFood()){
					$this->addFood(1.0);
					$food = $this->getFood();
				}
				if($this->foodTickTimer % 20 === 0 and $health < $this->getMaxHealth()){
					$this->heal(new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION));
				}
			}

			if($this->foodTickTimer === 0){
				if($food >= 18){
					if($health < $this->getMaxHealth()){
						$this->heal(new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION));
						$this->exhaust(3.0, PlayerExhaustEvent::CAUSE_HEALTH_REGEN);
					}
				}elseif($food <= 0){
					if(($difficulty === Level::DIFFICULTY_EASY and $health > 10) or ($difficulty === Level::DIFFICULTY_NORMAL and $health > 1) or $difficulty === Level::DIFFICULTY_HARD){
						$this->attack(new EntityDamageEvent($this, EntityDamageEvent::CAUSE_STARVATION, 1));
					}
				}
			}

			if($food <= 6){
				$this->setSprinting(false);
			}
		}
	}

	public function getName() : string{
		return $this->getNameTag();
	}

	public function applyDamageModifiers(EntityDamageEvent $source) : void{
		parent::applyDamageModifiers($source);

		$type = $source->getCause();
		if($type !== EntityDamageEvent::CAUSE_SUICIDE and $type !== EntityDamageEvent::CAUSE_VOID
			and $this->inventory->getItemInHand() instanceof Totem){ //TODO: check offhand as well (when it's implemented)

			$compensation = $this->getHealth() - $source->getFinalDamage() - 1;
			if($compensation < 0){
				$source->setModifier($compensation, EntityDamageEvent::MODIFIER_TOTEM);
			}
		}
	}

	protected function applyPostDamageEffects(EntityDamageEvent $source) : void{
		parent::applyPostDamageEffects($source);
		$totemModifier = $source->getModifier(EntityDamageEvent::MODIFIER_TOTEM);
		if($totemModifier < 0){ //Totem prevented death
			$this->removeAllEffects();

			$this->addEffect(new EffectInstance(Effect::getEffect(Effect::REGENERATION), 40 * 20, 1));
			$this->addEffect(new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 40 * 20, 1));
			$this->addEffect(new EffectInstance(Effect::getEffect(Effect::ABSORPTION), 5 * 20, 1));

			$this->broadcastEntityEvent(ActorEventPacket::CONSUME_TOTEM);
			$this->level->broadcastLevelEvent($this->add(0, $this->eyeHeight, 0), LevelEventPacket::EVENT_SOUND_TOTEM);

			$hand = $this->inventory->getItemInHand();
			if($hand instanceof Totem){
				$hand->pop(); //Plugins could alter max stack size
				$this->inventory->setItemInHand($hand);
			}
		}
	}

	public function getDrops() : array{
		return array_filter(array_merge(
			$this->inventory !== null ? array_values($this->inventory->getContents()) : [],
			$this->armorInventory !== null ? array_values($this->armorInventory->getContents()) : []
		), function(Item $item) : bool{ return !$item->hasEnchantment(Enchantment::VANISHING); });
	}

	public function saveNBT() : void{
		parent::saveNBT();

		$this->namedtag->setInt("foodLevel", (int) $this->getFood(), true);
		$this->namedtag->setFloat("foodExhaustionLevel", $this->getExhaustion(), true);
		$this->namedtag->setFloat("foodSaturationLevel", $this->getSaturation(), true);
		$this->namedtag->setInt("foodTickTimer", $this->foodTickTimer);

		$this->namedtag->setInt("XpLevel", $this->getXpLevel());
		$this->namedtag->setFloat("XpP", $this->getXpProgress());
		$this->namedtag->setInt("XpTotal", $this->totalXp);
		$this->namedtag->setInt("XpSeed", $this->xpSeed);

		$inventoryTag = new ListTag("Inventory", [], NBT::TAG_Compound);
		$this->namedtag->setTag($inventoryTag);
		if($this->inventory !== null){
			//Normal inventory
			$slotCount = $this->inventory->getSize() + $this->inventory->getHotbarSize();
			for($slot = $this->inventory->getHotbarSize(); $slot < $slotCount; ++$slot){
				$item = $this->inventory->getItem($slot - 9);
				if(!$item->isNull()){
					$inventoryTag->push($item->nbtSerialize($slot));
				}
			}

			//Armor
			for($slot = 100; $slot < 104; ++$slot){
				$item = $this->armorInventory->getItem($slot - 100);
				if(!$item->isNull()){
					$inventoryTag->push($item->nbtSerialize($slot));
				}
			}

			$this->namedtag->setInt("SelectedInventorySlot", $this->inventory->getHeldItemIndex());
		}

		if($this->enderChestInventory !== null){
			/** @var CompoundTag[] $items */
			$items = [];

			$slotCount = $this->enderChestInventory->getSize();
			for($slot = 0; $slot < $slotCount; ++$slot){
				$item = $this->enderChestInventory->getItem($slot);
				if(!$item->isNull()){
					$items[] = $item->nbtSerialize($slot);
				}
			}

			$this->namedtag->setTag(new ListTag("EnderChestInventory", $items, NBT::TAG_Compound));
		}

		if($this->skin !== null){
			$this->namedtag->setTag(new CompoundTag("Skin", [
				new StringTag("Name", $this->skin->getSkinId()),
				new ByteArrayTag("Data", $this->skin->getSkinData()),
				new ByteArrayTag("CapeData", $this->skin->getCapeData()),
				new StringTag("GeometryName", $this->skin->getGeometryName()),
				new ByteArrayTag("GeometryData", $this->skin->getGeometryData())
			]));
		}
	}

	public function spawnTo(Player $player) : void{
		if($player !== $this){
			parent::spawnTo($player);
		}
	}

	protected function sendSpawnPacket(Player $player) : void{
		$this->skin->validate();

		if(!($this instanceof Player)){
			/* we don't use Server->updatePlayerListData() because that uses batches, which could cause race conditions in async compression mode */
			$pk = new PlayerListPacket();
			$pk->type = PlayerListPacket::TYPE_ADD;
			$pk->entries = [PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))];
			$player->dataPacket($pk);
		}

		$pk = new AddPlayerPacket();
		$pk->uuid = $this->getUniqueId();
		$pk->username = $this->getName();
		$pk->entityRuntimeId = $this->getId();
		$pk->position = $this->asVector3();
		$pk->motion = $this->getMotion();
		$pk->yaw = $this->yaw;
		$pk->pitch = $this->pitch;
		$pk->item = $this->getInventory()->getItemInHand();
		$pk->metadata = $this->propertyManager->getAll();
		$player->dataPacket($pk);

		//TODO: Hack for MCPE 1.2.13: DATA_NAMETAG is useless in AddPlayerPacket, so it has to be sent separately
		$this->sendData($player, [self::DATA_NAMETAG => [self::DATA_TYPE_STRING, $this->getNameTag()]]);

		$this->armorInventory->sendContents($player);

		if(!($this instanceof Player)){
			$pk = new PlayerListPacket();
			$pk->type = PlayerListPacket::TYPE_REMOVE;
			$pk->entries = [PlayerListEntry::createRemovalEntry($this->uuid)];
			$player->dataPacket($pk);
		}
	}

	public function broadcastMovement(bool $teleport = false) : void{
		//TODO: workaround 1.14.30 bug: MoveActor(Absolute|Delta)Packet don't work on players anymore :(
		$pk = new MovePlayerPacket();
		$pk->entityRuntimeId = $this->getId();
		$pk->position = $this->getOffsetPosition($this);
		$pk->yaw = $this->yaw;
		$pk->pitch = $this->pitch;
		$pk->headYaw = $this->yaw;
		$pk->mode = $teleport ? MovePlayerPacket::MODE_TELEPORT : MovePlayerPacket::MODE_NORMAL;

		$this->level->addChunkPacket($this->getFloorX() >> 4, $this->getFloorZ() >> 4, $pk);
	}

	public function close() : void{
		if(!$this->closed){
			if($this->inventory !== null){
				$this->inventory->removeAllViewers(true);
				$this->inventory = null;
			}
			if($this->enderChestInventory !== null){
				$this->enderChestInventory->removeAllViewers(true);
				$this->enderChestInventory = null;
			}
			parent::close();
		}
	}

	/**
	 * Wrapper around {@link Entity#getDataFlag} for player-specific data flag reading.
	 */
	public function getPlayerFlag(int $flagId) : bool{
		return $this->getDataFlag(self::DATA_PLAYER_FLAGS, $flagId);
	}

	/**
	 * Wrapper around {@link Entity#setDataFlag} for player-specific data flag setting.
	 */
	public function setPlayerFlag(int $flagId, bool $value = true) : void{
		$this->setDataFlag(self::DATA_PLAYER_FLAGS, $flagId, $value, self::DATA_TYPE_BYTE);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\projectile;

interface ProjectileSource{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

interface InventoryHolder{

	/**
	 * Get the object related inventory
	 *
	 * @return Inventory
	 */
	public function getInventory();
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use function max;
use function min;

class Attribute{

	public const ABSORPTION = 0;
	public const SATURATION = 1;
	public const EXHAUSTION = 2;
	public const KNOCKBACK_RESISTANCE = 3;
	public const HEALTH = 4;
	public const MOVEMENT_SPEED = 5;
	public const FOLLOW_RANGE = 6;
	public const HUNGER = 7;
	public const FOOD = 7;
	public const ATTACK_DAMAGE = 8;
	public const EXPERIENCE_LEVEL = 9;
	public const EXPERIENCE = 10;
	public const UNDERWATER_MOVEMENT = 11;
	public const LUCK = 12;
	public const FALL_DAMAGE = 13;
	public const HORSE_JUMP_STRENGTH = 14;
	public const ZOMBIE_SPAWN_REINFORCEMENTS = 15;

	/** @var int */
	private $id;
	/** @var float */
	protected $minValue;
	/** @var float */
	protected $maxValue;
	/** @var float */
	protected $defaultValue;
	/** @var float */
	protected $currentValue;
	/** @var string */
	protected $name;
	/** @var bool */
	protected $shouldSend;

	/** @var bool */
	protected $desynchronized = true;

	/** @var Attribute[] */
	protected static $attributes = [];

	public static function init() : void{
		self::addAttribute(self::ABSORPTION, "minecraft:absorption", 0.00, 340282346638528859811704183484516925440.00, 0.00);
		self::addAttribute(self::SATURATION, "minecraft:player.saturation", 0.00, 20.00, 20.00);
		self::addAttribute(self::EXHAUSTION, "minecraft:player.exhaustion", 0.00, 5.00, 0.0, false);
		self::addAttribute(self::KNOCKBACK_RESISTANCE, "minecraft:knockback_resistance", 0.00, 1.00, 0.00);
		self::addAttribute(self::HEALTH, "minecraft:health", 0.00, 20.00, 20.00);
		self::addAttribute(self::MOVEMENT_SPEED, "minecraft:movement", 0.00, 340282346638528859811704183484516925440.00, 0.10);
		self::addAttribute(self::FOLLOW_RANGE, "minecraft:follow_range", 0.00, 2048.00, 16.00, false);
		self::addAttribute(self::HUNGER, "minecraft:player.hunger", 0.00, 20.00, 20.00);
		self::addAttribute(self::ATTACK_DAMAGE, "minecraft:attack_damage", 0.00, 340282346638528859811704183484516925440.00, 1.00, false);
		self::addAttribute(self::EXPERIENCE_LEVEL, "minecraft:player.level", 0.00, 24791.00, 0.00);
		self::addAttribute(self::EXPERIENCE, "minecraft:player.experience", 0.00, 1.00, 0.00);
		self::addAttribute(self::UNDERWATER_MOVEMENT, "minecraft:underwater_movement", 0.0, 340282346638528859811704183484516925440.0, 0.02);
		self::addAttribute(self::LUCK, "minecraft:luck", -1024.0, 1024.0, 0.0);
		self::addAttribute(self::FALL_DAMAGE, "minecraft:fall_damage", 0.0, 340282346638528859811704183484516925440.0, 1.0);
		self::addAttribute(self::HORSE_JUMP_STRENGTH, "minecraft:horse.jump_strength", 0.0, 2.0, 0.7);
		self::addAttribute(self::ZOMBIE_SPAWN_REINFORCEMENTS, "minecraft:zombie.spawn_reinforcements", 0.0, 1.0, 0.0);
	}

	/**
	 * @throws \InvalidArgumentException
	 */
	public static function addAttribute(int $id, string $name, float $minValue, float $maxValue, float $defaultValue, bool $shouldSend = true) : Attribute{
		if($minValue > $maxValue or $defaultValue > $maxValue or $defaultValue < $minValue){
			throw new \InvalidArgumentException("Invalid ranges: min value: $minValue, max value: $maxValue, $defaultValue: $defaultValue");
		}

		return self::$attributes[$id] = new Attribute($id, $name, $minValue, $maxValue, $defaultValue, $shouldSend);
	}

	public static function getAttribute(int $id) : ?Attribute{
		return isset(self::$attributes[$id]) ? clone self::$attributes[$id] : null;
	}

	public static function getAttributeByName(string $name) : ?Attribute{
		foreach(self::$attributes as $a){
			if($a->getName() === $name){
				return clone $a;
			}
		}

		return null;
	}

	private function __construct(int $id, string $name, float $minValue, float $maxValue, float $defaultValue, bool $shouldSend = true){
		$this->id = $id;
		$this->name = $name;
		$this->minValue = $minValue;
		$this->maxValue = $maxValue;
		$this->defaultValue = $defaultValue;
		$this->shouldSend = $shouldSend;

		$this->currentValue = $this->defaultValue;
	}

	public function getMinValue() : float{
		return $this->minValue;
	}

	/**
	 * @return $this
	 */
	public function setMinValue(float $minValue){
		if($minValue > ($max = $this->getMaxValue())){
			throw new \InvalidArgumentException("Minimum $minValue is greater than the maximum $max");
		}

		if($this->minValue != $minValue){
			$this->desynchronized = true;
			$this->minValue = $minValue;
		}
		return $this;
	}

	public function getMaxValue() : float{
		return $this->maxValue;
	}

	/**
	 * @return $this
	 */
	public function setMaxValue(float $maxValue){
		if($maxValue < ($min = $this->getMinValue())){
			throw new \InvalidArgumentException("Maximum $maxValue is less than the minimum $min");
		}

		if($this->maxValue != $maxValue){
			$this->desynchronized = true;
			$this->maxValue = $maxValue;
		}
		return $this;
	}

	public function getDefaultValue() : float{
		return $this->defaultValue;
	}

	/**
	 * @return $this
	 */
	public function setDefaultValue(float $defaultValue){
		if($defaultValue > $this->getMaxValue() or $defaultValue < $this->getMinValue()){
			throw new \InvalidArgumentException("Default $defaultValue is outside the range " . $this->getMinValue() . " - " . $this->getMaxValue());
		}

		if($this->defaultValue !== $defaultValue){
			$this->desynchronized = true;
			$this->defaultValue = $defaultValue;
		}
		return $this;
	}

	public function resetToDefault() : void{
		$this->setValue($this->getDefaultValue(), true);
	}

	public function getValue() : float{
		return $this->currentValue;
	}

	/**
	 * @return $this
	 */
	public function setValue(float $value, bool $fit = false, bool $forceSend = false){
		if($value > $this->getMaxValue() or $value < $this->getMinValue()){
			if(!$fit){
				throw new \InvalidArgumentException("Value $value is outside the range " . $this->getMinValue() . " - " . $this->getMaxValue());
			}
			$value = min(max($value, $this->getMinValue()), $this->getMaxValue());
		}

		if($this->currentValue != $value){
			$this->desynchronized = true;
			$this->currentValue = $value;
		}elseif($forceSend){
			$this->desynchronized = true;
		}

		return $this;
	}

	public function getName() : string{
		return $this->name;
	}

	public function getId() : int{
		return $this->id;
	}

	public function isSyncable() : bool{
		return $this->shouldSend;
	}

	public function isDesynchronized() : bool{
		return $this->shouldSend and $this->desynchronized;
	}

	public function markSynchronized(bool $synced = true) : void{
		$this->desynchronized = !$synced;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use pocketmine\event\entity\EntityDamageByChildEntityEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\event\player\PlayerExhaustEvent;
use pocketmine\utils\Color;
use function constant;
use function defined;
use function strtoupper;

class Effect{
	public const SPEED = 1;
	public const SLOWNESS = 2;
	public const HASTE = 3;
	public const FATIGUE = 4, MINING_FATIGUE = 4;
	public const STRENGTH = 5;
	public const INSTANT_HEALTH = 6, HEALING = 6;
	public const INSTANT_DAMAGE = 7, HARMING = 7;
	public const JUMP_BOOST = 8, JUMP = 8;
	public const NAUSEA = 9, CONFUSION = 9;
	public const REGENERATION = 10;
	public const RESISTANCE = 11, DAMAGE_RESISTANCE = 11;
	public const FIRE_RESISTANCE = 12;
	public const WATER_BREATHING = 13;
	public const INVISIBILITY = 14;
	public const BLINDNESS = 15;
	public const NIGHT_VISION = 16;
	public const HUNGER = 17;
	public const WEAKNESS = 18;
	public const POISON = 19;
	public const WITHER = 20;
	public const HEALTH_BOOST = 21;
	public const ABSORPTION = 22;
	public const SATURATION = 23;
	public const LEVITATION = 24; //TODO
	public const FATAL_POISON = 25;
	public const CONDUIT_POWER = 26;

	/** @var Effect[] */
	protected static $effects = [];

	public static function init() : void{
		self::registerEffect(new Effect(Effect::SPEED, "%potion.moveSpeed", new Color(0x7c, 0xaf, 0xc6)));
		self::registerEffect(new Effect(Effect::SLOWNESS, "%potion.moveSlowdown", new Color(0x5a, 0x6c, 0x81), true));
		self::registerEffect(new Effect(Effect::HASTE, "%potion.digSpeed", new Color(0xd9, 0xc0, 0x43)));
		self::registerEffect(new Effect(Effect::MINING_FATIGUE, "%potion.digSlowDown", new Color(0x4a, 0x42, 0x17), true));
		self::registerEffect(new Effect(Effect::STRENGTH, "%potion.damageBoost", new Color(0x93, 0x24, 0x23)));
		self::registerEffect(new Effect(Effect::INSTANT_HEALTH, "%potion.heal", new Color(0xf8, 0x24, 0x23), false, 1, false));
		self::registerEffect(new Effect(Effect::INSTANT_DAMAGE, "%potion.harm", new Color(0x43, 0x0a, 0x09), true, 1, false));
		self::registerEffect(new Effect(Effect::JUMP_BOOST, "%potion.jump", new Color(0x22, 0xff, 0x4c)));
		self::registerEffect(new Effect(Effect::NAUSEA, "%potion.confusion", new Color(0x55, 0x1d, 0x4a), true));
		self::registerEffect(new Effect(Effect::REGENERATION, "%potion.regeneration", new Color(0xcd, 0x5c, 0xab)));
		self::registerEffect(new Effect(Effect::RESISTANCE, "%potion.resistance", new Color(0x99, 0x45, 0x3a)));
		self::registerEffect(new Effect(Effect::FIRE_RESISTANCE, "%potion.fireResistance", new Color(0xe4, 0x9a, 0x3a)));
		self::registerEffect(new Effect(Effect::WATER_BREATHING, "%potion.waterBreathing", new Color(0x2e, 0x52, 0x99)));
		self::registerEffect(new Effect(Effect::INVISIBILITY, "%potion.invisibility", new Color(0x7f, 0x83, 0x92)));
		self::registerEffect(new Effect(Effect::BLINDNESS, "%potion.blindness", new Color(0x1f, 0x1f, 0x23), true));
		self::registerEffect(new Effect(Effect::NIGHT_VISION, "%potion.nightVision", new Color(0x1f, 0x1f, 0xa1)));
		self::registerEffect(new Effect(Effect::HUNGER, "%potion.hunger", new Color(0x58, 0x76, 0x53), true));
		self::registerEffect(new Effect(Effect::WEAKNESS, "%potion.weakness", new Color(0x48, 0x4d, 0x48), true));
		self::registerEffect(new Effect(Effect::POISON, "%potion.poison", new Color(0x4e, 0x93, 0x31), true));
		self::registerEffect(new Effect(Effect::WITHER, "%potion.wither", new Color(0x35, 0x2a, 0x27), true));
		self::registerEffect(new Effect(Effect::HEALTH_BOOST, "%potion.healthBoost", new Color(0xf8, 0x7d, 0x23)));
		self::registerEffect(new Effect(Effect::ABSORPTION, "%potion.absorption", new Color(0x25, 0x52, 0xa5)));
		self::registerEffect(new Effect(Effect::SATURATION, "%potion.saturation", new Color(0xf8, 0x24, 0x23), false, 1));
		self::registerEffect(new Effect(Effect::LEVITATION, "%potion.levitation", new Color(0xce, 0xff, 0xff)));
		self::registerEffect(new Effect(Effect::FATAL_POISON, "%potion.poison", new Color(0x4e, 0x93, 0x31), true));
		self::registerEffect(new Effect(Effect::CONDUIT_POWER, "%potion.conduitPower", new Color(0x1d, 0xc2, 0xd1)));
	}

	public static function registerEffect(Effect $effect) : void{
		self::$effects[$effect->getId()] = $effect;
	}

	public static function getEffect(int $id) : ?Effect{
		return self::$effects[$id] ?? null;
	}

	public static function getEffectByName(string $name) : ?Effect{
		$const = self::class . "::" . strtoupper($name);
		if(defined($const)){
			return self::getEffect(constant($const));
		}
		return null;
	}

	/** @var int */
	protected $id;
	/** @var string */
	protected $name;
	/** @var Color */
	protected $color;
	/** @var bool */
	protected $bad;
	/** @var int */
	protected $defaultDuration;
	/** @var bool */
	protected $hasBubbles;

	/**
	 * @param int    $id Effect ID as per Minecraft PE
	 * @param string $name Translation key used for effect name
	 * @param Color  $color
	 * @param bool   $isBad Whether the effect is harmful
	 * @param int    $defaultDuration Duration in ticks the effect will last for by default if applied without a duration.
	 * @param bool   $hasBubbles Whether the effect has potion bubbles. Some do not (e.g. Instant Damage has its own particles instead of bubbles)
	 */
	public function __construct(int $id, string $name, Color $color, bool $isBad = false, int $defaultDuration = 300 * 20, bool $hasBubbles = true){
		$this->id = $id;
		$this->name = $name;
		$this->color = $color;
		$this->bad = $isBad;
		$this->defaultDuration = $defaultDuration;
		$this->hasBubbles = $hasBubbles;
	}

	/**
	 * Returns the effect ID as per Minecraft PE
	 */
	public function getId() : int{
		return $this->id;
	}

	/**
	 * Returns the translation key used to translate this effect's name.
	 */
	public function getName() : string{
		return $this->name;
	}

	/**
	 * Returns a Color object representing this effect's particle colour.
	 */
	public function getColor() : Color{
		return clone $this->color;
	}

	/**
	 * Returns whether this effect is harmful.
	 * TODO: implement inverse effect results for undead mobs
	 */
	public function isBad() : bool{
		return $this->bad;
	}

	/**
	 * Returns whether the effect is by default an instant effect.
	 */
	public function isInstantEffect() : bool{
		return $this->defaultDuration <= 1;
	}

	/**
	 * Returns the default duration (in ticks) this effect will apply for if a duration is not specified.
	 */
	public function getDefaultDuration() : int{
		return $this->defaultDuration;
	}

	/**
	 * Returns whether this effect will give the subject potion bubbles.
	 */
	public function hasBubbles() : bool{
		return $this->hasBubbles;
	}

	/**
	 * Returns whether the effect will do something on the current tick.
	 */
	public function canTick(EffectInstance $instance) : bool{
		switch($this->id){
			case Effect::POISON:
			case Effect::FATAL_POISON:
				if(($interval = (25 >> $instance->getAmplifier())) > 0){
					return ($instance->getDuration() % $interval) === 0;
				}
				return true;
			case Effect::WITHER:
				if(($interval = (50 >> $instance->getAmplifier())) > 0){
					return ($instance->getDuration() % $interval) === 0;
				}
				return true;
			case Effect::REGENERATION:
				if(($interval = (40 >> $instance->getAmplifier())) > 0){
					return ($instance->getDuration() % $interval) === 0;
				}
				return true;
			case Effect::HUNGER:
				return true;
			case Effect::INSTANT_DAMAGE:
			case Effect::INSTANT_HEALTH:
			case Effect::SATURATION:
				//If forced to last longer than 1 tick, these apply every tick.
				return true;
		}
		return false;
	}

	/**
	 * Applies effect results to an entity. This will not be called unless canTick() returns true.
	 */
	public function applyEffect(Living $entity, EffectInstance $instance, float $potency = 1.0, ?Entity $source = null, ?Entity $sourceOwner = null) : void{
		switch($this->id){
			/** @noinspection PhpMissingBreakStatementInspection */
			case Effect::POISON:
				if($entity->getHealth() <= 1){
					break;
				}
			case Effect::FATAL_POISON:
				$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_MAGIC, 1);
				$entity->attack($ev);
				break;

			case Effect::WITHER:
				$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_MAGIC, 1);
				$entity->attack($ev);
				break;

			case Effect::REGENERATION:
				if($entity->getHealth() < $entity->getMaxHealth()){
					$ev = new EntityRegainHealthEvent($entity, 1, EntityRegainHealthEvent::CAUSE_MAGIC);
					$entity->heal($ev);
				}
				break;

			case Effect::HUNGER:
				if($entity instanceof Human){
					$entity->exhaust(0.025 * $instance->getEffectLevel(), PlayerExhaustEvent::CAUSE_POTION);
				}
				break;
			case Effect::INSTANT_HEALTH:
				//TODO: add particles (witch spell)
				if($entity->getHealth() < $entity->getMaxHealth()){
					$entity->heal(new EntityRegainHealthEvent($entity, (4 << $instance->getAmplifier()) * $potency, EntityRegainHealthEvent::CAUSE_MAGIC));
				}
				break;
			case Effect::INSTANT_DAMAGE:
				//TODO: add particles (witch spell)
				$damage = (4 << $instance->getAmplifier()) * $potency;
				if($source !== null and $sourceOwner !== null){
					$ev = new EntityDamageByChildEntityEvent($sourceOwner, $source, $entity, EntityDamageEvent::CAUSE_MAGIC, $damage);
				}elseif($source !== null){
					$ev = new EntityDamageByEntityEvent($source, $entity, EntityDamageEvent::CAUSE_MAGIC, $damage);
				}else{
					$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_MAGIC, $damage);
				}
				$entity->attack($ev);

				break;
			case Effect::SATURATION:
				if($entity instanceof Human){
					$entity->addFood($instance->getEffectLevel());
					$entity->addSaturation($instance->getEffectLevel() * 2);
				}
				break;
		}
	}

	/**
	 * Applies effects to the entity when the effect is first added.
	 */
	public function add(Living $entity, EffectInstance $instance) : void{
		switch($this->id){
			case Effect::INVISIBILITY:
				$entity->setInvisible();
				$entity->setNameTagVisible(false);
				break;
			case Effect::SPEED:
				$attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED);
				$attr->setValue($attr->getValue() * (1 + 0.2 * $instance->getEffectLevel()));
				break;
			case Effect::SLOWNESS:
				$attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED);
				$attr->setValue($attr->getValue() * (1 - 0.15 * $instance->getEffectLevel()), true);
				break;

			case Effect::HEALTH_BOOST:
				$entity->setMaxHealth($entity->getMaxHealth() + 4 * $instance->getEffectLevel());
				break;
			case Effect::ABSORPTION:
				$new = (4 * $instance->getEffectLevel());
				if($new > $entity->getAbsorption()){
					$entity->setAbsorption($new);
				}
				break;
		}
	}

	/**
	 * Removes the effect from the entity, resetting any changed values back to their original defaults.
	 */
	public function remove(Living $entity, EffectInstance $instance) : void{
		switch($this->id){
			case Effect::INVISIBILITY:
				$entity->setInvisible(false);
				$entity->setNameTagVisible(true);
				break;
			case Effect::SPEED:
				$attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED);
				$attr->setValue($attr->getValue() / (1 + 0.2 * $instance->getEffectLevel()));
				break;
			case Effect::SLOWNESS:
				$attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED);
				$attr->setValue($attr->getValue() / (1 - 0.15 * $instance->getEffectLevel()));
				break;
			case Effect::HEALTH_BOOST:
				$entity->setMaxHealth($entity->getMaxHealth() - 4 * $instance->getEffectLevel());
				break;
			case Effect::ABSORPTION:
				$entity->setAbsorption(0);
				break;
		}
	}

	public function __clone(){
		$this->color = clone $this->color;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;

use function count;

class Color{

	/** @var int */
	protected $a;
	/** @var int */
	protected $r;
	/** @var int */
	protected $g;
	/** @var int */
	protected $b;

	public function __construct(int $r, int $g, int $b, int $a = 0xff){
		$this->r = $r & 0xff;
		$this->g = $g & 0xff;
		$this->b = $b & 0xff;
		$this->a = $a & 0xff;
	}

	/**
	 * Returns the alpha (opacity) value of this colour.
	 */
	public function getA() : int{
		return $this->a;
	}

	/**
	 * Sets the alpha (opacity) value of this colour, lower = more transparent
	 *
	 * @return void
	 */
	public function setA(int $a){
		$this->a = $a & 0xff;
	}

	/**
	 * Retuns the red value of this colour.
	 */
	public function getR() : int{
		return $this->r;
	}

	/**
	 * Sets the red value of this colour.
	 *
	 * @return void
	 */
	public function setR(int $r){
		$this->r = $r & 0xff;
	}

	/**
	 * Returns the green value of this colour.
	 */
	public function getG() : int{
		return $this->g;
	}

	/**
	 * Sets the green value of this colour.
	 *
	 * @return void
	 */
	public function setG(int $g){
		$this->g = $g & 0xff;
	}

	/**
	 * Returns the blue value of this colour.
	 */
	public function getB() : int{
		return $this->b;
	}

	/**
	 * Sets the blue value of this colour.
	 *
	 * @return void
	 */
	public function setB(int $b){
		$this->b = $b & 0xff;
	}

	/**
	 * Mixes the supplied list of colours together to produce a result colour.
	 *
	 * @param Color ...$colors
	 */
	public static function mix(Color ...$colors) : Color{
		$count = count($colors);
		if($count < 1){
			throw new \ArgumentCountError("No colors given");
		}

		$a = $r = $g = $b = 0;

		foreach($colors as $color){
			$a += $color->a;
			$r += $color->r;
			$g += $color->g;
			$b += $color->b;
		}

		return new Color((int) ($r / $count), (int) ($g / $count), (int) ($b / $count), (int) ($a / $count));
	}

	/**
	 * Returns a Color from the supplied RGB colour code (24-bit)
	 *
	 * @return Color
	 */
	public static function fromRGB(int $code){
		return new Color(($code >> 16) & 0xff, ($code >> 8) & 0xff, $code & 0xff);
	}

	/**
	 * Returns a Color from the supplied ARGB colour code (32-bit)
	 *
	 * @return Color
	 */
	public static function fromARGB(int $code){
		return new Color(($code >> 16) & 0xff, ($code >> 8) & 0xff, $code & 0xff, ($code >> 24) & 0xff);
	}

	/**
	 * Returns an ARGB 32-bit colour value.
	 */
	public function toARGB() : int{
		return ($this->a << 24) | ($this->r << 16) | ($this->g << 8) | $this->b;
	}

	/**
	 * Returns a little-endian ARGB 32-bit colour value.
	 */
	public function toBGRA() : int{
		return ($this->b << 24) | ($this->g << 16) | ($this->r << 8) | $this->a;
	}

	/**
	 * Returns an RGBA 32-bit colour value.
	 */
	public function toRGBA() : int{
		return ($this->r << 24) | ($this->g << 16) | ($this->b << 8) | $this->a;
	}

	/**
	 * Returns a little-endian RGBA colour value.
	 */
	public function toABGR() : int{
		return ($this->a << 24) | ($this->b << 16) | ($this->g << 8) | $this->r;
	}

	/**
	 * @return Color
	 */
	public static function fromABGR(int $code){
		return new Color($code & 0xff, ($code >> 8) & 0xff, ($code >> 16) & 0xff, ($code >> 24) & 0xff);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity\object;

class PaintingMotive{
	/** @var PaintingMotive[] */
	protected static $motives = [];

	public static function init() : void{
		foreach([
			new PaintingMotive(1, 1, "Alban"),
			new PaintingMotive(1, 1, "Aztec"),
			new PaintingMotive(1, 1, "Aztec2"),
			new PaintingMotive(1, 1, "Bomb"),
			new PaintingMotive(1, 1, "Kebab"),
			new PaintingMotive(1, 1, "Plant"),
			new PaintingMotive(1, 1, "Wasteland"),
			new PaintingMotive(1, 2, "Graham"),
			new PaintingMotive(1, 2, "Wanderer"),
			new PaintingMotive(2, 1, "Courbet"),
			new PaintingMotive(2, 1, "Creebet"),
			new PaintingMotive(2, 1, "Pool"),
			new PaintingMotive(2, 1, "Sea"),
			new PaintingMotive(2, 1, "Sunset"),
			new PaintingMotive(2, 2, "Bust"),
			new PaintingMotive(2, 2, "Earth"),
			new PaintingMotive(2, 2, "Fire"),
			new PaintingMotive(2, 2, "Match"),
			new PaintingMotive(2, 2, "SkullAndRoses"),
			new PaintingMotive(2, 2, "Stage"),
			new PaintingMotive(2, 2, "Void"),
			new PaintingMotive(2, 2, "Water"),
			new PaintingMotive(2, 2, "Wind"),
			new PaintingMotive(2, 2, "Wither"),
			new PaintingMotive(4, 2, "Fighters"),
			new PaintingMotive(4, 3, "DonkeyKong"),
			new PaintingMotive(4, 3, "Skeleton"),
			new PaintingMotive(4, 4, "BurningSkull"),
			new PaintingMotive(4, 4, "Pigscene"),
			new PaintingMotive(4, 4, "Pointer")
		] as $motive){
			self::registerMotive($motive);
		}
	}

	public static function registerMotive(PaintingMotive $motive) : void{
		self::$motives[$motive->getName()] = $motive;
	}

	public static function getMotiveByName(string $name) : ?PaintingMotive{
		return self::$motives[$name] ?? null;
	}

	/**
	 * @return PaintingMotive[]
	 */
	public static function getAll() : array{
		return self::$motives;
	}

	/** @var string */
	protected $name;
	/** @var int */
	protected $width;
	/** @var int */
	protected $height;

	public function __construct(int $width, int $height, string $name){
		$this->name = $name;
		$this->width = $width;
		$this->height = $height;
	}

	public function getName() : string{
		return $this->name;
	}

	public function getWidth() : int{
		return $this->width;
	}

	public function getHeight() : int{
		return $this->height;
	}

	public function __toString() : string{
		return "PaintingMotive(name: " . $this->getName() . ", height: " . $this->getHeight() . ", width: " . $this->getWidth() . ")";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * All the Tile classes and related classes
 */

namespace pocketmine\tile;

use pocketmine\block\Block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\level\Position;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\timings\Timings;
use pocketmine\timings\TimingsHandler;
use function current;
use function get_class;
use function in_array;
use function is_a;
use function reset;

abstract class Tile extends Position{

	public const TAG_ID = "id";
	public const TAG_X = "x";
	public const TAG_Y = "y";
	public const TAG_Z = "z";

	public const BANNER = "Banner";
	public const BED = "Bed";
	public const BREWING_STAND = "BrewingStand";
	public const CHEST = "Chest";
	public const ENCHANT_TABLE = "EnchantTable";
	public const ENDER_CHEST = "EnderChest";
	public const FLOWER_POT = "FlowerPot";
	public const FURNACE = "Furnace";
	public const ITEM_FRAME = "ItemFrame";
	public const MOB_SPAWNER = "MobSpawner";
	public const SIGN = "Sign";
	public const SKULL = "Skull";

	/** @var int */
	public static $tileCount = 1;

	/**
	 * @var string[] classes that extend Tile
	 * @phpstan-var array<string, class-string<Tile>>
	 */
	private static $knownTiles = [];
	/**
	 * @var string[][]
	 * @phpstan-var array<class-string<Tile>, list<string>>
	 */
	private static $saveNames = [];

	/** @var string */
	public $name;
	/** @var int */
	public $id;
	/** @var bool */
	public $closed = false;
	/** @var Server */
	protected $server;
	/** @var TimingsHandler */
	protected $timings;

	/**
	 * @return void
	 */
	public static function init(){
		self::registerTile(Banner::class, [self::BANNER, "minecraft:banner"]);
		self::registerTile(Bed::class, [self::BED, "minecraft:bed"]);
		self::registerTile(Chest::class, [self::CHEST, "minecraft:chest"]);
		self::registerTile(EnchantTable::class, [self::ENCHANT_TABLE, "minecraft:enchanting_table"]);
		self::registerTile(EnderChest::class, [self::ENDER_CHEST, "minecraft:ender_chest"]);
		self::registerTile(FlowerPot::class, [self::FLOWER_POT, "minecraft:flower_pot"]);
		self::registerTile(Furnace::class, [self::FURNACE, "minecraft:furnace"]);
		self::registerTile(ItemFrame::class, [self::ITEM_FRAME]); //this is an entity in PC
		self::registerTile(Sign::class, [self::SIGN, "minecraft:sign"]);
		self::registerTile(Skull::class, [self::SKULL, "minecraft:skull"]);
	}

	/**
	 * @param string      $type
	 * @param mixed       ...$args
	 */
	public static function createTile($type, Level $level, CompoundTag $nbt, ...$args) : ?Tile{
		if(isset(self::$knownTiles[$type])){
			$class = self::$knownTiles[$type];
			/** @see Tile::__construct() */
			return new $class($level, $nbt, ...$args);
		}

		return null;
	}

	/**
	 * @param string[] $saveNames
	 * @phpstan-param class-string<Tile> $className
	 *
	 * @throws \ReflectionException
	 */
	public static function registerTile(string $className, array $saveNames = []) : bool{
		$class = new \ReflectionClass($className);
		if(is_a($className, Tile::class, true) and !$class->isAbstract()){
			$shortName = $class->getShortName();
			if(!in_array($shortName, $saveNames, true)){
				$saveNames[] = $shortName;
			}

			foreach($saveNames as $name){
				self::$knownTiles[$name] = $className;
			}

			self::$saveNames[$className] = $saveNames;

			return true;
		}

		return false;
	}

	/**
	 * Returns the short save name
	 */
	public static function getSaveId() : string{
		if(!isset(self::$saveNames[static::class])){
			throw new \InvalidStateException("Tile is not registered");
		}

		reset(self::$saveNames[static::class]);
		return current(self::$saveNames[static::class]);
	}

	public function __construct(Level $level, CompoundTag $nbt){
		$this->timings = Timings::getTileEntityTimings($this);

		$this->server = $level->getServer();
		$this->name = "";
		$this->id = Tile::$tileCount++;

		parent::__construct($nbt->getInt(self::TAG_X), $nbt->getInt(self::TAG_Y), $nbt->getInt(self::TAG_Z), $level);
		$this->readSaveData($nbt);

		$this->getLevel()->addTile($this);
	}

	public function getId() : int{
		return $this->id;
	}

	/**
	 * Reads additional data from the CompoundTag on tile creation.
	 */
	abstract protected function readSaveData(CompoundTag $nbt) : void;

	/**
	 * Writes additional save data to a CompoundTag, not including generic things like ID and coordinates.
	 */
	abstract protected function writeSaveData(CompoundTag $nbt) : void;

	public function saveNBT() : CompoundTag{
		$nbt = new CompoundTag();
		$nbt->setString(self::TAG_ID, static::getSaveId());
		$nbt->setInt(self::TAG_X, $this->x);
		$nbt->setInt(self::TAG_Y, $this->y);
		$nbt->setInt(self::TAG_Z, $this->z);
		$this->writeSaveData($nbt);

		return $nbt;
	}

	public function getCleanedNBT() : ?CompoundTag{
		$this->writeSaveData($tag = new CompoundTag());
		return $tag->getCount() > 0 ? $tag : null;
	}

	/**
	 * Creates and returns a CompoundTag containing the necessary information to spawn a tile of this type.
	 */
	public static function createNBT(Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : CompoundTag{
		if(static::class === self::class){
			throw new \BadMethodCallException(__METHOD__ . " must be called from the scope of a child class");
		}
		$nbt = new CompoundTag("", [
			new StringTag(self::TAG_ID, static::getSaveId()),
			new IntTag(self::TAG_X, (int) $pos->x),
			new IntTag(self::TAG_Y, (int) $pos->y),
			new IntTag(self::TAG_Z, (int) $pos->z)
		]);

		static::createAdditionalNBT($nbt, $pos, $face, $item, $player);

		if($item !== null){
			$customBlockData = $item->getCustomBlockData();
			if($customBlockData !== null){
				foreach($customBlockData as $customBlockDataTag){
					$nbt->setTag(clone $customBlockDataTag);
				}
			}
		}

		return $nbt;
	}

	/**
	 * Called by createNBT() to allow descendent classes to add their own base NBT using the parameters provided.
	 */
	protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{

	}

	public function getBlock() : Block{
		return $this->level->getBlockAt($this->x, $this->y, $this->z);
	}

	public function onUpdate() : bool{
		return false;
	}

	final public function scheduleUpdate() : void{
		if($this->closed){
			throw new \InvalidStateException("Cannot schedule update on garbage tile " . get_class($this));
		}
		$this->level->updateTiles[$this->id] = $this;
	}

	public function isClosed() : bool{
		return $this->closed;
	}

	public function __destruct(){
		$this->close();
	}

	public function close() : void{
		if(!$this->closed){
			$this->closed = true;

			if($this->isValid()){
				$this->level->removeTile($this);
				$this->setLevel(null);
			}
		}
	}

	public function getName() : string{
		return $this->name;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use function assert;

class Banner extends Spawnable implements Nameable{
	use NameableTrait {
		addAdditionalSpawnData as addNameSpawnData;
		createAdditionalNBT as createNameNBT;
	}

	public const TAG_BASE = "Base";
	public const TAG_PATTERNS = "Patterns";
	public const TAG_PATTERN_COLOR = "Color";
	public const TAG_PATTERN_NAME = "Pattern";

	public const PATTERN_BOTTOM_STRIPE = "bs";
	public const PATTERN_TOP_STRIPE = "ts";
	public const PATTERN_LEFT_STRIPE = "ls";
	public const PATTERN_RIGHT_STRIPE = "rs";
	public const PATTERN_CENTER_STRIPE = "cs";
	public const PATTERN_MIDDLE_STRIPE = "ms";
	public const PATTERN_DOWN_RIGHT_STRIPE = "drs";
	public const PATTERN_DOWN_LEFT_STRIPE = "dls";
	public const PATTERN_SMALL_STRIPES = "ss";
	public const PATTERN_DIAGONAL_CROSS = "cr";
	public const PATTERN_SQUARE_CROSS = "sc";
	public const PATTERN_LEFT_OF_DIAGONAL = "ld";
	public const PATTERN_RIGHT_OF_UPSIDE_DOWN_DIAGONAL = "rud";
	public const PATTERN_LEFT_OF_UPSIDE_DOWN_DIAGONAL = "lud";
	public const PATTERN_RIGHT_OF_DIAGONAL = "rd";
	public const PATTERN_VERTICAL_HALF_LEFT = "vh";
	public const PATTERN_VERTICAL_HALF_RIGHT = "vhr";
	public const PATTERN_HORIZONTAL_HALF_TOP = "hh";
	public const PATTERN_HORIZONTAL_HALF_BOTTOM = "hhb";
	public const PATTERN_BOTTOM_LEFT_CORNER = "bl";
	public const PATTERN_BOTTOM_RIGHT_CORNER = "br";
	public const PATTERN_TOP_LEFT_CORNER = "tl";
	public const PATTERN_TOP_RIGHT_CORNER = "tr";
	public const PATTERN_BOTTOM_TRIANGLE = "bt";
	public const PATTERN_TOP_TRIANGLE = "tt";
	public const PATTERN_BOTTOM_TRIANGLE_SAWTOOTH = "bts";
	public const PATTERN_TOP_TRIANGLE_SAWTOOTH = "tts";
	public const PATTERN_MIDDLE_CIRCLE = "mc";
	public const PATTERN_MIDDLE_RHOMBUS = "mr";
	public const PATTERN_BORDER = "bo";
	public const PATTERN_CURLY_BORDER = "cbo";
	public const PATTERN_BRICK = "bri";
	public const PATTERN_GRADIENT = "gra";
	public const PATTERN_GRADIENT_UPSIDE_DOWN = "gru";
	public const PATTERN_CREEPER = "cre";
	public const PATTERN_SKULL = "sku";
	public const PATTERN_FLOWER = "flo";
	public const PATTERN_MOJANG = "moj";

	public const COLOR_BLACK = 0;
	public const COLOR_RED = 1;
	public const COLOR_GREEN = 2;
	public const COLOR_BROWN = 3;
	public const COLOR_BLUE = 4;
	public const COLOR_PURPLE = 5;
	public const COLOR_CYAN = 6;
	public const COLOR_LIGHT_GRAY = 7;
	public const COLOR_GRAY = 8;
	public const COLOR_PINK = 9;
	public const COLOR_LIME = 10;
	public const COLOR_YELLOW = 11;
	public const COLOR_LIGHT_BLUE = 12;
	public const COLOR_MAGENTA = 13;
	public const COLOR_ORANGE = 14;
	public const COLOR_WHITE = 15;

	/** @var int */
	private $baseColor;
	/**
	 * @var ListTag
	 * TODO: break this down further and remove runtime NBT from here entirely
	 */
	private $patterns;

	protected function readSaveData(CompoundTag $nbt) : void{
		$this->baseColor = $nbt->getInt(self::TAG_BASE, self::COLOR_BLACK, true);
		$this->patterns = $nbt->getListTag(self::TAG_PATTERNS) ?? new ListTag(self::TAG_PATTERNS);
		$this->loadName($nbt);
	}

	protected function writeSaveData(CompoundTag $nbt) : void{
		$nbt->setInt(self::TAG_BASE, $this->baseColor);
		$nbt->setTag($this->patterns);
		$this->saveName($nbt);
	}

	protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
		$nbt->setInt(self::TAG_BASE, $this->baseColor);
		$nbt->setTag($this->patterns);
		$this->addNameSpawnData($nbt);
	}

	/**
	 * Returns the color of the banner base.
	 */
	public function getBaseColor() : int{
		return $this->baseColor;
	}

	/**
	 * Sets the color of the banner base.
	 */
	public function setBaseColor(int $color) : void{
		$this->baseColor = $color;
		$this->onChanged();
	}

	/**
	 * Applies a new pattern on the banner with the given color.
	 *
	 * @return int ID of pattern.
	 */
	public function addPattern(string $pattern, int $color) : int{
		$this->patterns->push(new CompoundTag("", [
			new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f),
			new StringTag(self::TAG_PATTERN_NAME, $pattern)
		]));

		$this->onChanged();
		return $this->patterns->count() - 1; //Last offset in the list
	}

	/**
	 * Returns whether a pattern with the given ID exists on the banner or not.
	 */
	public function patternExists(int $patternId) : bool{
		return $this->patterns->isset($patternId);
	}

	/**
	 * Returns the data of a pattern with the given ID.
	 *
	 * @return mixed[]
	 * @phpstan-return array{Color?: int, Pattern?: string}
	 */
	public function getPatternData(int $patternId) : array{
		if(!$this->patternExists($patternId)){
			return [];
		}

		$patternTag = $this->patterns->get($patternId);
		assert($patternTag instanceof CompoundTag);

		return [
			self::TAG_PATTERN_COLOR => $patternTag->getInt(self::TAG_PATTERN_COLOR),
			self::TAG_PATTERN_NAME => $patternTag->getString(self::TAG_PATTERN_NAME)
		];
	}

	/**
	 * Changes the pattern of a previously existing pattern.
	 *
	 * @return bool indicating success.
	 */
	public function changePattern(int $patternId, string $pattern, int $color) : bool{
		if(!$this->patternExists($patternId)){
			return false;
		}

		$this->patterns->set($patternId, new CompoundTag("", [
			new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f),
			new StringTag(self::TAG_PATTERN_NAME, $pattern)
		]));

		$this->onChanged();
		return true;
	}

	/**
	 * Deletes a pattern from the banner with the given ID.
	 *
	 * @return bool indicating whether the pattern existed or not.
	 */
	public function deletePattern(int $patternId) : bool{
		if(!$this->patternExists($patternId)){
			return false;
		}

		$this->patterns->remove($patternId);

		$this->onChanged();
		return true;
	}

	/**
	 * Deletes the top most pattern of the banner.
	 *
	 * @return bool indicating whether the banner was empty or not.
	 */
	public function deleteTopPattern() : bool{
		return $this->deletePattern($this->getPatternCount() - 1);
	}

	/**
	 * Deletes the bottom pattern of the banner.
	 *
	 * @return bool indicating whether the banner was empty or not.
	 */
	public function deleteBottomPattern() : bool{
		return $this->deletePattern(0);
	}

	/**
	 * Returns the total count of patterns on this banner.
	 */
	public function getPatternCount() : int{
		return $this->patterns->count();
	}

	public function getPatterns() : ListTag{
		return $this->patterns;
	}

	protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{
		$nbt->setInt(self::TAG_BASE, $item !== null ? $item->getDamage() & 0x0f : 0);

		if($item !== null){
			if($item->getNamedTag()->hasTag(self::TAG_PATTERNS, ListTag::class)){
				$nbt->setTag($item->getNamedTag()->getListTag(self::TAG_PATTERNS));
			}

			self::createNameNBT($nbt, $pos, $face, $item, $player);
		}
	}

	public function getDefaultName() : string{
		return "Banner";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\level\Level;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\Player;

abstract class Spawnable extends Tile{
	/** @var string|null */
	private $spawnCompoundCache = null;
	/** @var NetworkLittleEndianNBTStream|null */
	private static $nbtWriter = null;

	public function createSpawnPacket() : BlockActorDataPacket{
		$pk = new BlockActorDataPacket();
		$pk->x = $this->x;
		$pk->y = $this->y;
		$pk->z = $this->z;
		$pk->namedtag = $this->getSerializedSpawnCompound();

		return $pk;
	}

	public function spawnTo(Player $player) : bool{
		if($this->closed){
			return false;
		}

		$player->dataPacket($this->createSpawnPacket());

		return true;
	}

	public function __construct(Level $level, CompoundTag $nbt){
		parent::__construct($level, $nbt);
		$this->spawnToAll();
	}

	/**
	 * @return void
	 */
	public function spawnToAll(){
		if($this->closed){
			return;
		}

		$this->level->broadcastPacketToViewers($this, $this->createSpawnPacket());
	}

	/**
	 * Performs actions needed when the tile is modified, such as clearing caches and respawning the tile to players.
	 * WARNING: This MUST be called to clear spawn-compound and chunk caches when the tile's spawn compound has changed!
	 */
	protected function onChanged() : void{
		$this->spawnCompoundCache = null;
		$this->spawnToAll();

		$this->level->clearChunkCache($this->getFloorX() >> 4, $this->getFloorZ() >> 4);
	}

	/**
	 * Returns encoded NBT (varint, little-endian) used to spawn this tile to clients. Uses cache where possible,
	 * populates cache if it is null.
	 *
	 * @return string encoded NBT
	 */
	final public function getSerializedSpawnCompound() : string{
		if($this->spawnCompoundCache === null){
			if(self::$nbtWriter === null){
				self::$nbtWriter = new NetworkLittleEndianNBTStream();
			}

			$this->spawnCompoundCache = self::$nbtWriter->write($this->getSpawnCompound());
		}

		return $this->spawnCompoundCache;
	}

	final public function getSpawnCompound() : CompoundTag{
		$nbt = new CompoundTag("", [
			new StringTag(self::TAG_ID, static::getSaveId()),
			new IntTag(self::TAG_X, $this->x),
			new IntTag(self::TAG_Y, $this->y),
			new IntTag(self::TAG_Z, $this->z)
		]);
		$this->addAdditionalSpawnData($nbt);
		return $nbt;
	}

	/**
	 * An extension to getSpawnCompound() for
	 * further modifying the generic tile NBT.
	 */
	abstract protected function addAdditionalSpawnData(CompoundTag $nbt) : void;

	/**
	 * Called when a player updates a block entity's NBT data
	 * for example when writing on a sign.
	 *
	 * @return bool indication of success, will respawn the tile to the player if false.
	 */
	public function updateCompoundTag(CompoundTag $nbt, Player $player) : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;

/**
 * This trait implements most methods in the {@link Nameable} interface. It should only be used by Tiles.
 */
trait NameableTrait{
	/** @var string|null */
	private $customName;

	abstract public function getDefaultName() : string;

	public function getName() : string{
		return $this->customName ?? $this->getDefaultName();
	}

	public function setName(string $name) : void{
		if($name === ""){
			$this->customName = null;
		}else{
			$this->customName = $name;
		}
	}

	public function hasName() : bool{
		return $this->customName !== null;
	}

	protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{
		if($item !== null and $item->hasCustomName()){
			$nbt->setString(Nameable::TAG_CUSTOM_NAME, $item->getCustomName());
		}
	}

	public function addAdditionalSpawnData(CompoundTag $nbt) : void{
		if($this->customName !== null){
			$nbt->setString(Nameable::TAG_CUSTOM_NAME, $this->customName);
		}
	}

	protected function loadName(CompoundTag $tag) : void{
		if($tag->hasTag(Nameable::TAG_CUSTOM_NAME, StringTag::class)){
			$this->customName = $tag->getString(Nameable::TAG_CUSTOM_NAME);
		}
	}

	protected function saveName(CompoundTag $tag) : void{
		if($this->customName !== null){
			$tag->setString(Nameable::TAG_CUSTOM_NAME, $this->customName);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

interface Nameable{
	public const TAG_CUSTOM_NAME = "CustomName";

	public function getDefaultName() : string;

	public function getName() : string;

	/**
	 * @return void
	 */
	public function setName(string $str);

	public function hasName() : bool;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player;

class Bed extends Spawnable{
	public const TAG_COLOR = "color";
	/** @var int */
	private $color = 14; //default to old red

	public function getColor() : int{
		return $this->color;
	}

	/**
	 * @return void
	 */
	public function setColor(int $color){
		$this->color = $color & 0xf;
		$this->onChanged();
	}

	protected function readSaveData(CompoundTag $nbt) : void{
		$this->color = $nbt->getByte(self::TAG_COLOR, 14, true);
	}

	protected function writeSaveData(CompoundTag $nbt) : void{
		$nbt->setByte(self::TAG_COLOR, $this->color);
	}

	protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
		$nbt->setByte(self::TAG_COLOR, $this->color);
	}

	protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{
		if($item !== null){
			$nbt->setByte(self::TAG_COLOR, $item->getDamage());
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\inventory\ChestInventory;
use pocketmine\inventory\DoubleChestInventory;
use pocketmine\inventory\InventoryHolder;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;

class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
	use NameableTrait {
		addAdditionalSpawnData as addNameSpawnData;
	}
	use ContainerTrait;

	public const TAG_PAIRX = "pairx";
	public const TAG_PAIRZ = "pairz";
	public const TAG_PAIR_LEAD = "pairlead";

	/** @var ChestInventory */
	protected $inventory;
	/** @var DoubleChestInventory|null */
	protected $doubleInventory = null;

	/** @var int|null */
	private $pairX;
	/** @var int|null */
	private $pairZ;

	protected function readSaveData(CompoundTag $nbt) : void{
		if($nbt->hasTag(self::TAG_PAIRX, IntTag::class) and $nbt->hasTag(self::TAG_PAIRZ, IntTag::class)){
			$this->pairX = $nbt->getInt(self::TAG_PAIRX);
			$this->pairZ = $nbt->getInt(self::TAG_PAIRZ);
		}
		$this->loadName($nbt);

		$this->inventory = new ChestInventory($this);
		$this->loadItems($nbt);
	}

	protected function writeSaveData(CompoundTag $nbt) : void{
		if($this->isPaired()){
			$nbt->setInt(self::TAG_PAIRX, $this->pairX);
			$nbt->setInt(self::TAG_PAIRZ, $this->pairZ);
		}
		$this->saveName($nbt);
		$this->saveItems($nbt);
	}

	public function getCleanedNBT() : ?CompoundTag{
		$tag = parent::getCleanedNBT();
		if($tag !== null){
			//TODO: replace this with a purpose flag on writeSaveData()
			$tag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
		}
		return $tag;
	}

	public function close() : void{
		if(!$this->closed){
			$this->inventory->removeAllViewers(true);

			if($this->doubleInventory !== null){
				if($this->isPaired() and $this->level->isChunkLoaded($this->pairX >> 4, $this->pairZ >> 4)){
					$this->doubleInventory->removeAllViewers(true);
					$this->doubleInventory->invalidate();
					if(($pair = $this->getPair()) !== null){
						$pair->doubleInventory = null;
					}
				}
				$this->doubleInventory = null;
			}

			$this->inventory = null;

			parent::close();
		}
	}

	/**
	 * @return ChestInventory|DoubleChestInventory
	 */
	public function getInventory(){
		if($this->isPaired() and $this->doubleInventory === null){
			$this->checkPairing();
		}
		return $this->doubleInventory instanceof DoubleChestInventory ? $this->doubleInventory : $this->inventory;
	}

	/**
	 * @return ChestInventory
	 */
	public function getRealInventory(){
		return $this->inventory;
	}

	/**
	 * @return void
	 */
	protected function checkPairing(){
		if($this->isPaired() and !$this->getLevel()->isInLoadedTerrain(new Vector3($this->pairX, $this->y, $this->pairZ))){
			//paired to a tile in an unloaded chunk
			$this->doubleInventory = null;

		}elseif(($pair = $this->getPair()) instanceof Chest){
			if(!$pair->isPaired()){
				$pair->createPair($this);
				$pair->checkPairing();
			}
			if($this->doubleInventory === null){
				if($pair->doubleInventory !== null){
					$this->doubleInventory = $pair->doubleInventory;
				}else{
					if(($pair->x + ($pair->z << 15)) > ($this->x + ($this->z << 15))){ //Order them correctly
						$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($pair, $this);
					}else{
						$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($this, $pair);
					}
				}
			}
		}else{
			$this->doubleInventory = null;
			$this->pairX = $this->pairZ = null;
		}
	}

	public function getDefaultName() : string{
		return "Chest";
	}

	/**
	 * @return bool
	 */
	public function isPaired(){
		return $this->pairX !== null and $this->pairZ !== null;
	}

	public function getPair() : ?Chest{
		if($this->isPaired()){
			$tile = $this->getLevel()->getTileAt($this->pairX, $this->y, $this->pairZ);
			if($tile instanceof Chest){
				return $tile;
			}
		}

		return null;
	}

	/**
	 * @return bool
	 */
	public function pairWith(Chest $tile){
		if($this->isPaired() or $tile->isPaired()){
			return false;
		}

		$this->createPair($tile);

		$this->onChanged();
		$tile->onChanged();
		$this->checkPairing();

		return true;
	}

	private function createPair(Chest $tile) : void{
		$this->pairX = $tile->x;
		$this->pairZ = $tile->z;

		$tile->pairX = $this->x;
		$tile->pairZ = $this->z;
	}

	/**
	 * @return bool
	 */
	public function unpair(){
		if(!$this->isPaired()){
			return false;
		}

		$tile = $this->getPair();
		$this->pairX = $this->pairZ = null;

		$this->onChanged();

		if($tile instanceof Chest){
			$tile->pairX = $tile->pairZ = null;
			$tile->checkPairing();
			$tile->onChanged();
		}
		$this->checkPairing();

		return true;
	}

	protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
		if($this->isPaired()){
			$nbt->setInt(self::TAG_PAIRX, $this->pairX);
			$nbt->setInt(self::TAG_PAIRZ, $this->pairZ);
		}

		$this->addNameSpawnData($nbt);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\inventory\Inventory;
use pocketmine\item\Item;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;

/**
 * This trait implements most methods in the {@link Container} interface. It should only be used by Tiles.
 */
trait ContainerTrait{
	/** @var string|null */
	private $lock;

	/**
	 * @return Inventory
	 */
	abstract public function getRealInventory();

	protected function loadItems(CompoundTag $tag) : void{
		if($tag->hasTag(Container::TAG_ITEMS, ListTag::class)){
			$inventoryTag = $tag->getListTag(Container::TAG_ITEMS);

			$inventory = $this->getRealInventory();
			/** @var CompoundTag $itemNBT */
			foreach($inventoryTag as $itemNBT){
				$inventory->setItem($itemNBT->getByte("Slot"), Item::nbtDeserialize($itemNBT));
			}
		}

		if($tag->hasTag(Container::TAG_LOCK, StringTag::class)){
			$this->lock = $tag->getString(Container::TAG_LOCK);
		}
	}

	protected function saveItems(CompoundTag $tag) : void{
		$items = [];
		foreach($this->getRealInventory()->getContents() as $slot => $item){
			$items[] = $item->nbtSerialize($slot);
		}

		$tag->setTag(new ListTag(Container::TAG_ITEMS, $items, NBT::TAG_Compound));

		if($this->lock !== null){
			$tag->setString(Container::TAG_LOCK, $this->lock);
		}
	}

	/**
	 * @see Container::canOpenWith()
	 */
	public function canOpenWith(string $key) : bool{
		return $this->lock === null or $this->lock === $key;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\inventory\Inventory;

interface Container{
	public const TAG_ITEMS = "Items";
	public const TAG_LOCK = "Lock";

	/**
	 * @return Inventory
	 */
	public function getInventory();

	/**
	 * @return Inventory
	 */
	public function getRealInventory();

	/**
	 * Returns whether this container can be opened by an item with the given custom name.
	 */
	public function canOpenWith(string $key) : bool;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

class EnchantTable extends Spawnable implements Nameable{
	use NameableTrait{
		loadName as readSaveData;
		saveName as writeSaveData;
	}

	public function getDefaultName() : string{
		return "Enchanting Table";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\nbt\tag\CompoundTag;

class EnderChest extends Spawnable{

	protected function readSaveData(CompoundTag $nbt) : void{

	}

	protected function writeSaveData(CompoundTag $nbt) : void{

	}

	protected function addAdditionalSpawnData(CompoundTag $nbt) : void{

	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\nbt\tag\CompoundTag;

class FlowerPot extends Spawnable{
	public const TAG_ITEM = "item";
	public const TAG_ITEM_DATA = "mData";

	/** @var Item */
	private $item;

	protected function readSaveData(CompoundTag $nbt) : void{
		$this->item = ItemFactory::get($nbt->getShort(self::TAG_ITEM, 0, true), $nbt->getInt(self::TAG_ITEM_DATA, 0, true), 1);
	}

	protected function writeSaveData(CompoundTag $nbt) : void{
		$nbt->setShort(self::TAG_ITEM, $this->item->getId());
		$nbt->setInt(self::TAG_ITEM_DATA, $this->item->getDamage());
	}

	public function canAddItem(Item $item) : bool{
		if(!$this->isEmpty()){
			return false;
		}
		switch($item->getId()){
			/** @noinspection PhpMissingBreakStatementInspection */
			case Item::TALL_GRASS:
				if($item->getDamage() === 1){
					return false;
				}
			case Item::SAPLING:
			case Item::DEAD_BUSH:
			case Item::DANDELION:
			case Item::RED_FLOWER:
			case Item::BROWN_MUSHROOM:
			case Item::RED_MUSHROOM:
			case Item::CACTUS:
				return true;
			default:
				return false;
		}
	}

	public function getItem() : Item{
		return clone $this->item;
	}

	/**
	 * @return void
	 */
	public function setItem(Item $item){
		$this->item = clone $item;
		$this->onChanged();
	}

	/**
	 * @return void
	 */
	public function removeItem(){
		$this->setItem(ItemFactory::get(Item::AIR, 0, 0));
	}

	public function isEmpty() : bool{
		return $this->getItem()->isNull();
	}

	protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
		$nbt->setShort(self::TAG_ITEM, $this->item->getId());
		$nbt->setInt(self::TAG_ITEM_DATA, $this->item->getDamage());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\event\inventory\FurnaceBurnEvent;
use pocketmine\event\inventory\FurnaceSmeltEvent;
use pocketmine\inventory\FurnaceInventory;
use pocketmine\inventory\FurnaceRecipe;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\InventoryEventProcessor;
use pocketmine\inventory\InventoryHolder;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
use function ceil;
use function count;
use function max;

class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
	use NameableTrait {
		addAdditionalSpawnData as addNameSpawnData;
	}
	use ContainerTrait;

	public const TAG_BURN_TIME = "BurnTime";
	public const TAG_COOK_TIME = "CookTime";
	public const TAG_MAX_TIME = "MaxTime";

	/** @var FurnaceInventory */
	protected $inventory;
	/** @var int */
	private $burnTime;
	/** @var int */
	private $cookTime;
	/** @var int */
	private $maxTime;

	public function __construct(Level $level, CompoundTag $nbt){
		parent::__construct($level, $nbt);
		if($this->burnTime > 0){
			$this->scheduleUpdate();
		}
	}

	protected function readSaveData(CompoundTag $nbt) : void{
		$this->burnTime = max(0, $nbt->getShort(self::TAG_BURN_TIME, 0, true));

		$this->cookTime = $nbt->getShort(self::TAG_COOK_TIME, 0, true);
		if($this->burnTime === 0){
			$this->cookTime = 0;
		}

		$this->maxTime = $nbt->getShort(self::TAG_MAX_TIME, 0, true);
		if($this->maxTime === 0){
			$this->maxTime = $this->burnTime;
		}

		$this->loadName($nbt);

		$this->inventory = new FurnaceInventory($this);
		$this->loadItems($nbt);

		$this->inventory->setEventProcessor(new class($this) implements InventoryEventProcessor{
			/** @var Furnace */
			private $furnace;

			public function __construct(Furnace $furnace){
				$this->furnace = $furnace;
			}

			public function onSlotChange(Inventory $inventory, int $slot, Item $oldItem, Item $newItem) : ?Item{
				$this->furnace->scheduleUpdate();
				return $newItem;
			}
		});
	}

	protected function writeSaveData(CompoundTag $nbt) : void{
		$nbt->setShort(self::TAG_BURN_TIME, $this->burnTime);
		$nbt->setShort(self::TAG_COOK_TIME, $this->cookTime);
		$nbt->setShort(self::TAG_MAX_TIME, $this->maxTime);
		$this->saveName($nbt);
		$this->saveItems($nbt);
	}

	public function getDefaultName() : string{
		return "Furnace";
	}

	public function close() : void{
		if(!$this->closed){
			$this->inventory->removeAllViewers(true);
			$this->inventory = null;

			parent::close();
		}
	}

	/**
	 * @return FurnaceInventory
	 */
	public function getInventory(){
		return $this->inventory;
	}

	/**
	 * @return FurnaceInventory
	 */
	public function getRealInventory(){
		return $this->getInventory();
	}

	/**
	 * @return void
	 */
	protected function checkFuel(Item $fuel){
		$ev = new FurnaceBurnEvent($this, $fuel, $fuel->getFuelTime());
		$ev->call();
		if($ev->isCancelled()){
			return;
		}

		$this->maxTime = $this->burnTime = $ev->getBurnTime();

		if($this->getBlock()->getId() === Block::FURNACE){
			$this->getLevel()->setBlock($this, BlockFactory::get(Block::BURNING_FURNACE, $this->getBlock()->getDamage()), true);
		}

		if($this->burnTime > 0 and $ev->isBurning()){
			$fuel->pop();
			$this->inventory->setFuel($fuel);
		}
	}

	protected function getFuelTicksLeft() : int{
		return $this->maxTime > 0 ? (int) ceil($this->burnTime / $this->maxTime * 200) : 0;
	}

	public function onUpdate() : bool{
		if($this->closed){
			return false;
		}

		$this->timings->startTiming();

		$prevCookTime = $this->cookTime;
		$prevFuelTicksLeft = $this->getFuelTicksLeft();

		$ret = false;

		$fuel = $this->inventory->getFuel();
		$raw = $this->inventory->getSmelting();
		$product = $this->inventory->getResult();
		$smelt = $this->server->getCraftingManager()->matchFurnaceRecipe($raw);
		$canSmelt = ($smelt instanceof FurnaceRecipe and $raw->getCount() > 0 and (($smelt->getResult()->equals($product) and $product->getCount() < $product->getMaxStackSize()) or $product->isNull()));

		if($this->burnTime <= 0 and $canSmelt and $fuel->getFuelTime() > 0 and $fuel->getCount() > 0){
			$this->checkFuel($fuel);
		}

		if($this->burnTime > 0){
			--$this->burnTime;

			if($smelt instanceof FurnaceRecipe and $canSmelt){
				++$this->cookTime;

				if($this->cookTime >= 200){ //10 seconds
					$product = ItemFactory::get($smelt->getResult()->getId(), $smelt->getResult()->getDamage(), $product->getCount() + 1);

					$ev = new FurnaceSmeltEvent($this, $raw, $product);
					$ev->call();

					if(!$ev->isCancelled()){
						$this->inventory->setResult($ev->getResult());
						$raw->pop();
						$this->inventory->setSmelting($raw);
					}

					$this->cookTime -= 200;
				}
			}elseif($this->burnTime <= 0){
				$this->burnTime = $this->cookTime = $this->maxTime = 0;
			}else{
				$this->cookTime = 0;
			}
			$ret = true;
		}else{
			if($this->getBlock()->getId() === Block::BURNING_FURNACE){
				$this->getLevel()->setBlock($this, BlockFactory::get(Block::FURNACE, $this->getBlock()->getDamage()), true);
			}
			$this->burnTime = $this->cookTime = $this->maxTime = 0;
		}

		/** @var ContainerSetDataPacket[] $packets */
		$packets = [];
		if($prevCookTime !== $this->cookTime){
			$pk = new ContainerSetDataPacket();
			$pk->property = ContainerSetDataPacket::PROPERTY_FURNACE_TICK_COUNT;
			$pk->value = $this->cookTime;
			$packets[] = $pk;
		}

		$fuelTicksLeft = $this->getFuelTicksLeft();
		if($prevFuelTicksLeft !== $fuelTicksLeft){
			$pk = new ContainerSetDataPacket();
			$pk->property = ContainerSetDataPacket::PROPERTY_FURNACE_LIT_TIME;
			$pk->value = $fuelTicksLeft;
			$packets[] = $pk;
		}

		if(count($packets) > 0){
			foreach($this->getInventory()->getViewers() as $player){
				$windowId = $player->getWindowId($this->getInventory());
				if($windowId > 0){
					foreach($packets as $pk){
						$pk->windowId = $windowId;
						$player->dataPacket(clone $pk);
					}
				}
			}
		}

		$this->timings->stopTiming();

		return $ret;
	}

	protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
		$nbt->setShort(self::TAG_BURN_TIME, $this->burnTime);
		$nbt->setShort(self::TAG_COOK_TIME, $this->cookTime);

		$this->addNameSpawnData($nbt);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\nbt\tag\CompoundTag;

class ItemFrame extends Spawnable{
	public const TAG_ITEM_ROTATION = "ItemRotation";
	public const TAG_ITEM_DROP_CHANCE = "ItemDropChance";
	public const TAG_ITEM = "Item";

	/** @var Item */
	private $item;
	/** @var int */
	private $itemRotation;
	/** @var float */
	private $itemDropChance;

	protected function readSaveData(CompoundTag $nbt) : void{
		if(($itemTag = $nbt->getCompoundTag(self::TAG_ITEM)) !== null){
			$this->item = Item::nbtDeserialize($itemTag);
		}else{
			$this->item = ItemFactory::get(Item::AIR, 0, 0);
		}
		$this->itemRotation = $nbt->getByte(self::TAG_ITEM_ROTATION, 0, true);
		$this->itemDropChance = $nbt->getFloat(self::TAG_ITEM_DROP_CHANCE, 1.0, true);
	}

	protected function writeSaveData(CompoundTag $nbt) : void{
		$nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance);
		$nbt->setByte(self::TAG_ITEM_ROTATION, $this->itemRotation);
		$nbt->setTag($this->item->nbtSerialize(-1, self::TAG_ITEM));
	}

	public function hasItem() : bool{
		return !$this->item->isNull();
	}

	public function getItem() : Item{
		return clone $this->item;
	}

	/**
	 * @return void
	 */
	public function setItem(Item $item = null){
		if($item !== null and !$item->isNull()){
			$this->item = clone $item;
		}else{
			$this->item = ItemFactory::get(Item::AIR, 0, 0);
		}
		$this->onChanged();
	}

	public function getItemRotation() : int{
		return $this->itemRotation;
	}

	/**
	 * @return void
	 */
	public function setItemRotation(int $rotation){
		$this->itemRotation = $rotation;
		$this->onChanged();
	}

	public function getItemDropChance() : float{
		return $this->itemDropChance;
	}

	/**
	 * @return void
	 */
	public function setItemDropChance(float $chance){
		$this->itemDropChance = $chance;
		$this->onChanged();
	}

	protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
		$nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance);
		$nbt->setByte(self::TAG_ITEM_ROTATION, $this->itemRotation);
		$nbt->setTag($this->item->nbtSerialize(-1, self::TAG_ITEM));
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\event\block\SignChangeEvent;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use function array_map;
use function array_pad;
use function array_slice;
use function explode;
use function implode;
use function mb_check_encoding;
use function mb_scrub;
use function sprintf;
use function strlen;

class Sign extends Spawnable{
	public const TAG_TEXT_BLOB = "Text";
	public const TAG_TEXT_LINE = "Text%d"; //sprintf()able

	/**
	 * @return string[]
	 */
	private static function fixTextBlob(string $blob) : array{
		return array_slice(array_pad(explode("\n", $blob), 4, ""), 0, 4);
	}

	/** @var string[] */
	protected $text = ["", "", "", ""];

	protected function readSaveData(CompoundTag $nbt) : void{
		if($nbt->hasTag(self::TAG_TEXT_BLOB, StringTag::class)){ //MCPE 1.2 save format
			$this->text = self::fixTextBlob($nbt->getString(self::TAG_TEXT_BLOB));
		}else{
			for($i = 1; $i <= 4; ++$i){
				$textKey = sprintf(self::TAG_TEXT_LINE, $i);
				if($nbt->hasTag($textKey, StringTag::class)){
					$this->text[$i - 1] = $nbt->getString($textKey);
				}
			}
		}
		$this->text = array_map(function(string $line) : string{
			return mb_scrub($line, 'UTF-8');
		}, $this->text);
	}

	protected function writeSaveData(CompoundTag $nbt) : void{
		$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));

		for($i = 1; $i <= 4; ++$i){ //Backwards-compatibility
			$textKey = sprintf(self::TAG_TEXT_LINE, $i);
			$nbt->setString($textKey, $this->getLine($i - 1));
		}
	}

	/**
	 * Changes contents of the specific lines to the string provided.
	 * Leaves contents of the specific lines as is if null is provided.
	 */
	public function setText(?string $line1 = "", ?string $line2 = "", ?string $line3 = "", ?string $line4 = "") : void{
		if($line1 !== null){
			$this->setLine(0, $line1, false);
		}
		if($line2 !== null){
			$this->setLine(1, $line2, false);
		}
		if($line3 !== null){
			$this->setLine(2, $line3, false);
		}
		if($line4 !== null){
			$this->setLine(3, $line4, false);
		}

		$this->onChanged();
	}

	/**
	 * @param int    $index 0-3
	 */
	public function setLine(int $index, string $line, bool $update = true) : void{
		if($index < 0 or $index > 3){
			throw new \InvalidArgumentException("Index must be in the range 0-3!");
		}
		if(!mb_check_encoding($line, 'UTF-8')){
			throw new \InvalidArgumentException("Text must be valid UTF-8");
		}

		$this->text[$index] = $line;
		if($update){
			$this->onChanged();
		}
	}

	/**
	 * @param int $index 0-3
	 */
	public function getLine(int $index) : string{
		if($index < 0 or $index > 3){
			throw new \InvalidArgumentException("Index must be in the range 0-3!");
		}
		return $this->text[$index];
	}

	/**
	 * @return string[]
	 */
	public function getText() : array{
		return $this->text;
	}

	protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
		$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));
	}

	public function updateCompoundTag(CompoundTag $nbt, Player $player) : bool{
		if($nbt->getString("id") !== Tile::SIGN){
			return false;
		}

		if($nbt->hasTag(self::TAG_TEXT_BLOB, StringTag::class)){
			$lines = self::fixTextBlob($nbt->getString(self::TAG_TEXT_BLOB));
		}else{
			return false;
		}
		$size = 0;
		foreach($lines as $line){
			$size += strlen($line);
		}
		if($size > 1000){
			//trigger kick + IP ban - TODO: on 4.0 this will require a better fix
			throw new \UnexpectedValueException($player->getName() . " tried to write $size bytes of text onto a sign (bigger than max 1000)");
		}

		$removeFormat = $player->getRemoveFormat();

		$ev = new SignChangeEvent($this->getBlock(), $player, array_map(function(string $line) use ($removeFormat) : string{ return TextFormat::clean($line, $removeFormat); }, $lines));
		$ev->call();

		if(!$ev->isCancelled()){
			$this->setText(...$ev->getLines());

			return true;
		}else{
			return false;
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\tile;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player;
use function floor;

class Skull extends Spawnable{
	public const TYPE_SKELETON = 0;
	public const TYPE_WITHER = 1;
	public const TYPE_ZOMBIE = 2;
	public const TYPE_HUMAN = 3;
	public const TYPE_CREEPER = 4;
	public const TYPE_DRAGON = 5;

	public const TAG_SKULL_TYPE = "SkullType"; //TAG_Byte
	public const TAG_ROT = "Rot"; //TAG_Byte
	public const TAG_MOUTH_MOVING = "MouthMoving"; //TAG_Byte
	public const TAG_MOUTH_TICK_COUNT = "MouthTickCount"; //TAG_Int

	/** @var int */
	private $skullType;
	/** @var int */
	private $skullRotation;

	protected function readSaveData(CompoundTag $nbt) : void{
		$this->skullType = $nbt->getByte(self::TAG_SKULL_TYPE, self::TYPE_SKELETON, true);
		$this->skullRotation = $nbt->getByte(self::TAG_ROT, 0, true);
	}

	protected function writeSaveData(CompoundTag $nbt) : void{
		$nbt->setByte(self::TAG_SKULL_TYPE, $this->skullType);
		$nbt->setByte(self::TAG_ROT, $this->skullRotation);
	}

	/**
	 * @return void
	 */
	public function setType(int $type){
		$this->skullType = $type;
		$this->onChanged();
	}

	public function getType() : int{
		return $this->skullType;
	}

	protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
		$nbt->setByte(self::TAG_SKULL_TYPE, $this->skullType);
		$nbt->setByte(self::TAG_ROT, $this->skullRotation);
	}

	protected static function createAdditionalNBT(CompoundTag $nbt, Vector3 $pos, ?int $face = null, ?Item $item = null, ?Player $player = null) : void{
		$nbt->setByte(self::TAG_SKULL_TYPE, $item !== null ? $item->getDamage() : self::TYPE_SKELETON);

		$rot = 0;
		if($face === Vector3::SIDE_UP and $player !== null){
			$rot = floor(($player->yaw * 16 / 360) + 0.5) & 0x0F;
		}
		$nbt->setByte(self::TAG_ROT, $rot);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\level\Position;
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
use function min;

/**
 * Manages block registration and instance creation
 */
class BlockFactory{
	/**
	 * @var \SplFixedArray|Block[]
	 * @phpstan-var \SplFixedArray<Block>
	 */
	private static $fullList;

	/**
	 * @var \SplFixedArray|bool[]
	 * @phpstan-var \SplFixedArray<bool>
	 */
	public static $solid;
	/**
	 * @var \SplFixedArray|bool[]
	 * @phpstan-var \SplFixedArray<bool>
	 */
	public static $transparent;
	/**
	 * @var \SplFixedArray|float[]
	 * @phpstan-var \SplFixedArray<float>
	 */
	public static $hardness;
	/**
	 * @var \SplFixedArray|int[]
	 * @phpstan-var \SplFixedArray<int>
	 */
	public static $light;
	/**
	 * @var \SplFixedArray|int[]
	 * @phpstan-var \SplFixedArray<int>
	 */
	public static $lightFilter;
	/**
	 * @var \SplFixedArray|bool[]
	 * @phpstan-var \SplFixedArray<bool>
	 */
	public static $diffusesSkyLight;
	/**
	 * @var \SplFixedArray|float[]
	 * @phpstan-var \SplFixedArray<float>
	 */
	public static $blastResistance;

	/**
	 * Initializes the block factory. By default this is called only once on server start, however you may wish to use
	 * this if you need to reset the block factory back to its original defaults for whatever reason.
	 */
	public static function init() : void{
		self::$fullList = new \SplFixedArray(4096);

		self::$light = new \SplFixedArray(256);
		self::$lightFilter = new \SplFixedArray(256);
		self::$solid = new \SplFixedArray(256);
		self::$hardness = new \SplFixedArray(256);
		self::$transparent = new \SplFixedArray(256);
		self::$diffusesSkyLight = new \SplFixedArray(256);
		self::$blastResistance = new \SplFixedArray(256);

		self::registerBlock(new Air());
		self::registerBlock(new Stone());
		self::registerBlock(new Grass());
		self::registerBlock(new Dirt());
		self::registerBlock(new Cobblestone());
		self::registerBlock(new Planks());
		self::registerBlock(new Sapling());
		self::registerBlock(new Bedrock());
		self::registerBlock(new Water());
		self::registerBlock(new StillWater());
		self::registerBlock(new Lava());
		self::registerBlock(new StillLava());
		self::registerBlock(new Sand());
		self::registerBlock(new Gravel());
		self::registerBlock(new GoldOre());
		self::registerBlock(new IronOre());
		self::registerBlock(new CoalOre());
		self::registerBlock(new Wood());
		self::registerBlock(new Leaves());
		self::registerBlock(new Sponge());
		self::registerBlock(new Glass());
		self::registerBlock(new LapisOre());
		self::registerBlock(new Lapis());
		//TODO: DISPENSER
		self::registerBlock(new Sandstone());
		self::registerBlock(new NoteBlock());
		self::registerBlock(new Bed());
		self::registerBlock(new PoweredRail());
		self::registerBlock(new DetectorRail());
		//TODO: STICKY_PISTON
		self::registerBlock(new Cobweb());
		self::registerBlock(new TallGrass());
		self::registerBlock(new DeadBush());
		//TODO: PISTON
		//TODO: PISTONARMCOLLISION
		self::registerBlock(new Wool());

		self::registerBlock(new Dandelion());
		self::registerBlock(new Flower());
		self::registerBlock(new BrownMushroom());
		self::registerBlock(new RedMushroom());
		self::registerBlock(new Gold());
		self::registerBlock(new Iron());
		self::registerBlock(new DoubleStoneSlab());
		self::registerBlock(new StoneSlab());
		self::registerBlock(new Bricks());
		self::registerBlock(new TNT());
		self::registerBlock(new Bookshelf());
		self::registerBlock(new MossyCobblestone());
		self::registerBlock(new Obsidian());
		self::registerBlock(new Torch());
		self::registerBlock(new Fire());
		self::registerBlock(new MonsterSpawner());
		self::registerBlock(new WoodenStairs(Block::OAK_STAIRS, 0, "Oak Stairs"));
		self::registerBlock(new Chest());
		//TODO: REDSTONE_WIRE
		self::registerBlock(new DiamondOre());
		self::registerBlock(new Diamond());
		self::registerBlock(new CraftingTable());
		self::registerBlock(new Wheat());
		self::registerBlock(new Farmland());
		self::registerBlock(new Furnace());
		self::registerBlock(new BurningFurnace());
		self::registerBlock(new SignPost());
		self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door", Item::OAK_DOOR));
		self::registerBlock(new Ladder());
		self::registerBlock(new Rail());
		self::registerBlock(new CobblestoneStairs());
		self::registerBlock(new WallSign());
		self::registerBlock(new Lever());
		self::registerBlock(new StonePressurePlate());
		self::registerBlock(new IronDoor());
		self::registerBlock(new WoodenPressurePlate());
		self::registerBlock(new RedstoneOre());
		self::registerBlock(new GlowingRedstoneOre());
		self::registerBlock(new RedstoneTorchUnlit());
		self::registerBlock(new RedstoneTorch());
		self::registerBlock(new StoneButton());
		self::registerBlock(new SnowLayer());
		self::registerBlock(new Ice());
		self::registerBlock(new Snow());
		self::registerBlock(new Cactus());
		self::registerBlock(new Clay());
		self::registerBlock(new Sugarcane());
		//TODO: JUKEBOX
		self::registerBlock(new WoodenFence());
		self::registerBlock(new Pumpkin());
		self::registerBlock(new Netherrack());
		self::registerBlock(new SoulSand());
		self::registerBlock(new Glowstone());
		//TODO: PORTAL
		self::registerBlock(new LitPumpkin());
		self::registerBlock(new Cake());
		//TODO: REPEATER_BLOCK
		//TODO: POWERED_REPEATER
		self::registerBlock(new InvisibleBedrock());
		self::registerBlock(new Trapdoor());
		//TODO: MONSTER_EGG
		self::registerBlock(new StoneBricks());
		self::registerBlock(new BrownMushroomBlock());
		self::registerBlock(new RedMushroomBlock());
		self::registerBlock(new IronBars());
		self::registerBlock(new GlassPane());
		self::registerBlock(new Melon());
		self::registerBlock(new PumpkinStem());
		self::registerBlock(new MelonStem());
		self::registerBlock(new Vine());
		self::registerBlock(new FenceGate(Block::OAK_FENCE_GATE, 0, "Oak Fence Gate"));
		self::registerBlock(new BrickStairs());
		self::registerBlock(new StoneBrickStairs());
		self::registerBlock(new Mycelium());
		self::registerBlock(new WaterLily());
		self::registerBlock(new NetherBrick(Block::NETHER_BRICK_BLOCK, 0, "Nether Bricks"));
		self::registerBlock(new NetherBrickFence());
		self::registerBlock(new NetherBrickStairs());
		self::registerBlock(new NetherWartPlant());
		self::registerBlock(new EnchantingTable());
		self::registerBlock(new BrewingStand());
		//TODO: CAULDRON_BLOCK
		//TODO: END_PORTAL
		self::registerBlock(new EndPortalFrame());
		self::registerBlock(new EndStone());
		//TODO: DRAGON_EGG
		self::registerBlock(new RedstoneLamp());
		self::registerBlock(new LitRedstoneLamp());
		//TODO: DROPPER
		self::registerBlock(new ActivatorRail());
		self::registerBlock(new CocoaBlock());
		self::registerBlock(new SandstoneStairs());
		self::registerBlock(new EmeraldOre());
		self::registerBlock(new EnderChest());
		self::registerBlock(new TripwireHook());
		self::registerBlock(new Tripwire());
		self::registerBlock(new Emerald());
		self::registerBlock(new WoodenStairs(Block::SPRUCE_STAIRS, 0, "Spruce Stairs"));
		self::registerBlock(new WoodenStairs(Block::BIRCH_STAIRS, 0, "Birch Stairs"));
		self::registerBlock(new WoodenStairs(Block::JUNGLE_STAIRS, 0, "Jungle Stairs"));
		//TODO: COMMAND_BLOCK
		//TODO: BEACON
		self::registerBlock(new CobblestoneWall());
		self::registerBlock(new FlowerPot());
		self::registerBlock(new Carrot());
		self::registerBlock(new Potato());
		self::registerBlock(new WoodenButton());
		self::registerBlock(new Skull());
		self::registerBlock(new Anvil());
		self::registerBlock(new TrappedChest());
		self::registerBlock(new WeightedPressurePlateLight());
		self::registerBlock(new WeightedPressurePlateHeavy());
		//TODO: COMPARATOR_BLOCK
		//TODO: POWERED_COMPARATOR
		self::registerBlock(new DaylightSensor());
		self::registerBlock(new Redstone());
		self::registerBlock(new NetherQuartzOre());
		//TODO: HOPPER_BLOCK
		self::registerBlock(new Quartz());
		self::registerBlock(new QuartzStairs());
		self::registerBlock(new DoubleWoodenSlab());
		self::registerBlock(new WoodenSlab());
		self::registerBlock(new StainedClay());
		self::registerBlock(new StainedGlassPane());
		self::registerBlock(new Leaves2());
		self::registerBlock(new Wood2());
		self::registerBlock(new WoodenStairs(Block::ACACIA_STAIRS, 0, "Acacia Stairs"));
		self::registerBlock(new WoodenStairs(Block::DARK_OAK_STAIRS, 0, "Dark Oak Stairs"));
		//TODO: SLIME

		self::registerBlock(new IronTrapdoor());
		self::registerBlock(new Prismarine());
		self::registerBlock(new SeaLantern());
		self::registerBlock(new HayBale());
		self::registerBlock(new Carpet());
		self::registerBlock(new HardenedClay());
		self::registerBlock(new Coal());
		self::registerBlock(new PackedIce());
		self::registerBlock(new DoublePlant());
		self::registerBlock(new StandingBanner());
		self::registerBlock(new WallBanner());
		//TODO: DAYLIGHT_DETECTOR_INVERTED
		self::registerBlock(new RedSandstone());
		self::registerBlock(new RedSandstoneStairs());
		self::registerBlock(new DoubleStoneSlab2());
		self::registerBlock(new StoneSlab2());
		self::registerBlock(new FenceGate(Block::SPRUCE_FENCE_GATE, 0, "Spruce Fence Gate"));
		self::registerBlock(new FenceGate(Block::BIRCH_FENCE_GATE, 0, "Birch Fence Gate"));
		self::registerBlock(new FenceGate(Block::JUNGLE_FENCE_GATE, 0, "Jungle Fence Gate"));
		self::registerBlock(new FenceGate(Block::DARK_OAK_FENCE_GATE, 0, "Dark Oak Fence Gate"));
		self::registerBlock(new FenceGate(Block::ACACIA_FENCE_GATE, 0, "Acacia Fence Gate"));
		//TODO: REPEATING_COMMAND_BLOCK
		//TODO: CHAIN_COMMAND_BLOCK

		self::registerBlock(new WoodenDoor(Block::SPRUCE_DOOR_BLOCK, 0, "Spruce Door", Item::SPRUCE_DOOR));
		self::registerBlock(new WoodenDoor(Block::BIRCH_DOOR_BLOCK, 0, "Birch Door", Item::BIRCH_DOOR));
		self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door", Item::JUNGLE_DOOR));
		self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door", Item::ACACIA_DOOR));
		self::registerBlock(new WoodenDoor(Block::DARK_OAK_DOOR_BLOCK, 0, "Dark Oak Door", Item::DARK_OAK_DOOR));
		self::registerBlock(new GrassPath());
		self::registerBlock(new ItemFrame());
		//TODO: CHORUS_FLOWER
		self::registerBlock(new Purpur());

		self::registerBlock(new PurpurStairs());

		//TODO: UNDYED_SHULKER_BOX
		self::registerBlock(new EndStoneBricks());
		//TODO: FROSTED_ICE
		self::registerBlock(new EndRod());
		//TODO: END_GATEWAY

		self::registerBlock(new Magma());
		self::registerBlock(new NetherWartBlock());
		self::registerBlock(new NetherBrick(Block::RED_NETHER_BRICK, 0, "Red Nether Bricks"));
		self::registerBlock(new BoneBlock());

		//TODO: SHULKER_BOX
		self::registerBlock(new GlazedTerracotta(Block::PURPLE_GLAZED_TERRACOTTA, 0, "Purple Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::WHITE_GLAZED_TERRACOTTA, 0, "White Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::ORANGE_GLAZED_TERRACOTTA, 0, "Orange Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::MAGENTA_GLAZED_TERRACOTTA, 0, "Magenta Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::LIGHT_BLUE_GLAZED_TERRACOTTA, 0, "Light Blue Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::YELLOW_GLAZED_TERRACOTTA, 0, "Yellow Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::LIME_GLAZED_TERRACOTTA, 0, "Lime Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::PINK_GLAZED_TERRACOTTA, 0, "Pink Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::GRAY_GLAZED_TERRACOTTA, 0, "Grey Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::SILVER_GLAZED_TERRACOTTA, 0, "Light Grey Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::CYAN_GLAZED_TERRACOTTA, 0, "Cyan Glazed Terracotta"));

		self::registerBlock(new GlazedTerracotta(Block::BLUE_GLAZED_TERRACOTTA, 0, "Blue Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::BROWN_GLAZED_TERRACOTTA, 0, "Brown Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::GREEN_GLAZED_TERRACOTTA, 0, "Green Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::RED_GLAZED_TERRACOTTA, 0, "Red Glazed Terracotta"));
		self::registerBlock(new GlazedTerracotta(Block::BLACK_GLAZED_TERRACOTTA, 0, "Black Glazed Terracotta"));
		self::registerBlock(new Concrete());
		self::registerBlock(new ConcretePowder());

		//TODO: CHORUS_PLANT
		self::registerBlock(new StainedGlass());

		self::registerBlock(new Podzol());
		self::registerBlock(new Beetroot());
		self::registerBlock(new Stonecutter());
		self::registerBlock(new GlowingObsidian());
		self::registerBlock(new NetherReactor());
		self::registerBlock(new InfoUpdate(Block::INFO_UPDATE, 0, "update!"));
		self::registerBlock(new InfoUpdate(Block::INFO_UPDATE2, 0, "ate!upd"));
		//TODO: MOVINGBLOCK
		//TODO: OBSERVER
		//TODO: STRUCTURE_BLOCK

		self::registerBlock(new Reserved6(Block::RESERVED6, 0, "reserved6"));

		for($id = 0, $size = self::$fullList->getSize() >> 4; $id < $size; ++$id){
			if(self::$fullList[$id << 4] === null){
				self::registerBlock(new UnknownBlock($id));
			}
		}
	}

	public static function isInit() : bool{
		return self::$fullList !== null;
	}

	/**
	 * Registers a block type into the index. Plugins may use this method to register new block types or override
	 * existing ones.
	 *
	 * NOTE: If you are registering a new block type, you will need to add it to the creative inventory yourself - it
	 * will not automatically appear there.
	 *
	 * @param bool  $override Whether to override existing registrations
	 *
	 * @throws \RuntimeException if something attempted to override an already-registered block without specifying the
	 * $override parameter.
	 */
	public static function registerBlock(Block $block, bool $override = false) : void{
		$id = $block->getId();

		if(!$override and self::isRegistered($id)){
			throw new \RuntimeException("Trying to overwrite an already registered block");
		}

		for($meta = 0; $meta < 16; ++$meta){
			$variant = clone $block;
			$variant->setDamage($meta);
			self::$fullList[($id << 4) | $meta] = $variant;
		}

		self::$solid[$id] = $block->isSolid();
		self::$transparent[$id] = $block->isTransparent();
		self::$hardness[$id] = $block->getHardness();
		self::$light[$id] = $block->getLightLevel();
		self::$lightFilter[$id] = min(15, $block->getLightFilter() + 1); //opacity plus 1 standard light filter
		self::$diffusesSkyLight[$id] = $block->diffusesSkyLight();
		self::$blastResistance[$id] = $block->getBlastResistance();
	}

	/**
	 * Returns a new Block instance with the specified ID, meta and position.
	 */
	public static function get(int $id, int $meta = 0, Position $pos = null) : Block{
		if($meta < 0 or $meta > 0xf){
			throw new \InvalidArgumentException("Block meta value $meta is out of bounds");
		}

		try{
			if(self::$fullList !== null){
				$block = clone self::$fullList[($id << 4) | $meta];
			}else{
				$block = new UnknownBlock($id, $meta);
			}
		}catch(\RuntimeException $e){
			throw new \InvalidArgumentException("Block ID $id is out of bounds");
		}

		if($pos !== null){
			$block->x = $pos->getFloorX();
			$block->y = $pos->getFloorY();
			$block->z = $pos->getFloorZ();
			$block->level = $pos->level;
		}

		return $block;
	}

	/**
	 * @internal
	 * @phpstan-return \SplFixedArray<Block>
	 */
	public static function getBlockStatesArray() : \SplFixedArray{
		return self::$fullList;
	}

	/**
	 * Returns whether a specified block ID is already registered in the block factory.
	 */
	public static function isRegistered(int $id) : bool{
		$b = self::$fullList[$id << 4];
		return $b !== null and !($b instanceof UnknownBlock);
	}

	/**
	 * @internal
	 * @deprecated
	 */
	public static function toStaticRuntimeId(int $id, int $meta = 0) : int{
		return RuntimeBlockMapping::toStaticRuntimeId($id, $meta);
	}

	/**
	 * @deprecated
	 * @internal
	 *
	 * @return int[] [id, meta]
	 */
	public static function fromStaticRuntimeId(int $runtimeId) : array{
		return RuntimeBlockMapping::fromStaticRuntimeId($runtimeId);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;

/**
 * Air block
 */
class Air extends Transparent{

	protected $id = self::AIR;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Air";
	}

	public function canPassThrough() : bool{
		return true;
	}

	public function isBreakable(Item $item) : bool{
		return false;
	}

	public function canBeFlowedInto() : bool{
		return true;
	}

	public function canBeReplaced() : bool{
		return true;
	}

	public function canBePlaced() : bool{
		return false;
	}

	public function isSolid() : bool{
		return false;
	}

	public function getBoundingBox() : ?AxisAlignedBB{
		return null;
	}

	public function getCollisionBoxes() : array{
		return [];
	}

	public function getHardness() : float{
		return -1;
	}

	public function getBlastResistance() : float{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

abstract class Transparent extends Block{

	public function isTransparent() : bool{
		return true;
	}

	public function getLightFilter() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * All Block classes are in here
 */
namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Position;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue;
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
use pocketmine\Player;
use pocketmine\plugin\Plugin;
use function array_merge;
use function count;
use function get_class;
use const PHP_INT_MAX;

class Block extends Position implements BlockIds, Metadatable{

	/**
	 * Returns a new Block instance with the specified ID, meta and position.
	 *
	 * This function redirects to {@link BlockFactory#get}.
	 */
	public static function get(int $id, int $meta = 0, Position $pos = null) : Block{
		return BlockFactory::get($id, $meta, $pos);
	}

	/** @var int */
	protected $id;
	/** @var int */
	protected $meta = 0;
	/** @var string|null */
	protected $fallbackName;
	/** @var int|null */
	protected $itemId;

	/** @var AxisAlignedBB|null */
	protected $boundingBox = null;

	/** @var AxisAlignedBB[]|null */
	protected $collisionBoxes = null;

	/**
	 * @param int         $id     The block type's ID, 0-255
	 * @param int         $meta   Meta value of the block type
	 * @param string|null $name   English name of the block type (TODO: implement translations)
	 * @param int         $itemId The item ID of the block type, used for block picking and dropping items.
	 */
	public function __construct(int $id, int $meta = 0, string $name = null, int $itemId = null){
		$this->id = $id;
		$this->meta = $meta;
		$this->fallbackName = $name;
		$this->itemId = $itemId;
	}

	public function getName() : string{
		return $this->fallbackName ?? "Unknown";
	}

	final public function getId() : int{
		return $this->id;
	}

	/**
	 * Returns the ID of the item form of the block.
	 * Used for drops for blocks (some blocks such as doors have a different item ID).
	 */
	public function getItemId() : int{
		return $this->itemId ?? $this->getId();
	}

	/**
	 * @internal
	 */
	public function getRuntimeId() : int{
		return RuntimeBlockMapping::toStaticRuntimeId($this->getId(), $this->getDamage());
	}

	final public function getDamage() : int{
		return $this->meta;
	}

	final public function setDamage(int $meta) : void{
		if($meta < 0 or $meta > 0xf){
			throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta");
		}
		$this->meta = $meta;
	}

	/**
	 * Bitmask to use to remove superfluous information from block meta when getting its item form or name.
	 * This defaults to -1 (don't remove any data). Used to remove rotation data and bitflags from block drops.
	 *
	 * If your block should not have any meta value when it's dropped as an item, override this to return 0 in
	 * descendent classes.
	 */
	public function getVariantBitmask() : int{
		return -1;
	}

	/**
	 * Returns the block meta, stripped of non-variant flags.
	 */
	public function getVariant() : int{
		return $this->meta & $this->getVariantBitmask();
	}

	/**
	 * AKA: Block->isPlaceable
	 */
	public function canBePlaced() : bool{
		return true;
	}

	public function canBeReplaced() : bool{
		return false;
	}

	public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
		return $blockReplace->canBeReplaced();
	}

	/**
	 * Places the Block, using block space and block target, and side. Returns if the block has been placed.
	 */
	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		return $this->getLevel()->setBlock($this, $this, true, true);
	}

	/**
	 * Returns if the block can be broken with an specific Item
	 */
	public function isBreakable(Item $item) : bool{
		return true;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_NONE;
	}

	/**
	 * Returns the level of tool required to harvest this block (for normal blocks). When the tool type matches the
	 * block's required tool type, the tool must have a harvest level greater than or equal to this value to be able to
	 * successfully harvest the block.
	 *
	 * If the block requires a specific minimum tier of tiered tool, the minimum tier required should be returned.
	 * Otherwise, 1 should be returned if a tool is required, 0 if not.
	 *
	 * @see Item::getBlockToolHarvestLevel()
	 */
	public function getToolHarvestLevel() : int{
		return 0;
	}

	/**
	 * Returns whether the specified item is the proper tool to use for breaking this block. This checks tool type and
	 * harvest level requirement.
	 *
	 * In most cases this is also used to determine whether block drops should be created or not, except in some
	 * special cases such as vines.
	 */
	public function isCompatibleWithTool(Item $tool) : bool{
		if($this->getHardness() < 0){
			return false;
		}

		$toolType = $this->getToolType();
		$harvestLevel = $this->getToolHarvestLevel();
		return $toolType === BlockToolType::TYPE_NONE or $harvestLevel === 0 or (
			($toolType & $tool->getBlockToolType()) !== 0 and $tool->getBlockToolHarvestLevel() >= $harvestLevel);
	}

	/**
	 * Do the actions needed so the block is broken with the Item
	 */
	public function onBreak(Item $item, Player $player = null) : bool{
		return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
	}

	/**
	 * Returns the seconds that this block takes to be broken using an specific Item
	 *
	 * @throws \InvalidArgumentException if the item efficiency is not a positive number
	 */
	public function getBreakTime(Item $item) : float{
		$base = $this->getHardness();
		if($this->isCompatibleWithTool($item)){
			$base *= 1.5;
		}else{
			$base *= 5;
		}

		$efficiency = $item->getMiningEfficiency($this);
		if($efficiency <= 0){
			throw new \InvalidArgumentException(get_class($item) . " has invalid mining efficiency: expected >= 0, got $efficiency");
		}

		$base /= $efficiency;

		return $base;
	}

	/**
	 * Called when this block or a block immediately adjacent to it changes state.
	 */
	public function onNearbyBlockChange() : void{

	}

	/**
	 * Returns whether random block updates will be done on this block.
	 */
	public function ticksRandomly() : bool{
		return false;
	}

	/**
	 * Called when this block is randomly updated due to chunk ticking.
	 * WARNING: This will not be called if ticksRandomly() does not return true!
	 */
	public function onRandomTick() : void{

	}

	/**
	 * Called when this block is updated by the delayed blockupdate scheduler in the level.
	 */
	public function onScheduledUpdate() : void{

	}

	/**
	 * Do actions when activated by Item. Returns if it has done anything
	 */
	public function onActivate(Item $item, Player $player = null) : bool{
		return false;
	}

	/**
	 * Returns a base value used to compute block break times.
	 */
	public function getHardness() : float{
		return 10;
	}

	/**
	 * Returns the block's resistance to explosions. Usually 5x hardness.
	 */
	public function getBlastResistance() : float{
		return $this->getHardness() * 5;
	}

	public function getFrictionFactor() : float{
		return 0.6;
	}

	/**
	 * @return int 0-15
	 */
	public function getLightLevel() : int{
		return 0;
	}

	/**
	 * Returns the amount of light this block will filter out when light passes through this block.
	 * This value is used in light spread calculation.
	 *
	 * @return int 0-15
	 */
	public function getLightFilter() : int{
		return 15;
	}

	/**
	 * Returns whether this block will diffuse sky light passing through it vertically.
	 * Diffusion means that full-strength sky light passing through this block will not be reduced, but will start being filtered below the block.
	 * Examples of this behaviour include leaves and cobwebs.
	 *
	 * Light-diffusing blocks are included by the heightmap.
	 */
	public function diffusesSkyLight() : bool{
		return false;
	}

	public function isTransparent() : bool{
		return false;
	}

	public function isSolid() : bool{
		return true;
	}

	/**
	 * AKA: Block->isFlowable
	 */
	public function canBeFlowedInto() : bool{
		return false;
	}

	public function hasEntityCollision() : bool{
		return false;
	}

	public function canPassThrough() : bool{
		return false;
	}

	/**
	 * Returns whether entities can climb up this block.
	 */
	public function canClimb() : bool{
		return false;
	}

	public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{

	}

	/**
	 * Sets the block position to a new Position object
	 */
	final public function position(Position $v) : void{
		$this->x = (int) $v->x;
		$this->y = (int) $v->y;
		$this->z = (int) $v->z;
		$this->level = $v->level;
		$this->boundingBox = null;
	}

	/**
	 * Returns an array of Item objects to be dropped
	 *
	 * @return Item[]
	 */
	public function getDrops(Item $item) : array{
		if($this->isCompatibleWithTool($item)){
			if($this->isAffectedBySilkTouch() and $item->hasEnchantment(Enchantment::SILK_TOUCH)){
				return $this->getSilkTouchDrops($item);
			}

			return $this->getDropsForCompatibleTool($item);
		}

		return [];
	}

	/**
	 * Returns an array of Items to be dropped when the block is broken using the correct tool type.
	 *
	 * @return Item[]
	 */
	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get($this->getItemId(), $this->getVariant())
		];
	}

	/**
	 * Returns an array of Items to be dropped when the block is broken using a compatible Silk Touch-enchanted tool.
	 *
	 * @return Item[]
	 */
	public function getSilkTouchDrops(Item $item) : array{
		return [
			ItemFactory::get($this->getItemId(), $this->getVariant())
		];
	}

	/**
	 * Returns how much XP will be dropped by breaking this block with the given item.
	 */
	public function getXpDropForTool(Item $item) : int{
		if($item->hasEnchantment(Enchantment::SILK_TOUCH) or !$this->isCompatibleWithTool($item)){
			return 0;
		}

		return $this->getXpDropAmount();
	}

	/**
	 * Returns how much XP this block will drop when broken with an appropriate tool.
	 */
	protected function getXpDropAmount() : int{
		return 0;
	}

	/**
	 * Returns whether Silk Touch enchanted tools will cause this block to drop as itself. Since most blocks drop
	 * themselves anyway, this is implicitly true.
	 */
	public function isAffectedBySilkTouch() : bool{
		return true;
	}

	/**
	 * Returns the item that players will equip when middle-clicking on this block.
	 */
	public function getPickedItem() : Item{
		return ItemFactory::get($this->getItemId(), $this->getVariant());
	}

	/**
	 * Returns the time in ticks which the block will fuel a furnace for.
	 */
	public function getFuelTime() : int{
		return 0;
	}

	/**
	 * Returns the chance that the block will catch fire from nearby fire sources. Higher values lead to faster catching
	 * fire.
	 */
	public function getFlameEncouragement() : int{
		return 0;
	}

	/**
	 * Returns the base flammability of this block. Higher values lead to the block burning away more quickly.
	 */
	public function getFlammability() : int{
		return 0;
	}

	/**
	 * Returns whether fire lit on this block will burn indefinitely.
	 */
	public function burnsForever() : bool{
		return false;
	}

	/**
	 * Returns whether this block can catch fire.
	 */
	public function isFlammable() : bool{
		return $this->getFlammability() > 0;
	}

	/**
	 * Called when this block is burned away by being on fire.
	 */
	public function onIncinerate() : void{

	}

	/**
	 * Returns the Block on the side $side, works like Vector3::getSide()
	 *
	 * @return Block
	 */
	public function getSide(int $side, int $step = 1){
		if($this->isValid()){
			return $this->getLevel()->getBlock(Vector3::getSide($side, $step));
		}

		return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
	}

	/**
	 * Returns the 4 blocks on the horizontal axes around the block (north, south, east, west)
	 *
	 * @return Block[]
	 */
	public function getHorizontalSides() : array{
		return [
			$this->getSide(Vector3::SIDE_NORTH),
			$this->getSide(Vector3::SIDE_SOUTH),
			$this->getSide(Vector3::SIDE_WEST),
			$this->getSide(Vector3::SIDE_EAST)
		];
	}

	/**
	 * Returns the six blocks around this block.
	 *
	 * @return Block[]
	 */
	public function getAllSides() : array{
		return array_merge(
			[
				$this->getSide(Vector3::SIDE_DOWN),
				$this->getSide(Vector3::SIDE_UP)
			],
			$this->getHorizontalSides()
		);
	}

	/**
	 * Returns a list of blocks that this block is part of. In most cases, only contains the block itself, but in cases
	 * such as double plants, beds and doors, will contain both halves.
	 *
	 * @return Block[]
	 */
	public function getAffectedBlocks() : array{
		return [$this];
	}

	/**
	 * @return string
	 */
	public function __toString(){
		return "Block[" . $this->getName() . "] (" . $this->getId() . ":" . $this->getDamage() . ")";
	}

	/**
	 * Checks for collision against an AxisAlignedBB
	 */
	public function collidesWithBB(AxisAlignedBB $bb) : bool{
		foreach($this->getCollisionBoxes() as $bb2){
			if($bb->intersectsWith($bb2)){
				return true;
			}
		}

		return false;
	}

	public function onEntityCollide(Entity $entity) : void{

	}

	/**
	 * @return AxisAlignedBB[]
	 */
	public function getCollisionBoxes() : array{
		if($this->collisionBoxes === null){
			$this->collisionBoxes = $this->recalculateCollisionBoxes();
		}

		return $this->collisionBoxes;
	}

	/**
	 * @return AxisAlignedBB[]
	 */
	protected function recalculateCollisionBoxes() : array{
		if(($bb = $this->recalculateBoundingBox()) !== null){
			return [$bb];
		}

		return [];
	}

	public function getBoundingBox() : ?AxisAlignedBB{
		if($this->boundingBox === null){
			$this->boundingBox = $this->recalculateBoundingBox();
		}
		return $this->boundingBox;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return new AxisAlignedBB(
			$this->x,
			$this->y,
			$this->z,
			$this->x + 1,
			$this->y + 1,
			$this->z + 1
		);
	}

	/**
	 * Clears any cached precomputed objects, such as bounding boxes. This is called on block neighbour update and when
	 * the block is set into the world to remove any outdated precomputed things such as AABBs and force recalculation.
	 */
	public function clearCaches() : void{
		$this->boundingBox = null;
		$this->collisionBoxes = null;
	}

	public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
		$bbs = $this->getCollisionBoxes();
		if(count($bbs) === 0){
			return null;
		}

		/** @var RayTraceResult|null $currentHit */
		$currentHit = null;
		/** @var int|float $currentDistance */
		$currentDistance = PHP_INT_MAX;

		foreach($bbs as $bb){
			$nextHit = $bb->calculateIntercept($pos1, $pos2);
			if($nextHit === null){
				continue;
			}

			$nextDistance = $nextHit->hitVector->distanceSquared($pos1);
			if($nextDistance < $currentDistance){
				$currentHit = $nextHit;
				$currentDistance = $nextDistance;
			}
		}

		return $currentHit;
	}

	public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
		if($this->isValid()){
			$this->level->getBlockMetadata()->setMetadata($this, $metadataKey, $newMetadataValue);
		}
	}

	public function getMetadata(string $metadataKey){
		if($this->isValid()){
			return $this->level->getBlockMetadata()->getMetadata($this, $metadataKey);
		}

		return [];
	}

	public function hasMetadata(string $metadataKey) : bool{
		if($this->isValid()){
			return $this->level->getBlockMetadata()->hasMetadata($this, $metadataKey);
		}

		return false;
	}

	public function removeMetadata(string $metadataKey, Plugin $owningPlugin){
		if($this->isValid()){
			$this->level->getBlockMetadata()->removeMetadata($this, $metadataKey, $owningPlugin);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

interface BlockIds{

	public const AIR = 0;
	public const STONE = 1;
	public const GRASS = 2;
	public const DIRT = 3;
	public const COBBLESTONE = 4;
	public const PLANKS = 5, WOODEN_PLANKS = 5;
	public const SAPLING = 6;
	public const BEDROCK = 7;
	public const FLOWING_WATER = 8;
	public const STILL_WATER = 9, WATER = 9;
	public const FLOWING_LAVA = 10;
	public const LAVA = 11, STILL_LAVA = 11;
	public const SAND = 12;
	public const GRAVEL = 13;
	public const GOLD_ORE = 14;
	public const IRON_ORE = 15;
	public const COAL_ORE = 16;
	public const LOG = 17, WOOD = 17;
	public const LEAVES = 18;
	public const SPONGE = 19;
	public const GLASS = 20;
	public const LAPIS_ORE = 21;
	public const LAPIS_BLOCK = 22;
	public const DISPENSER = 23;
	public const SANDSTONE = 24;
	public const NOTEBLOCK = 25, NOTE_BLOCK = 25;
	public const BED_BLOCK = 26;
	public const GOLDEN_RAIL = 27, POWERED_RAIL = 27;
	public const DETECTOR_RAIL = 28;
	public const STICKY_PISTON = 29;
	public const COBWEB = 30, WEB = 30;
	public const TALLGRASS = 31, TALL_GRASS = 31;
	public const DEADBUSH = 32, DEAD_BUSH = 32;
	public const PISTON = 33;
	public const PISTONARMCOLLISION = 34, PISTON_ARM_COLLISION = 34;
	public const WOOL = 35;

	public const DANDELION = 37, YELLOW_FLOWER = 37;
	public const POPPY = 38, RED_FLOWER = 38;
	public const BROWN_MUSHROOM = 39;
	public const RED_MUSHROOM = 40;
	public const GOLD_BLOCK = 41;
	public const IRON_BLOCK = 42;
	public const DOUBLE_STONE_SLAB = 43;
	public const STONE_SLAB = 44;
	public const BRICK_BLOCK = 45;
	public const TNT = 46;
	public const BOOKSHELF = 47;
	public const MOSSY_COBBLESTONE = 48, MOSS_STONE = 48;
	public const OBSIDIAN = 49;
	public const TORCH = 50;
	public const FIRE = 51;
	public const MOB_SPAWNER = 52, MONSTER_SPAWNER = 52;
	public const OAK_STAIRS = 53, WOODEN_STAIRS = 53;
	public const CHEST = 54;
	public const REDSTONE_WIRE = 55;
	public const DIAMOND_ORE = 56;
	public const DIAMOND_BLOCK = 57;
	public const CRAFTING_TABLE = 58, WORKBENCH = 58;
	public const WHEAT_BLOCK = 59;
	public const FARMLAND = 60;
	public const FURNACE = 61;
	public const BURNING_FURNACE = 62, LIT_FURNACE = 62;
	public const SIGN_POST = 63, STANDING_SIGN = 63;
	public const OAK_DOOR_BLOCK = 64, WOODEN_DOOR_BLOCK = 64;
	public const LADDER = 65;
	public const RAIL = 66;
	public const COBBLESTONE_STAIRS = 67, STONE_STAIRS = 67;
	public const WALL_SIGN = 68;
	public const LEVER = 69;
	public const STONE_PRESSURE_PLATE = 70;
	public const IRON_DOOR_BLOCK = 71;
	public const WOODEN_PRESSURE_PLATE = 72;
	public const REDSTONE_ORE = 73;
	public const GLOWING_REDSTONE_ORE = 74, LIT_REDSTONE_ORE = 74;
	public const UNLIT_REDSTONE_TORCH = 75;
	public const LIT_REDSTONE_TORCH = 76, REDSTONE_TORCH = 76;
	public const STONE_BUTTON = 77;
	public const SNOW_LAYER = 78;
	public const ICE = 79;
	public const SNOW = 80, SNOW_BLOCK = 80;
	public const CACTUS = 81;
	public const CLAY_BLOCK = 82;
	public const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
	public const JUKEBOX = 84;
	public const FENCE = 85;
	public const PUMPKIN = 86;
	public const NETHERRACK = 87;
	public const SOUL_SAND = 88;
	public const GLOWSTONE = 89;
	public const PORTAL = 90;
	public const JACK_O_LANTERN = 91, LIT_PUMPKIN = 91;
	public const CAKE_BLOCK = 92;
	public const REPEATER_BLOCK = 93, UNPOWERED_REPEATER = 93;
	public const POWERED_REPEATER = 94;
	public const INVISIBLEBEDROCK = 95, INVISIBLE_BEDROCK = 95;
	public const TRAPDOOR = 96, WOODEN_TRAPDOOR = 96;
	public const MONSTER_EGG = 97;
	public const STONEBRICK = 98, STONE_BRICK = 98, STONE_BRICKS = 98;
	public const BROWN_MUSHROOM_BLOCK = 99;
	public const RED_MUSHROOM_BLOCK = 100;
	public const IRON_BARS = 101;
	public const GLASS_PANE = 102;
	public const MELON_BLOCK = 103;
	public const PUMPKIN_STEM = 104;
	public const MELON_STEM = 105;
	public const VINE = 106, VINES = 106;
	public const FENCE_GATE = 107, OAK_FENCE_GATE = 107;
	public const BRICK_STAIRS = 108;
	public const STONE_BRICK_STAIRS = 109;
	public const MYCELIUM = 110;
	public const LILY_PAD = 111, WATERLILY = 111, WATER_LILY = 111;
	public const NETHER_BRICK_BLOCK = 112;
	public const NETHER_BRICK_FENCE = 113;
	public const NETHER_BRICK_STAIRS = 114;
	public const NETHER_WART_PLANT = 115;
	public const ENCHANTING_TABLE = 116, ENCHANTMENT_TABLE = 116;
	public const BREWING_STAND_BLOCK = 117;
	public const CAULDRON_BLOCK = 118;
	public const END_PORTAL = 119;
	public const END_PORTAL_FRAME = 120;
	public const END_STONE = 121;
	public const DRAGON_EGG = 122;
	public const REDSTONE_LAMP = 123;
	public const LIT_REDSTONE_LAMP = 124;
	public const DROPPER = 125;
	public const ACTIVATOR_RAIL = 126;
	public const COCOA = 127, COCOA_BLOCK = 127;
	public const SANDSTONE_STAIRS = 128;
	public const EMERALD_ORE = 129;
	public const ENDER_CHEST = 130;
	public const TRIPWIRE_HOOK = 131;
	public const TRIPWIRE = 132, TRIP_WIRE = 132;
	public const EMERALD_BLOCK = 133;
	public const SPRUCE_STAIRS = 134;
	public const BIRCH_STAIRS = 135;
	public const JUNGLE_STAIRS = 136;
	public const COMMAND_BLOCK = 137;
	public const BEACON = 138;
	public const COBBLESTONE_WALL = 139, STONE_WALL = 139;
	public const FLOWER_POT_BLOCK = 140;
	public const CARROTS = 141, CARROT_BLOCK = 141;
	public const POTATOES = 142, POTATO_BLOCK = 142;
	public const WOODEN_BUTTON = 143;
	public const MOB_HEAD_BLOCK = 144, SKULL_BLOCK = 144;
	public const ANVIL = 145;
	public const TRAPPED_CHEST = 146;
	public const LIGHT_WEIGHTED_PRESSURE_PLATE = 147;
	public const HEAVY_WEIGHTED_PRESSURE_PLATE = 148;
	public const COMPARATOR_BLOCK = 149, UNPOWERED_COMPARATOR = 149;
	public const POWERED_COMPARATOR = 150;
	public const DAYLIGHT_DETECTOR = 151, DAYLIGHT_SENSOR = 151;
	public const REDSTONE_BLOCK = 152;
	public const NETHER_QUARTZ_ORE = 153, QUARTZ_ORE = 153;
	public const HOPPER_BLOCK = 154;
	public const QUARTZ_BLOCK = 155;
	public const QUARTZ_STAIRS = 156;
	public const DOUBLE_WOODEN_SLAB = 157;
	public const WOODEN_SLAB = 158;
	public const STAINED_CLAY = 159, STAINED_HARDENED_CLAY = 159, TERRACOTTA = 159;
	public const STAINED_GLASS_PANE = 160;
	public const LEAVES2 = 161;
	public const LOG2 = 162, WOOD2 = 162;
	public const ACACIA_STAIRS = 163;
	public const DARK_OAK_STAIRS = 164;
	public const SLIME = 165, SLIME_BLOCK = 165;

	public const IRON_TRAPDOOR = 167;
	public const PRISMARINE = 168;
	public const SEALANTERN = 169, SEA_LANTERN = 169;
	public const HAY_BALE = 170, HAY_BLOCK = 170;
	public const CARPET = 171;
	public const HARDENED_CLAY = 172;
	public const COAL_BLOCK = 173;
	public const PACKED_ICE = 174;
	public const DOUBLE_PLANT = 175;
	public const STANDING_BANNER = 176;
	public const WALL_BANNER = 177;
	public const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
	public const RED_SANDSTONE = 179;
	public const RED_SANDSTONE_STAIRS = 180;
	public const DOUBLE_STONE_SLAB2 = 181;
	public const STONE_SLAB2 = 182;
	public const SPRUCE_FENCE_GATE = 183;
	public const BIRCH_FENCE_GATE = 184;
	public const JUNGLE_FENCE_GATE = 185;
	public const DARK_OAK_FENCE_GATE = 186;
	public const ACACIA_FENCE_GATE = 187;
	public const REPEATING_COMMAND_BLOCK = 188;
	public const CHAIN_COMMAND_BLOCK = 189;

	public const SPRUCE_DOOR_BLOCK = 193;
	public const BIRCH_DOOR_BLOCK = 194;
	public const JUNGLE_DOOR_BLOCK = 195;
	public const ACACIA_DOOR_BLOCK = 196;
	public const DARK_OAK_DOOR_BLOCK = 197;
	public const GRASS_PATH = 198;
	public const FRAME_BLOCK = 199, ITEM_FRAME_BLOCK = 199;
	public const CHORUS_FLOWER = 200;
	public const PURPUR_BLOCK = 201;

	public const PURPUR_STAIRS = 203;

	public const UNDYED_SHULKER_BOX = 205;
	public const END_BRICKS = 206;
	public const FROSTED_ICE = 207;
	public const END_ROD = 208;
	public const END_GATEWAY = 209;

	public const MAGMA = 213;
	public const NETHER_WART_BLOCK = 214;
	public const RED_NETHER_BRICK = 215;
	public const BONE_BLOCK = 216;

	public const SHULKER_BOX = 218;
	public const PURPLE_GLAZED_TERRACOTTA = 219;
	public const WHITE_GLAZED_TERRACOTTA = 220;
	public const ORANGE_GLAZED_TERRACOTTA = 221;
	public const MAGENTA_GLAZED_TERRACOTTA = 222;
	public const LIGHT_BLUE_GLAZED_TERRACOTTA = 223;
	public const YELLOW_GLAZED_TERRACOTTA = 224;
	public const LIME_GLAZED_TERRACOTTA = 225;
	public const PINK_GLAZED_TERRACOTTA = 226;
	public const GRAY_GLAZED_TERRACOTTA = 227;
	public const SILVER_GLAZED_TERRACOTTA = 228;
	public const CYAN_GLAZED_TERRACOTTA = 229;

	public const BLUE_GLAZED_TERRACOTTA = 231;
	public const BROWN_GLAZED_TERRACOTTA = 232;
	public const GREEN_GLAZED_TERRACOTTA = 233;
	public const RED_GLAZED_TERRACOTTA = 234;
	public const BLACK_GLAZED_TERRACOTTA = 235;
	public const CONCRETE = 236;
	public const CONCRETEPOWDER = 237, CONCRETE_POWDER = 237;

	public const CHORUS_PLANT = 240;
	public const STAINED_GLASS = 241;

	public const PODZOL = 243;
	public const BEETROOT_BLOCK = 244;
	public const STONECUTTER = 245;
	public const GLOWINGOBSIDIAN = 246, GLOWING_OBSIDIAN = 246;
	public const NETHERREACTOR = 247, NETHER_REACTOR = 247;
	public const INFO_UPDATE = 248;
	public const INFO_UPDATE2 = 249;
	public const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
	public const OBSERVER = 251;
	public const STRUCTURE_BLOCK = 252;

	public const RESERVED6 = 255;

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;

class Stone extends Solid{
	public const NORMAL = 0;
	public const GRANITE = 1;
	public const POLISHED_GRANITE = 2;
	public const DIORITE = 3;
	public const POLISHED_DIORITE = 4;
	public const ANDESITE = 5;
	public const POLISHED_ANDESITE = 6;

	protected $id = self::STONE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 1.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		static $names = [
			self::NORMAL => "Stone",
			self::GRANITE => "Granite",
			self::POLISHED_GRANITE => "Polished Granite",
			self::DIORITE => "Diorite",
			self::POLISHED_DIORITE => "Polished Diorite",
			self::ANDESITE => "Andesite",
			self::POLISHED_ANDESITE => "Polished Andesite"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		if($this->getDamage() === self::NORMAL){
			return [
				ItemFactory::get(Item::COBBLESTONE, $this->getDamage())
			];
		}

		return parent::getDropsForCompatibleTool($item);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

abstract class Solid extends Block{

	public function isSolid() : bool{
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Hoe;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Shovel;
use pocketmine\level\generator\object\TallGrass as TallGrassObject;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\Random;
use function mt_rand;

class Grass extends Solid{

	protected $id = self::GRASS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Grass";
	}

	public function getHardness() : float{
		return 0.6;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::DIRT)
		];
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		$lightAbove = $this->level->getFullLightAt($this->x, $this->y + 1, $this->z);
		if($lightAbove < 4 and BlockFactory::$lightFilter[$this->level->getBlockIdAt($this->x, $this->y + 1, $this->z)] >= 3){ //2 plus 1 standard filter amount
			//grass dies
			$ev = new BlockSpreadEvent($this, $this, BlockFactory::get(Block::DIRT));
			$ev->call();
			if(!$ev->isCancelled()){
				$this->level->setBlock($this, $ev->getNewState(), false, false);
			}
		}elseif($lightAbove >= 9){
			//try grass spread
			for($i = 0; $i < 4; ++$i){
				$x = mt_rand($this->x - 1, $this->x + 1);
				$y = mt_rand($this->y - 3, $this->y + 1);
				$z = mt_rand($this->z - 1, $this->z + 1);
				if(
					$this->level->getBlockIdAt($x, $y, $z) !== Block::DIRT or
					$this->level->getBlockDataAt($x, $y, $z) === 1 or
					$this->level->getFullLightAt($x, $y + 1, $z) < 4 or
					BlockFactory::$lightFilter[$this->level->getBlockIdAt($x, $y + 1, $z)] >= 3
				){
					continue;
				}

				$ev = new BlockSpreadEvent($b = $this->level->getBlockAt($x, $y, $z), $this, BlockFactory::get(Block::GRASS));
				$ev->call();
				if(!$ev->isCancelled()){
					$this->level->setBlock($b, $ev->getNewState(), false, false);
				}
			}
		}
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){
			$item->count--;
			TallGrassObject::growGrass($this->getLevel(), $this, new Random(mt_rand()), 8, 2);

			return true;
		}elseif($item instanceof Hoe){
			$item->applyDamage(1);
			$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND));

			return true;
		}elseif($item instanceof Shovel and $this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR){
			$item->applyDamage(1);
			$this->getLevel()->setBlock($this, BlockFactory::get(Block::GRASS_PATH));

			return true;
		}

		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Hoe;
use pocketmine\item\Item;
use pocketmine\Player;

class Dirt extends Solid{

	protected $id = self::DIRT;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getName() : string{
		if($this->meta === 1){
			return "Coarse Dirt";
		}
		return "Dirt";
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($item instanceof Hoe){
			$item->applyDamage(1);
			if($this->meta === 1){
				$this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT), true);
			}else{
				$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);
			}

			return true;
		}

		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Cobblestone extends Solid{

	protected $id = self::COBBLESTONE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Cobblestone";
	}

	public function getHardness() : float{
		return 2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class Planks extends Solid{
	public const OAK = 0;
	public const SPRUCE = 1;
	public const BIRCH = 2;
	public const JUNGLE = 3;
	public const ACACIA = 4;
	public const DARK_OAK = 5;

	protected $id = self::WOODEN_PLANKS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getName() : string{
		static $names = [
			self::OAK => "Oak Wood Planks",
			self::SPRUCE => "Spruce Wood Planks",
			self::BIRCH => "Birch Wood Planks",
			self::JUNGLE => "Jungle Wood Planks",
			self::ACACIA => "Acacia Wood Planks",
			self::DARK_OAK => "Dark Oak Wood Planks"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function getFuelTime() : int{
		return 300;
	}

	public function getFlameEncouragement() : int{
		return 5;
	}

	public function getFlammability() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\level\generator\object\Tree;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\Random;
use function mt_rand;

class Sapling extends Flowable{
	public const OAK = 0;
	public const SPRUCE = 1;
	public const BIRCH = 2;
	public const JUNGLE = 3;
	public const ACACIA = 4;
	public const DARK_OAK = 5;

	protected $id = self::SAPLING;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		static $names = [
			0 => "Oak Sapling",
			1 => "Spruce Sapling",
			2 => "Birch Sapling",
			3 => "Jungle Sapling",
			4 => "Acacia Sapling",
			5 => "Dark Oak Sapling"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::FARMLAND){
			$this->getLevel()->setBlock($blockReplace, $this, true, true);

			return true;
		}

		return false;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
			//TODO: change log type
			Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());

			$item->count--;

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		if($this->level->getFullLightAt($this->x, $this->y, $this->z) >= 8 and mt_rand(1, 7) === 1){
			if(($this->meta & 0x08) === 0x08){
				Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
			}else{
				$this->meta |= 0x08;
				$this->getLevel()->setBlock($this, $this, true);
			}
		}
	}

	public function getVariantBitmask() : int{
		return 0x07;
	}

	public function getFuelTime() : int{
		return 100;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\math\AxisAlignedBB;

abstract class Flowable extends Transparent{

	public function canBeFlowedInto() : bool{
		return true;
	}

	public function getHardness() : float{
		return 0;
	}

	public function isSolid() : bool{
		return false;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return null;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;

class Bedrock extends Solid{

	protected $id = self::BEDROCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Bedrock";
	}

	public function getHardness() : float{
		return -1;
	}

	public function getBlastResistance() : float{
		return 18000000;
	}

	public function isBreakable(Item $item) : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\Player;

class Water extends Liquid{

	protected $id = self::FLOWING_WATER;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Water";
	}

	public function getLightFilter() : int{
		return 2;
	}

	public function getStillForm() : Block{
		return BlockFactory::get(Block::STILL_WATER, $this->meta);
	}

	public function getFlowingForm() : Block{
		return BlockFactory::get(Block::FLOWING_WATER, $this->meta);
	}

	public function getBucketFillSound() : int{
		return LevelSoundEventPacket::SOUND_BUCKET_FILL_WATER;
	}

	public function getBucketEmptySound() : int{
		return LevelSoundEventPacket::SOUND_BUCKET_EMPTY_WATER;
	}

	public function tickRate() : int{
		return 5;
	}

	public function onEntityCollide(Entity $entity) : void{
		$entity->resetFallDistance();
		if($entity->isOnFire()){
			$entity->extinguish();
		}

		$entity->resetFallDistance();
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$ret = $this->getLevel()->setBlock($this, $this, true, false);
		$this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate());

		return $ret;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\event\block\BlockFormEvent;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\level\sound\FizzSound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use function array_fill;
use function intdiv;
use function lcg_value;
use function min;

abstract class Liquid extends Transparent{

	/** @var int */
	public $adjacentSources = 0;

	/** @var Vector3|null */
	protected $flowVector = null;

	/** @var int[] */
	private $flowCostVisited = [];

	private const CAN_FLOW_DOWN = 1;
	private const CAN_FLOW = 0;
	private const BLOCKED = -1;

	public function hasEntityCollision() : bool{
		return true;
	}

	public function isBreakable(Item $item) : bool{
		return false;
	}

	public function canBeReplaced() : bool{
		return true;
	}

	public function canBeFlowedInto() : bool{
		return true;
	}

	public function isSolid() : bool{
		return false;
	}

	public function getHardness() : float{
		return 100;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return null;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [];
	}

	abstract public function getStillForm() : Block;

	abstract public function getFlowingForm() : Block;

	abstract public function getBucketFillSound() : int;

	abstract public function getBucketEmptySound() : int;

	/**
	 * @return float
	 */
	public function getFluidHeightPercent(){
		$d = $this->meta;
		if($d >= 8){
			$d = 0;
		}

		return ($d + 1) / 9;
	}

	protected function getFlowDecay(Block $block) : int{
		if($block->getId() !== $this->getId()){
			return -1;
		}

		return $block->getDamage();
	}

	protected function getEffectiveFlowDecay(Block $block) : int{
		if($block->getId() !== $this->getId()){
			return -1;
		}

		$decay = $block->getDamage();

		if($decay >= 8){
			$decay = 0;
		}

		return $decay;
	}

	public function clearCaches() : void{
		parent::clearCaches();
		$this->flowVector = null;
	}

	public function getFlowVector() : Vector3{
		if($this->flowVector !== null){
			return $this->flowVector;
		}

		$vector = new Vector3(0, 0, 0);

		$decay = $this->getEffectiveFlowDecay($this);

		for($j = 0; $j < 4; ++$j){

			$x = $this->x;
			$y = $this->y;
			$z = $this->z;

			if($j === 0){
				--$x;
			}elseif($j === 1){
				++$x;
			}elseif($j === 2){
				--$z;
			}elseif($j === 3){
				++$z;
			}
			$sideBlock = $this->level->getBlockAt($x, $y, $z);
			$blockDecay = $this->getEffectiveFlowDecay($sideBlock);

			if($blockDecay < 0){
				if(!$sideBlock->canBeFlowedInto()){
					continue;
				}

				$blockDecay = $this->getEffectiveFlowDecay($this->level->getBlockAt($x, $y - 1, $z));

				if($blockDecay >= 0){
					$realDecay = $blockDecay - ($decay - 8);
					$vector->x += ($sideBlock->x - $this->x) * $realDecay;
					$vector->y += ($sideBlock->y - $this->y) * $realDecay;
					$vector->z += ($sideBlock->z - $this->z) * $realDecay;
				}

				continue;
			}else{
				$realDecay = $blockDecay - $decay;
				$vector->x += ($sideBlock->x - $this->x) * $realDecay;
				$vector->y += ($sideBlock->y - $this->y) * $realDecay;
				$vector->z += ($sideBlock->z - $this->z) * $realDecay;
			}
		}

		if($this->getDamage() >= 8){
			if(
				!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y, $this->z - 1)) or
				!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y, $this->z + 1)) or
				!$this->canFlowInto($this->level->getBlockAt($this->x - 1, $this->y, $this->z)) or
				!$this->canFlowInto($this->level->getBlockAt($this->x + 1, $this->y, $this->z)) or
				!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y + 1, $this->z - 1)) or
				!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y + 1, $this->z + 1)) or
				!$this->canFlowInto($this->level->getBlockAt($this->x - 1, $this->y + 1, $this->z)) or
				!$this->canFlowInto($this->level->getBlockAt($this->x + 1, $this->y + 1, $this->z))
			){
				$vector = $vector->normalize()->add(0, -6, 0);
			}
		}

		return $this->flowVector = $vector->normalize();
	}

	public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
		if($entity->canBeMovedByCurrents()){
			$flow = $this->getFlowVector();
			$vector->x += $flow->x;
			$vector->y += $flow->y;
			$vector->z += $flow->z;
		}
	}

	abstract public function tickRate() : int;

	/**
	 * Returns how many liquid levels are lost per block flowed horizontally. Affects how far the liquid can flow.
	 */
	public function getFlowDecayPerBlock() : int{
		return 1;
	}

	public function onNearbyBlockChange() : void{
		$this->checkForHarden();
		$this->level->scheduleDelayedBlockUpdate($this, $this->tickRate());
	}

	public function onScheduledUpdate() : void{
		$decay = $this->getFlowDecay($this);
		$multiplier = $this->getFlowDecayPerBlock();

		if($decay > 0){
			$smallestFlowDecay = -100;
			$this->adjacentSources = 0;
			$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $smallestFlowDecay);
			$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $smallestFlowDecay);
			$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $smallestFlowDecay);
			$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $smallestFlowDecay);

			$newDecay = $smallestFlowDecay + $multiplier;

			if($newDecay >= 8 or $smallestFlowDecay < 0){
				$newDecay = -1;
			}

			if(($topFlowDecay = $this->getFlowDecay($this->level->getBlockAt($this->x, $this->y + 1, $this->z))) >= 0){
				$newDecay = $topFlowDecay | 0x08;
			}

			if($this->adjacentSources >= 2 and $this instanceof Water){
				$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
				if($bottomBlock->isSolid()){
					$newDecay = 0;
				}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
					$newDecay = 0;
				}
			}

			if($newDecay !== $decay){
				$decay = $newDecay;
				if($decay < 0){
					$this->level->setBlock($this, BlockFactory::get(Block::AIR), true, true);
				}else{
					$this->level->setBlock($this, BlockFactory::get($this->id, $decay), true, true);
					$this->level->scheduleDelayedBlockUpdate($this, $this->tickRate());
				}
			}
		}

		if($decay >= 0){
			$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);

			$this->flowIntoBlock($bottomBlock, $decay | 0x08);

			if($decay === 0 or !$bottomBlock->canBeFlowedInto()){
				if($decay >= 8){
					$adjacentDecay = 1;
				}else{
					$adjacentDecay = $decay + $multiplier;
				}

				if($adjacentDecay < 8){
					$flags = $this->getOptimalFlowDirections();

					if($flags[0]){
						$this->flowIntoBlock($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $adjacentDecay);
					}

					if($flags[1]){
						$this->flowIntoBlock($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $adjacentDecay);
					}

					if($flags[2]){
						$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $adjacentDecay);
					}

					if($flags[3]){
						$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $adjacentDecay);
					}
				}
			}

			$this->checkForHarden();
		}
	}

	protected function flowIntoBlock(Block $block, int $newFlowDecay) : void{
		if($this->canFlowInto($block) and !($block instanceof Liquid)){
			$ev = new BlockSpreadEvent($block, $this, BlockFactory::get($this->getId(), $newFlowDecay));
			$ev->call();
			if(!$ev->isCancelled()){
				if($block->getId() > 0){
					$this->level->useBreakOn($block);
				}

				$this->level->setBlock($block, $ev->getNewState(), true, true);
				$this->level->scheduleDelayedBlockUpdate($block, $this->tickRate());
			}
		}
	}

	private function calculateFlowCost(int $blockX, int $blockY, int $blockZ, int $accumulatedCost, int $maxCost, int $originOpposite, int $lastOpposite) : int{
		$cost = 1000;

		for($j = 0; $j < 4; ++$j){
			if($j === $originOpposite or $j === $lastOpposite){
				continue;
			}

			$x = $blockX;
			$y = $blockY;
			$z = $blockZ;

			if($j === 0){
				--$x;
			}elseif($j === 1){
				++$x;
			}elseif($j === 2){
				--$z;
			}elseif($j === 3){
				++$z;
			}

			if(!isset($this->flowCostVisited[$hash = ((($x) & 0xFFFFFFF) << 36) | ((( $y) & 0xff) << 28) | (( $z) & 0xFFFFFFF)])){
				$blockSide = $this->level->getBlockAt($x, $y, $z);
				if(!$this->canFlowInto($blockSide)){
					$this->flowCostVisited[$hash] = self::BLOCKED;
				}elseif($this->level->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
					$this->flowCostVisited[$hash] = self::CAN_FLOW_DOWN;
				}else{
					$this->flowCostVisited[$hash] = self::CAN_FLOW;
				}
			}

			$status = $this->flowCostVisited[$hash];

			if($status === self::BLOCKED){
				continue;
			}elseif($status === self::CAN_FLOW_DOWN){
				return $accumulatedCost;
			}

			if($accumulatedCost >= $maxCost){
				continue;
			}

			$realCost = $this->calculateFlowCost($x, $y, $z, $accumulatedCost + 1, $maxCost, $originOpposite, $j ^ 0x01);

			if($realCost < $cost){
				$cost = $realCost;
			}
		}

		return $cost;
	}

	/**
	 * @return bool[]
	 */
	private function getOptimalFlowDirections() : array{
		$flowCost = array_fill(0, 4, 1000);
		$maxCost = intdiv(4, $this->getFlowDecayPerBlock());
		for($j = 0; $j < 4; ++$j){
			$x = $this->x;
			$y = $this->y;
			$z = $this->z;

			if($j === 0){
				--$x;
			}elseif($j === 1){
				++$x;
			}elseif($j === 2){
				--$z;
			}elseif($j === 3){
				++$z;
			}
			$block = $this->level->getBlockAt($x, $y, $z);

			if(!$this->canFlowInto($block)){
				$this->flowCostVisited[((($x) & 0xFFFFFFF) << 36) | ((( $y) & 0xff) << 28) | (( $z) & 0xFFFFFFF)] = self::BLOCKED;
				continue;
			}elseif($this->level->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
				$this->flowCostVisited[((($x) & 0xFFFFFFF) << 36) | ((( $y) & 0xff) << 28) | (( $z) & 0xFFFFFFF)] = self::CAN_FLOW_DOWN;
				$flowCost[$j] = $maxCost = 0;
			}elseif($maxCost > 0){
				$this->flowCostVisited[((($x) & 0xFFFFFFF) << 36) | ((( $y) & 0xff) << 28) | (( $z) & 0xFFFFFFF)] = self::CAN_FLOW;
				$flowCost[$j] = $this->calculateFlowCost($x, $y, $z, 1, $maxCost, $j ^ 0x01, $j ^ 0x01);
				$maxCost = min($maxCost, $flowCost[$j]);
			}
		}

		$this->flowCostVisited = [];

		$minCost = min($flowCost);

		$isOptimalFlowDirection = [];

		for($i = 0; $i < 4; ++$i){
			$isOptimalFlowDirection[$i] = ($flowCost[$i] === $minCost);
		}

		return $isOptimalFlowDirection;
	}

	private function getSmallestFlowDecay(Block $block, int $decay) : int{
		$blockDecay = $this->getFlowDecay($block);

		if($blockDecay < 0){
			return $decay;
		}elseif($blockDecay === 0){
			++$this->adjacentSources;
		}elseif($blockDecay >= 8){
			$blockDecay = 0;
		}

		return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay;
	}

	/**
	 * @return void
	 */
	protected function checkForHarden(){

	}

	protected function liquidCollide(Block $cause, Block $result) : bool{
		$ev = new BlockFormEvent($this, $result);
		$ev->call();
		if(!$ev->isCancelled()){
			$this->level->setBlock($this, $ev->getNewState(), true, true);
			$this->level->addSound(new FizzSound($this->add(0.5, 0.5, 0.5), 2.6 + (lcg_value() - lcg_value()) * 0.8));
		}
		return true;
	}

	protected function canFlowInto(Block $block) : bool{
		return $block->canBeFlowedInto() and !($block instanceof Liquid and $block->meta === 0); //TODO: I think this should only be liquids of the same type
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class StillWater extends Water{

	protected $id = self::STILL_WATER;

	public function getName() : string{
		return "Still Water";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\event\entity\EntityCombustByBlockEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\Player;

class Lava extends Liquid{

	protected $id = self::FLOWING_LAVA;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getLightLevel() : int{
		return 15;
	}

	public function getName() : string{
		return "Lava";
	}

	public function getStillForm() : Block{
		return BlockFactory::get(Block::STILL_LAVA, $this->meta);
	}

	public function getFlowingForm() : Block{
		return BlockFactory::get(Block::FLOWING_LAVA, $this->meta);
	}

	public function getBucketFillSound() : int{
		return LevelSoundEventPacket::SOUND_BUCKET_FILL_LAVA;
	}

	public function getBucketEmptySound() : int{
		return LevelSoundEventPacket::SOUND_BUCKET_EMPTY_LAVA;
	}

	public function tickRate() : int{
		return 30;
	}

	public function getFlowDecayPerBlock() : int{
		return 2; //TODO: this is 1 in the nether
	}

	protected function checkForHarden(){
		$colliding = null;
		for($side = 1; $side <= 5; ++$side){ //don't check downwards side
			$blockSide = $this->getSide($side);
			if($blockSide instanceof Water){
				$colliding = $blockSide;
				break;
			}
		}

		if($colliding !== null){
			if($this->getDamage() === 0){
				$this->liquidCollide($colliding, BlockFactory::get(Block::OBSIDIAN));
			}elseif($this->getDamage() <= 4){
				$this->liquidCollide($colliding, BlockFactory::get(Block::COBBLESTONE));
			}
		}
	}

	protected function flowIntoBlock(Block $block, int $newFlowDecay) : void{
		if($block instanceof Water){
			$block->liquidCollide($this, BlockFactory::get(Block::STONE));
		}else{
			parent::flowIntoBlock($block, $newFlowDecay);
		}
	}

	public function onEntityCollide(Entity $entity) : void{
		$entity->fallDistance *= 0.5;

		$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
		$entity->attack($ev);

		$ev = new EntityCombustByBlockEvent($this, $entity, 15);
		$ev->call();
		if(!$ev->isCancelled()){
			$entity->setOnFire($ev->getDuration());
		}

		$entity->resetFallDistance();
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$ret = $this->getLevel()->setBlock($this, $this, true, false);
		$this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate());

		return $ret;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class StillLava extends Lava{

	protected $id = self::STILL_LAVA;

	public function getName() : string{
		return "Still Lava";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class Sand extends Fallable{

	protected $id = self::SAND;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getName() : string{
		if($this->getVariant() === 0x01){
			return "Red Sand";
		}

		return "Sand";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\math\Vector3;

abstract class Fallable extends Solid{

	public function onNearbyBlockChange() : void{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() === self::AIR or $down instanceof Liquid or $down instanceof Fire){
			$this->level->setBlock($this, BlockFactory::get(Block::AIR), true);

			$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5));
			$nbt->setInt("TileID", $this->getId());
			$nbt->setByte("Data", $this->getDamage());

			$fall = Entity::createEntity("FallingSand", $this->getLevel(), $nbt);

			if($fall !== null){
				$fall->spawnToAll();
			}
		}
	}

	public function tickFalling() : ?Block{
		return null;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use function mt_rand;

class Gravel extends Fallable{

	protected $id = self::GRAVEL;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Gravel";
	}

	public function getHardness() : float{
		return 0.6;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		if(mt_rand(1, 10) === 1){
			return [
				ItemFactory::get(Item::FLINT)
			];
		}

		return parent::getDropsForCompatibleTool($item);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class GoldOre extends Solid{

	protected $id = self::GOLD_ORE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Gold Ore";
	}

	public function getHardness() : float{
		return 3;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_IRON;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class IronOre extends Solid{

	protected $id = self::IRON_ORE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Iron Ore";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_STONE;
	}

	public function getHardness() : float{
		return 3;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;
use function mt_rand;

class CoalOre extends Solid{

	protected $id = self::COAL_ORE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 3;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Coal Ore";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::COAL)
		];
	}

	protected function getXpDropAmount() : int{
		return mt_rand(0, 2);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\PillarRotationHelper;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Wood extends Solid{
	public const OAK = 0;
	public const SPRUCE = 1;
	public const BIRCH = 2;
	public const JUNGLE = 3;

	protected $id = self::WOOD;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getName() : string{
		static $names = [
			self::OAK => "Oak Wood",
			self::SPRUCE => "Spruce Wood",
			self::BIRCH => "Birch Wood",
			self::JUNGLE => "Jungle Wood"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
		return $this->getLevel()->setBlock($blockReplace, $this, true, true);
	}

	public function getVariantBitmask() : int{
		return 0x03;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getFuelTime() : int{
		return 300;
	}

	public function getFlameEncouragement() : int{
		return 5;
	}

	public function getFlammability() : int{
		return 5;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\event\block\LeavesDecayEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function mt_rand;

class Leaves extends Transparent{
	public const OAK = 0;
	public const SPRUCE = 1;
	public const BIRCH = 2;
	public const JUNGLE = 3;
	public const ACACIA = 0;
	public const DARK_OAK = 1;

	protected $id = self::LEAVES;
	/** @var int */
	protected $woodType = self::WOOD;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHEARS;
	}

	public function getName() : string{
		static $names = [
			self::OAK => "Oak Leaves",
			self::SPRUCE => "Spruce Leaves",
			self::BIRCH => "Birch Leaves",
			self::JUNGLE => "Jungle Leaves"
		];
		return $names[$this->getVariant()];
	}

	public function diffusesSkyLight() : bool{
		return true;
	}

	/**
	 * @param true[] $visited reference parameter
	 * @phpstan-param array<string, true> $visited
	 */
	protected function findLog(Block $pos, array &$visited, int $distance, ?int $fromSide = null) : bool{
		$index = $pos->x . "." . $pos->y . "." . $pos->z;
		if(isset($visited[$index])){
			return false;
		}
		if($pos->getId() === $this->woodType){
			return true;
		}elseif($pos->getId() === $this->id and $distance < 3){
			$visited[$index] = true;
			$down = $pos->getSide(Vector3::SIDE_DOWN)->getId();
			if($down === $this->woodType){
				return true;
			}
			if($fromSide === null){
				for($side = 2; $side <= 5; ++$side){
					if($this->findLog($pos->getSide($side), $visited, $distance + 1, $side)){
						return true;
					}
				}
			}else{ //No more loops
				switch($fromSide){
					case 2:
						if($this->findLog($pos->getSide(Vector3::SIDE_NORTH), $visited, $distance + 1, $fromSide)){
							return true;
						}elseif($this->findLog($pos->getSide(Vector3::SIDE_WEST), $visited, $distance + 1, $fromSide)){
							return true;
						}elseif($this->findLog($pos->getSide(Vector3::SIDE_EAST), $visited, $distance + 1, $fromSide)){
							return true;
						}
						break;
					case 3:
						if($this->findLog($pos->getSide(Vector3::SIDE_SOUTH), $visited, $distance + 1, $fromSide)){
							return true;
						}elseif($this->findLog($pos->getSide(Vector3::SIDE_WEST), $visited, $distance + 1, $fromSide)){
							return true;
						}elseif($this->findLog($pos->getSide(Vector3::SIDE_EAST), $visited, $distance + 1, $fromSide)){
							return true;
						}
						break;
					case 4:
						if($this->findLog($pos->getSide(Vector3::SIDE_NORTH), $visited, $distance + 1, $fromSide)){
							return true;
						}elseif($this->findLog($pos->getSide(Vector3::SIDE_SOUTH), $visited, $distance + 1, $fromSide)){
							return true;
						}elseif($this->findLog($pos->getSide(Vector3::SIDE_WEST), $visited, $distance + 1, $fromSide)){
							return true;
						}
						break;
					case 5:
						if($this->findLog($pos->getSide(Vector3::SIDE_NORTH), $visited, $distance + 1, $fromSide)){
							return true;
						}elseif($this->findLog($pos->getSide(Vector3::SIDE_SOUTH), $visited, $distance + 1, $fromSide)){
							return true;
						}elseif($this->findLog($pos->getSide(Vector3::SIDE_EAST), $visited, $distance + 1, $fromSide)){
							return true;
						}
						break;
				}
			}
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if(($this->meta & 0b00001100) === 0){
			$this->meta |= 0x08;
			$this->getLevel()->setBlock($this, $this, true, false);
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		if(($this->meta & 0b00001100) === 0x08){
			$this->meta &= 0x03;
			$visited = [];

			$ev = new LeavesDecayEvent($this);
			$ev->call();
			if($ev->isCancelled() or $this->findLog($this, $visited, 0)){
				$this->getLevel()->setBlock($this, $this, false, false);
			}else{
				$this->getLevel()->useBreakOn($this);
			}
		}
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$this->meta |= 0x04;
		return $this->getLevel()->setBlock($this, $this, true);
	}

	public function getVariantBitmask() : int{
		return 0x03;
	}

	public function getDrops(Item $item) : array{
		if(($item->getBlockToolType() & BlockToolType::TYPE_SHEARS) !== 0){
			return $this->getDropsForCompatibleTool($item);
		}

		$drops = [];
		if(mt_rand(1, 20) === 1){ //Saplings
			$drops[] = $this->getSaplingItem();
		}
		if($this->canDropApples() and mt_rand(1, 200) === 1){ //Apples
			$drops[] = ItemFactory::get(Item::APPLE);
		}

		return $drops;
	}

	public function getSaplingItem() : Item{
		return ItemFactory::get(Item::SAPLING, $this->getVariant());
	}

	public function canDropApples() : bool{
		return $this->getVariant() === self::OAK;
	}

	public function getFlameEncouragement() : int{
		return 30;
	}

	public function getFlammability() : int{
		return 60;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class Sponge extends Solid{

	protected $id = self::SPONGE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.6;
	}

	public function getName() : string{
		return "Sponge";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;

class Glass extends Transparent{

	protected $id = self::GLASS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Glass";
	}

	public function getHardness() : float{
		return 0.3;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;
use function mt_rand;

class LapisOre extends Solid{

	protected $id = self::LAPIS_ORE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 3;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_STONE;
	}

	public function getName() : string{
		return "Lapis Lazuli Ore";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::DYE, 4, mt_rand(4, 8))
		];
	}

	protected function getXpDropAmount() : int{
		return mt_rand(2, 5);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Lapis extends Solid{

	protected $id = self::LAPIS_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Lapis Lazuli Block";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_STONE;
	}

	public function getHardness() : float{
		return 3;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Sandstone extends Solid{

	public const NORMAL = 0;
	public const CHISELED = 1;
	public const SMOOTH = 2;

	protected $id = self::SANDSTONE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.8;
	}

	public function getName() : string{
		static $names = [
			self::NORMAL => "Sandstone",
			self::CHISELED => "Chiseled Sandstone",
			self::SMOOTH => "Smooth Sandstone"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getVariantBitmask() : int{
		return 0x03;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class NoteBlock extends Solid{

	protected $id = self::NOTE_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Note Block";
	}

	public function getFuelTime() : int{
		return 300;
	}

	public function getHardness() : float{
		return 0.8;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\lang\TranslationContainer;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\Bed as TileBed;
use pocketmine\tile\Tile;
use pocketmine\utils\TextFormat;

class Bed extends Transparent{
	public const BITFLAG_OCCUPIED = 0x04;
	public const BITFLAG_HEAD = 0x08;

	protected $id = self::BED_BLOCK;

	protected $itemId = Item::BED;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.2;
	}

	public function getName() : string{
		return "Bed Block";
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return new AxisAlignedBB(
			$this->x,
			$this->y,
			$this->z,
			$this->x + 1,
			$this->y + 0.5625,
			$this->z + 1
		);
	}

	public function isHeadPart() : bool{
		return ($this->meta & self::BITFLAG_HEAD) !== 0;
	}

	public function isOccupied() : bool{
		return ($this->meta & self::BITFLAG_OCCUPIED) !== 0;
	}

	/**
	 * @return void
	 */
	public function setOccupied(bool $occupied = true){
		if($occupied){
			$this->meta |= self::BITFLAG_OCCUPIED;
		}else{
			$this->meta &= ~self::BITFLAG_OCCUPIED;
		}

		$this->getLevel()->setBlock($this, $this, false, false);

		if(($other = $this->getOtherHalf()) !== null and $other->isOccupied() !== $occupied){
			$other->setOccupied($occupied);
		}
	}

	public static function getOtherHalfSide(int $meta, bool $isHead = false) : int{
		$rotation = $meta & 0x03;
		$side = -1;

		switch($rotation){
			case 0x00: //South
				$side = Vector3::SIDE_SOUTH;
				break;
			case 0x01: //West
				$side = Vector3::SIDE_WEST;
				break;
			case 0x02: //North
				$side = Vector3::SIDE_NORTH;
				break;
			case 0x03: //East
				$side = Vector3::SIDE_EAST;
				break;
		}

		if($isHead){
			$side = Vector3::getOppositeSide($side);
		}

		return $side;
	}

	public function getOtherHalf() : ?Bed{
		$other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart()));
		if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){
			return $other;
		}

		return null;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($player !== null){
			$other = $this->getOtherHalf();
			if($other === null){
				$player->sendMessage(TextFormat::GRAY . "This bed is incomplete");

				return true;
			}elseif($player->distanceSquared($this) > 4 and $player->distanceSquared($other) > 4){
				$player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.tooFar"));
				return true;
			}

			$time = $this->getLevel()->getTime() % Level::TIME_FULL;

			$isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE);

			if(!$isNight){
				$player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.noSleep"));

				return true;
			}

			$b = ($this->isHeadPart() ? $this : $other);

			if($b->isOccupied()){
				$player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.occupied"));

				return true;
			}

			$player->sleepOn($b);
		}

		return true;

	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if(!$down->isTransparent()){
			$meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03;
			$next = $this->getSide(self::getOtherHalfSide($meta));
			if($next->canBeReplaced() and !$next->getSide(Vector3::SIDE_DOWN)->isTransparent()){
				$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
				$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);

				Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player));
				Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player));

				return true;
			}
		}

		return false;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		if($this->isHeadPart()){
			return [$this->getItem()];
		}

		return [];
	}

	public function getPickedItem() : Item{
		return $this->getItem();
	}

	private function getItem() : Item{
		$tile = $this->getLevel()->getTile($this);
		if($tile instanceof TileBed){
			return ItemFactory::get($this->getItemId(), $tile->getColor());
		}

		return ItemFactory::get($this->getItemId(), 14); //Red
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}

	public function getAffectedBlocks() : array{
		if(($other = $this->getOtherHalf()) !== null){
			return [$this, $other];
		}

		return parent::getAffectedBlocks();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * All the Item classes
 */
namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\block\BlockToolType;
use pocketmine\entity\Entity;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\enchantment\EnchantmentInstance;
use pocketmine\math\Vector3;
use pocketmine\nbt\LittleEndianNBTStream;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\NamedTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\utils\Binary;
use function array_map;
use function base64_decode;
use function base64_encode;
use function file_get_contents;
use function get_class;
use function hex2bin;
use function is_string;
use function json_decode;
use function strlen;
use const DIRECTORY_SEPARATOR;

class Item implements ItemIds, \JsonSerializable{
	public const TAG_ENCH = "ench";
	public const TAG_DISPLAY = "display";
	public const TAG_BLOCK_ENTITY_TAG = "BlockEntityTag";

	public const TAG_DISPLAY_NAME = "Name";
	public const TAG_DISPLAY_LORE = "Lore";

	/** @var LittleEndianNBTStream|null */
	private static $cachedParser = null;

	private static function parseCompoundTag(string $tag) : CompoundTag{
		if($tag === ""){
			throw new \InvalidArgumentException("No NBT data found in supplied string");
		}

		if(self::$cachedParser === null){
			self::$cachedParser = new LittleEndianNBTStream();
		}

		$data = self::$cachedParser->read($tag);
		if(!($data instanceof CompoundTag)){
			throw new \InvalidArgumentException("Invalid item NBT string given, it could not be deserialized");
		}

		return $data;
	}

	private static function writeCompoundTag(CompoundTag $tag) : string{
		if(self::$cachedParser === null){
			self::$cachedParser = new LittleEndianNBTStream();
		}

		return self::$cachedParser->write($tag);
	}

	/**
	 * Returns a new Item instance with the specified ID, damage, count and NBT.
	 *
	 * This function redirects to {@link ItemFactory#get}.
	 *
	 * @param CompoundTag|string $tags
	 */
	public static function get(int $id, int $meta = 0, int $count = 1, $tags = "") : Item{
		return ItemFactory::get($id, $meta, $count, $tags);
	}

	/**
	 * Tries to parse the specified string into Item ID/meta identifiers, and returns Item instances it created.
	 *
	 * This function redirects to {@link ItemFactory#fromString}.
	 *
	 * @return Item[]|Item
	 */
	public static function fromString(string $str, bool $multiple = false){
		return ItemFactory::fromString($str, $multiple);
	}

	/** @var Item[] */
	private static $creative = [];

	/**
	 * @return void
	 */
	public static function initCreativeItems(){
		self::clearCreativeItems();

		$creativeItems = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla" . DIRECTORY_SEPARATOR . "creativeitems.json"), true);

		foreach($creativeItems as $data){
			$item = Item::jsonDeserialize($data);
			if($item->getName() === "Unknown"){
				continue;
			}
			self::addCreativeItem($item);
		}
	}

	/**
	 * Removes all previously added items from the creative menu.
	 * Note: Players who are already online when this is called will not see this change.
	 *
	 * @return void
	 */
	public static function clearCreativeItems(){
		Item::$creative = [];
	}

	/**
	 * @return Item[]
	 */
	public static function getCreativeItems() : array{
		return Item::$creative;
	}

	/**
	 * Adds an item to the creative menu.
	 * Note: Players who are already online when this is called will not see this change.
	 *
	 * @return void
	 */
	public static function addCreativeItem(Item $item){
		Item::$creative[] = clone $item;
	}

	/**
	 * Removes an item from the creative menu.
	 * Note: Players who are already online when this is called will not see this change.
	 *
	 * @return void
	 */
	public static function removeCreativeItem(Item $item){
		$index = self::getCreativeItemIndex($item);
		if($index !== -1){
			unset(Item::$creative[$index]);
		}
	}

	public static function isCreativeItem(Item $item) : bool{
		return Item::getCreativeItemIndex($item) !== -1;
	}

	/**
	 * @return Item|null
	 */
	public static function getCreativeItem(int $index){
		return Item::$creative[$index] ?? null;
	}

	public static function getCreativeItemIndex(Item $item) : int{
		foreach(Item::$creative as $i => $d){
			if($item->equals($d, !($item instanceof Durable))){
				return $i;
			}
		}

		return -1;
	}

	/** @var int */
	protected $id;
	/** @var int */
	protected $meta;
	/** @var CompoundTag|null */
	private $nbt = null;
	/** @var int */
	public $count = 1;
	/** @var string */
	protected $name;

	/**
	 * Constructs a new Item type. This constructor should ONLY be used when constructing a new item TYPE to register
	 * into the index.
	 *
	 * NOTE: This should NOT BE USED for creating items to set into an inventory. Use {@link ItemFactory#get} for that
	 * purpose.
	 */
	public function __construct(int $id, int $meta = 0, string $name = "Unknown"){
		if($id < -0x8000 or $id > 0x7fff){ //signed short range
			throw new \InvalidArgumentException("ID must be in range " . -0x8000 . " - " . 0x7fff);
		}
		$this->id = $id;
		$this->setDamage($meta);
		$this->name = $name;
	}

	/**
	 * @deprecated This method accepts NBT serialized in a network-dependent format.
	 * @see Item::setNamedTag()
	 *
	 * @param CompoundTag|string|null $tags
	 *
	 * @return $this
	 */
	public function setCompoundTag($tags) : Item{
		if($tags instanceof CompoundTag){
			$this->setNamedTag($tags);
		}elseif(is_string($tags) and strlen($tags) > 0){
			$this->setNamedTag(self::parseCompoundTag($tags));
		}else{
			$this->clearNamedTag();
		}

		return $this;
	}

	/**
	 * @deprecated This method returns NBT serialized in a network-dependent format. Prefer use of getNamedTag() instead.
	 * @see Item::getNamedTag()
	 *
	 * Returns the serialized NBT of the Item
	 */
	public function getCompoundTag() : string{
		return $this->nbt !== null ? self::writeCompoundTag($this->nbt) : "";
	}

	/**
	 * Returns whether this Item has a non-empty NBT.
	 */
	public function hasCompoundTag() : bool{
		return $this->nbt !== null and $this->nbt->getCount() > 0;
	}

	public function hasCustomBlockData() : bool{
		return $this->getNamedTagEntry(self::TAG_BLOCK_ENTITY_TAG) instanceof CompoundTag;
	}

	/**
	 * @return $this
	 */
	public function clearCustomBlockData(){
		$this->removeNamedTagEntry(self::TAG_BLOCK_ENTITY_TAG);
		return $this;
	}

	/**
	 * @return $this
	 */
	public function setCustomBlockData(CompoundTag $compound) : Item{
		$tags = clone $compound;
		$tags->setName(self::TAG_BLOCK_ENTITY_TAG);
		$this->setNamedTagEntry($tags);

		return $this;
	}

	public function getCustomBlockData() : ?CompoundTag{
		$tag = $this->getNamedTagEntry(self::TAG_BLOCK_ENTITY_TAG);
		return $tag instanceof CompoundTag ? $tag : null;
	}

	public function hasEnchantments() : bool{
		return $this->getNamedTagEntry(self::TAG_ENCH) instanceof ListTag;
	}

	public function hasEnchantment(int $id, int $level = -1) : bool{
		$ench = $this->getNamedTagEntry(self::TAG_ENCH);
		if(!($ench instanceof ListTag)){
			return false;
		}

		/** @var CompoundTag $entry */
		foreach($ench as $entry){
			if($entry->getShort("id") === $id and ($level === -1 or $entry->getShort("lvl") === $level)){
				return true;
			}
		}

		return false;
	}

	public function getEnchantment(int $id) : ?EnchantmentInstance{
		$ench = $this->getNamedTagEntry(self::TAG_ENCH);
		if(!($ench instanceof ListTag)){
			return null;
		}

		/** @var CompoundTag $entry */
		foreach($ench as $entry){
			if($entry->getShort("id") === $id){
				$e = Enchantment::getEnchantment($entry->getShort("id"));
				if($e !== null){
					return new EnchantmentInstance($e, $entry->getShort("lvl"));
				}
			}
		}

		return null;
	}

	public function removeEnchantment(int $id, int $level = -1) : void{
		$ench = $this->getNamedTagEntry(self::TAG_ENCH);
		if(!($ench instanceof ListTag)){
			return;
		}

		/** @var CompoundTag $entry */
		foreach($ench as $k => $entry){
			if($entry->getShort("id") === $id and ($level === -1 or $entry->getShort("lvl") === $level)){
				$ench->remove($k);
				break;
			}
		}

		$this->setNamedTagEntry($ench);
	}

	public function removeEnchantments() : void{
		$this->removeNamedTagEntry(self::TAG_ENCH);
	}

	public function addEnchantment(EnchantmentInstance $enchantment) : void{
		$found = false;

		$ench = $this->getNamedTagEntry(self::TAG_ENCH);
		if(!($ench instanceof ListTag)){
			$ench = new ListTag(self::TAG_ENCH, [], NBT::TAG_Compound);
		}else{
			/** @var CompoundTag $entry */
			foreach($ench as $k => $entry){
				if($entry->getShort("id") === $enchantment->getId()){
					$ench->set($k, new CompoundTag("", [
						new ShortTag("id", $enchantment->getId()),
						new ShortTag("lvl", $enchantment->getLevel())
					]));
					$found = true;
					break;
				}
			}
		}

		if(!$found){
			$ench->push(new CompoundTag("", [
				new ShortTag("id", $enchantment->getId()),
				new ShortTag("lvl", $enchantment->getLevel())
			]));
		}

		$this->setNamedTagEntry($ench);
	}

	/**
	 * @return EnchantmentInstance[]
	 */
	public function getEnchantments() : array{
		/** @var EnchantmentInstance[] $enchantments */
		$enchantments = [];

		$ench = $this->getNamedTagEntry(self::TAG_ENCH);
		if($ench instanceof ListTag){
			/** @var CompoundTag $entry */
			foreach($ench as $entry){
				$e = Enchantment::getEnchantment($entry->getShort("id"));
				if($e !== null){
					$enchantments[] = new EnchantmentInstance($e, $entry->getShort("lvl"));
				}
			}
		}

		return $enchantments;
	}

	/**
	 * Returns the level of the enchantment on this item with the specified ID, or 0 if the item does not have the
	 * enchantment.
	 */
	public function getEnchantmentLevel(int $enchantmentId) : int{
		$ench = $this->getNamedTag()->getListTag(self::TAG_ENCH);
		if($ench !== null){
			/** @var CompoundTag $entry */
			foreach($ench as $entry){
				if($entry->getShort("id") === $enchantmentId){
					return $entry->getShort("lvl");
				}
			}
		}

		return 0;
	}

	public function hasCustomName() : bool{
		$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
		if($display instanceof CompoundTag){
			return $display->hasTag(self::TAG_DISPLAY_NAME);
		}

		return false;
	}

	public function getCustomName() : string{
		$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
		if($display instanceof CompoundTag){
			return $display->getString(self::TAG_DISPLAY_NAME, "");
		}

		return "";
	}

	/**
	 * @return $this
	 */
	public function setCustomName(string $name) : Item{
		if($name === ""){
			return $this->clearCustomName();
		}

		$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
		if(!($display instanceof CompoundTag)){
			$display = new CompoundTag(self::TAG_DISPLAY);
		}

		$display->setString(self::TAG_DISPLAY_NAME, $name);
		$this->setNamedTagEntry($display);

		return $this;
	}

	/**
	 * @return $this
	 */
	public function clearCustomName() : Item{
		$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
		if($display instanceof CompoundTag){
			$display->removeTag(self::TAG_DISPLAY_NAME);

			if($display->getCount() === 0){
				$this->removeNamedTagEntry($display->getName());
			}else{
				$this->setNamedTagEntry($display);
			}
		}

		return $this;
	}

	/**
	 * @return string[]
	 */
	public function getLore() : array{
		$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
		if($display instanceof CompoundTag and ($lore = $display->getListTag(self::TAG_DISPLAY_LORE)) !== null){
			return $lore->getAllValues();
		}

		return [];
	}

	/**
	 * @param string[] $lines
	 *
	 * @return $this
	 */
	public function setLore(array $lines) : Item{
		$display = $this->getNamedTagEntry(self::TAG_DISPLAY);
		if(!($display instanceof CompoundTag)){
			$display = new CompoundTag(self::TAG_DISPLAY, []);
		}

		$display->setTag(new ListTag(self::TAG_DISPLAY_LORE, array_map(function(string $str) : StringTag{
			return new StringTag("", $str);
		}, $lines), NBT::TAG_String));

		$this->setNamedTagEntry($display);

		return $this;
	}

	public function getNamedTagEntry(string $name) : ?NamedTag{
		return $this->getNamedTag()->getTag($name);
	}

	public function setNamedTagEntry(NamedTag $new) : void{
		$tag = $this->getNamedTag();
		$tag->setTag($new);
		$this->setNamedTag($tag);
	}

	public function removeNamedTagEntry(string $name) : void{
		$tag = $this->getNamedTag();
		$tag->removeTag($name);
		$this->setNamedTag($tag);
	}

	/**
	 * Returns a tree of Tag objects representing the Item's NBT. If the item does not have any NBT, an empty CompoundTag
	 * object is returned to allow the caller to manipulate and apply back to the item.
	 */
	public function getNamedTag() : CompoundTag{
		return $this->nbt ?? ($this->nbt = new CompoundTag());
	}

	/**
	 * Sets the Item's NBT from the supplied CompoundTag object.
	 *
	 * @return $this
	 */
	public function setNamedTag(CompoundTag $tag) : Item{
		if($tag->getCount() === 0){
			return $this->clearNamedTag();
		}

		$this->nbt = clone $tag;

		return $this;
	}

	/**
	 * Removes the Item's NBT.
	 * @return $this
	 */
	public function clearNamedTag() : Item{
		$this->nbt = null;
		return $this;
	}

	public function getCount() : int{
		return $this->count;
	}

	/**
	 * @return $this
	 */
	public function setCount(int $count) : Item{
		$this->count = $count;

		return $this;
	}

	/**
	 * Pops an item from the stack and returns it, decreasing the stack count of this item stack by one.
	 *
	 * @return $this
	 * @throws \InvalidArgumentException if trying to pop more items than are on the stack
	 */
	public function pop(int $count = 1) : Item{
		if($count > $this->count){
			throw new \InvalidArgumentException("Cannot pop $count items from a stack of $this->count");
		}

		$item = clone $this;
		$item->count = $count;

		$this->count -= $count;

		return $item;
	}

	public function isNull() : bool{
		return $this->count <= 0 or $this->id === Item::AIR;
	}

	/**
	 * Returns the name of the item, or the custom name if it is set.
	 */
	final public function getName() : string{
		return $this->hasCustomName() ? $this->getCustomName() : $this->getVanillaName();
	}

	/**
	 * Returns the vanilla name of the item, disregarding custom names.
	 */
	public function getVanillaName() : string{
		return $this->name;
	}

	final public function canBePlaced() : bool{
		return $this->getBlock()->canBePlaced();
	}

	/**
	 * Returns the block corresponding to this Item.
	 */
	public function getBlock() : Block{
		return BlockFactory::get(self::AIR);
	}

	final public function getId() : int{
		return $this->id;
	}

	final public function getDamage() : int{
		return $this->meta;
	}

	/**
	 * @return $this
	 */
	public function setDamage(int $meta) : Item{
		$this->meta = $meta !== -1 ? $meta & 0x7FFF : -1;

		return $this;
	}

	/**
	 * Returns whether this item can match any item with an equivalent ID with any meta value.
	 * Used in crafting recipes which accept multiple variants of the same item, for example crafting tables recipes.
	 */
	public function hasAnyDamageValue() : bool{
		return $this->meta === -1;
	}

	/**
	 * Returns the highest amount of this item which will fit into one inventory slot.
	 */
	public function getMaxStackSize() : int{
		return 64;
	}

	/**
	 * Returns the time in ticks which the item will fuel a furnace for.
	 */
	public function getFuelTime() : int{
		return 0;
	}

	/**
	 * Returns how many points of damage this item will deal to an entity when used as a weapon.
	 */
	public function getAttackPoints() : int{
		return 1;
	}

	/**
	 * Returns how many armor points can be gained by wearing this item.
	 */
	public function getDefensePoints() : int{
		return 0;
	}

	/**
	 * Returns what type of block-breaking tool this is. Blocks requiring the same tool type as the item will break
	 * faster (except for blocks requiring no tool, which break at the same speed regardless of the tool used)
	 */
	public function getBlockToolType() : int{
		return BlockToolType::TYPE_NONE;
	}

	/**
	 * Returns the harvesting power that this tool has. This affects what blocks it can mine when the tool type matches
	 * the mined block.
	 * This should return 1 for non-tiered tools, and the tool tier for tiered tools.
	 *
	 * @see Block::getToolHarvestLevel()
	 */
	public function getBlockToolHarvestLevel() : int{
		return 0;
	}

	public function getMiningEfficiency(Block $block) : float{
		return 1;
	}

	/**
	 * Called when a player uses this item on a block.
	 */
	public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{
		return false;
	}

	/**
	 * Called when a player uses the item on air, for example throwing a projectile.
	 * Returns whether the item was changed, for example count decrease or durability change.
	 */
	public function onClickAir(Player $player, Vector3 $directionVector) : bool{
		return false;
	}

	/**
	 * Called when a player is using this item and releases it. Used to handle bow shoot actions.
	 * Returns whether the item was changed, for example count decrease or durability change.
	 */
	public function onReleaseUsing(Player $player) : bool{
		return false;
	}

	/**
	 * Called when this item is used to destroy a block. Usually used to update durability.
	 */
	public function onDestroyBlock(Block $block) : bool{
		return false;
	}

	/**
	 * Called when this item is used to attack an entity. Usually used to update durability.
	 */
	public function onAttackEntity(Entity $victim) : bool{
		return false;
	}

	/**
	 * Returns the number of ticks a player must wait before activating this item again.
	 */
	public function getCooldownTicks() : int{
		return 0;
	}

	/**
	 * Compares an Item to this Item and check if they match.
	 *
	 * @param bool $checkDamage Whether to verify that the damage values match.
	 * @param bool $checkCompound Whether to verify that the items' NBT match.
	 */
	final public function equals(Item $item, bool $checkDamage = true, bool $checkCompound = true) : bool{
		return $this->id === $item->getId() and
			(!$checkDamage or $this->getDamage() === $item->getDamage()) and
			(!$checkCompound or $this->getNamedTag()->equals($item->getNamedTag()));
	}

	/**
	 * Returns whether the specified item stack has the same ID, damage, NBT and count as this item stack.
	 */
	final public function equalsExact(Item $other) : bool{
		return $this->equals($other, true, true) and $this->count === $other->count;
	}

	final public function __toString() : string{
		return "Item " . $this->name . " (" . $this->id . ":" . ($this->hasAnyDamageValue() ? "?" : $this->meta) . ")x" . $this->count . ($this->hasCompoundTag() ? " tags:" . base64_encode($this->getCompoundTag()) : "");
	}

	/**
	 * Returns an array of item stack properties that can be serialized to json.
	 *
	 * @return mixed[]
	 * @phpstan-return array{id: int, damage?: int, count?: int, nbt_b64?: string}
	 */
	final public function jsonSerialize() : array{
		$data = [
			"id" => $this->getId()
		];

		if($this->getDamage() !== 0){
			$data["damage"] = $this->getDamage();
		}

		if($this->getCount() !== 1){
			$data["count"] = $this->getCount();
		}

		if($this->hasCompoundTag()){
			$data["nbt_b64"] = base64_encode($this->getCompoundTag());
		}

		return $data;
	}

	/**
	 * Returns an Item from properties created in an array by {@link Item#jsonSerialize}
	 * @param mixed[] $data
	 * @phpstan-param array{
	 * 	id: int,
	 * 	damage?: int,
	 * 	count?: int,
	 * 	nbt?: string,
	 * 	nbt_hex?: string,
	 * 	nbt_b64?: string
	 * } $data
	 */
	final public static function jsonDeserialize(array $data) : Item{
		$nbt = "";

		//Backwards compatibility
		if(isset($data["nbt"])){
			$nbt = $data["nbt"];
		}elseif(isset($data["nbt_hex"])){
			$nbt = hex2bin($data["nbt_hex"]);
		}elseif(isset($data["nbt_b64"])){
			$nbt = base64_decode($data["nbt_b64"], true);
		}
		return ItemFactory::get(
			(int) $data["id"],
			(int) ($data["damage"] ?? 0),
			(int) ($data["count"] ?? 1),
			(string) $nbt
		);
	}

	/**
	 * Serializes the item to an NBT CompoundTag
	 *
	 * @param int    $slot optional, the inventory slot of the item
	 * @param string $tagName the name to assign to the CompoundTag object
	 */
	public function nbtSerialize(int $slot = -1, string $tagName = "") : CompoundTag{
		$result = new CompoundTag($tagName, [
			new ShortTag("id", $this->id),
			new ByteTag("Count", Binary::signByte($this->count)),
			new ShortTag("Damage", $this->meta)
		]);

		if($this->hasCompoundTag()){
			$itemNBT = clone $this->getNamedTag();
			$itemNBT->setName("tag");
			$result->setTag($itemNBT);
		}

		if($slot !== -1){
			$result->setByte("Slot", $slot);
		}

		return $result;
	}

	/**
	 * Deserializes an Item from an NBT CompoundTag
	 */
	public static function nbtDeserialize(CompoundTag $tag) : Item{
		if(!$tag->hasTag("id") or !$tag->hasTag("Count")){
			return ItemFactory::get(0);
		}

		$count = Binary::unsignByte($tag->getByte("Count"));
		$meta = $tag->getShort("Damage", 0);

		$idTag = $tag->getTag("id");
		if($idTag instanceof ShortTag){
			$item = ItemFactory::get($idTag->getValue(), $meta, $count);
		}elseif($idTag instanceof StringTag){ //PC item save format
			try{
				$item = ItemFactory::fromString($idTag->getValue());
			}catch(\InvalidArgumentException $e){
				//TODO: improve error handling
				return ItemFactory::get(Item::AIR, 0, 0);
			}
			$item->setDamage($meta);
			$item->setCount($count);
		}else{
			throw new \InvalidArgumentException("Item CompoundTag ID must be an instance of StringTag or ShortTag, " . get_class($idTag) . " given");
		}

		$itemNBT = $tag->getCompoundTag("tag");
		if($itemNBT instanceof CompoundTag){
			/** @var CompoundTag $t */
			$t = clone $itemNBT;
			$t->setName("");
			$item->setNamedTag($t);
		}

		return $item;
	}

	public function __clone(){
		if($this->nbt !== null){
			$this->nbt = clone $this->nbt;
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\BlockIds;

interface ItemIds extends BlockIds{

	public const IRON_SHOVEL = 256;
	public const IRON_PICKAXE = 257;
	public const IRON_AXE = 258;
	public const FLINT_AND_STEEL = 259, FLINT_STEEL = 259;
	public const APPLE = 260;
	public const BOW = 261;
	public const ARROW = 262;
	public const COAL = 263;
	public const DIAMOND = 264;
	public const IRON_INGOT = 265;
	public const GOLD_INGOT = 266;
	public const IRON_SWORD = 267;
	public const WOODEN_SWORD = 268;
	public const WOODEN_SHOVEL = 269;
	public const WOODEN_PICKAXE = 270;
	public const WOODEN_AXE = 271;
	public const STONE_SWORD = 272;
	public const STONE_SHOVEL = 273;
	public const STONE_PICKAXE = 274;
	public const STONE_AXE = 275;
	public const DIAMOND_SWORD = 276;
	public const DIAMOND_SHOVEL = 277;
	public const DIAMOND_PICKAXE = 278;
	public const DIAMOND_AXE = 279;
	public const STICK = 280;
	public const BOWL = 281;
	public const MUSHROOM_STEW = 282;
	public const GOLDEN_SWORD = 283, GOLD_SWORD = 283;
	public const GOLDEN_SHOVEL = 284, GOLD_SHOVEL = 284;
	public const GOLDEN_PICKAXE = 285, GOLD_PICKAXE = 285;
	public const GOLDEN_AXE = 286, GOLD_AXE = 286;
	public const STRING = 287;
	public const FEATHER = 288;
	public const GUNPOWDER = 289;
	public const WOODEN_HOE = 290;
	public const STONE_HOE = 291;
	public const IRON_HOE = 292;
	public const DIAMOND_HOE = 293;
	public const GOLDEN_HOE = 294, GOLD_HOE = 294;
	public const SEEDS = 295, WHEAT_SEEDS = 295;
	public const WHEAT = 296;
	public const BREAD = 297;
	public const LEATHER_CAP = 298, LEATHER_HELMET = 298;
	public const LEATHER_CHESTPLATE = 299, LEATHER_TUNIC = 299;
	public const LEATHER_LEGGINGS = 300, LEATHER_PANTS = 300;
	public const LEATHER_BOOTS = 301;
	public const CHAINMAIL_HELMET = 302, CHAIN_HELMET = 302;
	public const CHAINMAIL_CHESTPLATE = 303, CHAIN_CHESTPLATE = 303;
	public const CHAINMAIL_LEGGINGS = 304, CHAIN_LEGGINGS = 304;
	public const CHAINMAIL_BOOTS = 305, CHAIN_BOOTS = 305;
	public const IRON_HELMET = 306;
	public const IRON_CHESTPLATE = 307;
	public const IRON_LEGGINGS = 308;
	public const IRON_BOOTS = 309;
	public const DIAMOND_HELMET = 310;
	public const DIAMOND_CHESTPLATE = 311;
	public const DIAMOND_LEGGINGS = 312;
	public const DIAMOND_BOOTS = 313;
	public const GOLDEN_HELMET = 314, GOLD_HELMET = 314;
	public const GOLDEN_CHESTPLATE = 315, GOLD_CHESTPLATE = 315;
	public const GOLDEN_LEGGINGS = 316, GOLD_LEGGINGS = 316;
	public const GOLDEN_BOOTS = 317, GOLD_BOOTS = 317;
	public const FLINT = 318;
	public const PORKCHOP = 319, RAW_PORKCHOP = 319;
	public const COOKED_PORKCHOP = 320;
	public const PAINTING = 321;
	public const GOLDEN_APPLE = 322;
	public const SIGN = 323;
	public const OAK_DOOR = 324, WOODEN_DOOR = 324;
	public const BUCKET = 325;

	public const MINECART = 328;
	public const SADDLE = 329;
	public const IRON_DOOR = 330;
	public const REDSTONE = 331, REDSTONE_DUST = 331;
	public const SNOWBALL = 332;
	public const BOAT = 333;
	public const LEATHER = 334;
	public const KELP = 335;
	public const BRICK = 336;
	public const CLAY = 337, CLAY_BALL = 337;
	public const REEDS = 338, SUGARCANE = 338;
	public const PAPER = 339;
	public const BOOK = 340;
	public const SLIMEBALL = 341, SLIME_BALL = 341;
	public const CHEST_MINECART = 342, MINECART_WITH_CHEST = 342;

	public const EGG = 344;
	public const COMPASS = 345;
	public const FISHING_ROD = 346;
	public const CLOCK = 347;
	public const GLOWSTONE_DUST = 348;
	public const FISH = 349, RAW_FISH = 349;
	public const COOKED_FISH = 350;
	public const DYE = 351;
	public const BONE = 352;
	public const SUGAR = 353;
	public const CAKE = 354;
	public const BED = 355;
	public const REPEATER = 356;
	public const COOKIE = 357;
	public const FILLED_MAP = 358;
	public const SHEARS = 359;
	public const MELON = 360, MELON_SLICE = 360;
	public const PUMPKIN_SEEDS = 361;
	public const MELON_SEEDS = 362;
	public const BEEF = 363, RAW_BEEF = 363;
	public const COOKED_BEEF = 364, STEAK = 364;
	public const CHICKEN = 365, RAW_CHICKEN = 365;
	public const COOKED_CHICKEN = 366;
	public const ROTTEN_FLESH = 367;
	public const ENDER_PEARL = 368;
	public const BLAZE_ROD = 369;
	public const GHAST_TEAR = 370;
	public const GOLDEN_NUGGET = 371, GOLD_NUGGET = 371;
	public const NETHER_WART = 372;
	public const POTION = 373;
	public const GLASS_BOTTLE = 374;
	public const SPIDER_EYE = 375;
	public const FERMENTED_SPIDER_EYE = 376;
	public const BLAZE_POWDER = 377;
	public const MAGMA_CREAM = 378;
	public const BREWING_STAND = 379;
	public const CAULDRON = 380;
	public const ENDER_EYE = 381;
	public const GLISTERING_MELON = 382, SPECKLED_MELON = 382;
	public const SPAWN_EGG = 383;
	public const BOTTLE_O_ENCHANTING = 384, EXPERIENCE_BOTTLE = 384;
	public const FIREBALL = 385, FIRE_CHARGE = 385;
	public const WRITABLE_BOOK = 386;
	public const WRITTEN_BOOK = 387;
	public const EMERALD = 388;
	public const FRAME = 389, ITEM_FRAME = 389;
	public const FLOWER_POT = 390;
	public const CARROT = 391;
	public const POTATO = 392;
	public const BAKED_POTATO = 393;
	public const POISONOUS_POTATO = 394;
	public const EMPTYMAP = 395, EMPTY_MAP = 395, MAP = 395;
	public const GOLDEN_CARROT = 396;
	public const MOB_HEAD = 397, SKULL = 397;
	public const CARROTONASTICK = 398, CARROT_ON_A_STICK = 398;
	public const NETHERSTAR = 399, NETHER_STAR = 399;
	public const PUMPKIN_PIE = 400;
	public const FIREWORKS = 401;
	public const FIREWORKSCHARGE = 402, FIREWORKS_CHARGE = 402;
	public const ENCHANTED_BOOK = 403;
	public const COMPARATOR = 404;
	public const NETHERBRICK = 405, NETHER_BRICK = 405;
	public const NETHER_QUARTZ = 406, QUARTZ = 406;
	public const MINECART_WITH_TNT = 407, TNT_MINECART = 407;
	public const HOPPER_MINECART = 408, MINECART_WITH_HOPPER = 408;
	public const PRISMARINE_SHARD = 409;
	public const HOPPER = 410;
	public const RABBIT = 411, RAW_RABBIT = 411;
	public const COOKED_RABBIT = 412;
	public const RABBIT_STEW = 413;
	public const RABBIT_FOOT = 414;
	public const RABBIT_HIDE = 415;
	public const HORSEARMORLEATHER = 416, HORSE_ARMOR_LEATHER = 416, LEATHER_HORSE_ARMOR = 416;
	public const HORSEARMORIRON = 417, HORSE_ARMOR_IRON = 417, IRON_HORSE_ARMOR = 417;
	public const GOLD_HORSE_ARMOR = 418, GOLDEN_HORSE_ARMOR = 418, HORSEARMORGOLD = 418, HORSE_ARMOR_GOLD = 418;
	public const DIAMOND_HORSE_ARMOR = 419, HORSEARMORDIAMOND = 419, HORSE_ARMOR_DIAMOND = 419;
	public const LEAD = 420;
	public const NAMETAG = 421, NAME_TAG = 421;
	public const PRISMARINE_CRYSTALS = 422;
	public const MUTTON = 423, MUTTONRAW = 423, MUTTON_RAW = 423, RAW_MUTTON = 423;
	public const COOKED_MUTTON = 424, MUTTONCOOKED = 424, MUTTON_COOKED = 424;
	public const ARMOR_STAND = 425;
	public const END_CRYSTAL = 426;
	public const SPRUCE_DOOR = 427;
	public const BIRCH_DOOR = 428;
	public const JUNGLE_DOOR = 429;
	public const ACACIA_DOOR = 430;
	public const DARK_OAK_DOOR = 431;
	public const CHORUS_FRUIT = 432;
	public const CHORUS_FRUIT_POPPED = 433;
	public const BANNER_PATTERN = 434;

	public const DRAGON_BREATH = 437;
	public const SPLASH_POTION = 438;

	public const LINGERING_POTION = 441;
	public const SPARKLER = 442;
	public const COMMAND_BLOCK_MINECART = 443, MINECART_WITH_COMMAND_BLOCK = 443;
	public const ELYTRA = 444;
	public const SHULKER_SHELL = 445;
	public const BANNER = 446;
	public const MEDICINE = 447;
	public const BALLOON = 448;
	public const RAPID_FERTILIZER = 449;
	public const TOTEM = 450;
	public const BLEACH = 451;
	public const IRON_NUGGET = 452;
	public const ICE_BOMB = 453;

	public const TRIDENT = 455;

	public const BEETROOT = 457;
	public const BEETROOT_SEEDS = 458;
	public const BEETROOT_SOUP = 459;
	public const RAW_SALMON = 460, SALMON = 460;
	public const CLOWNFISH = 461;
	public const PUFFERFISH = 462;
	public const COOKED_SALMON = 463;
	public const DRIED_KELP = 464;
	public const NAUTILUS_SHELL = 465;
	public const APPLEENCHANTED = 466, APPLE_ENCHANTED = 466, ENCHANTED_GOLDEN_APPLE = 466;
	public const HEART_OF_THE_SEA = 467;
	public const TURTLE_SHELL_PIECE = 468;
	public const TURTLE_HELMET = 469;
	public const PHANTOM_MEMBRANE = 470;
	public const CROSSBOW = 471;
	public const SPRUCE_SIGN = 472;
	public const BIRCH_SIGN = 473;
	public const JUNGLE_SIGN = 474;
	public const ACACIA_SIGN = 475;
	public const DARKOAK_SIGN = 476;
	public const SWEET_BERRIES = 477;

	public const COMPOUND = 499;
	public const RECORD_13 = 500;
	public const RECORD_CAT = 501;
	public const RECORD_BLOCKS = 502;
	public const RECORD_CHIRP = 503;
	public const RECORD_FAR = 504;
	public const RECORD_MALL = 505;
	public const RECORD_MELLOHI = 506;
	public const RECORD_STAL = 507;
	public const RECORD_STRAD = 508;
	public const RECORD_WARD = 509;
	public const RECORD_11 = 510;
	public const RECORD_WAIT = 511;

	public const SHIELD = 513;

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class PoweredRail extends RedstoneRail{
	protected $id = self::POWERED_RAIL;

	public function getName() : string{
		return "Powered Rail";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class RedstoneRail extends BaseRail{
	protected const FLAG_POWERED = 0x08;

	protected function getConnectionsForState() : array{
		return self::CONNECTIONS[$this->meta & ~self::FLAG_POWERED];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function array_map;
use function array_reverse;
use function array_search;
use function array_shift;
use function count;
use function implode;
use function in_array;

abstract class BaseRail extends Flowable{

	public const STRAIGHT_NORTH_SOUTH = 0;
	public const STRAIGHT_EAST_WEST = 1;
	public const ASCENDING_EAST = 2;
	public const ASCENDING_WEST = 3;
	public const ASCENDING_NORTH = 4;
	public const ASCENDING_SOUTH = 5;

	private const ASCENDING_SIDES = [
		self::ASCENDING_NORTH => Vector3::SIDE_NORTH,
		self::ASCENDING_EAST => Vector3::SIDE_EAST,
		self::ASCENDING_SOUTH => Vector3::SIDE_SOUTH,
		self::ASCENDING_WEST => Vector3::SIDE_WEST
	];

	protected const FLAG_ASCEND = 1 << 24; //used to indicate direction-up

	protected const CONNECTIONS = [
		//straights
		self::STRAIGHT_NORTH_SOUTH => [
			Vector3::SIDE_NORTH,
			Vector3::SIDE_SOUTH
		],
		self::STRAIGHT_EAST_WEST => [
			Vector3::SIDE_EAST,
			Vector3::SIDE_WEST
		],

		//ascending
		self::ASCENDING_EAST => [
			Vector3::SIDE_WEST,
			Vector3::SIDE_EAST | self::FLAG_ASCEND
		],
		self::ASCENDING_WEST => [
			Vector3::SIDE_EAST,
			Vector3::SIDE_WEST | self::FLAG_ASCEND
		],
		self::ASCENDING_NORTH => [
			Vector3::SIDE_SOUTH,
			Vector3::SIDE_NORTH | self::FLAG_ASCEND
		],
		self::ASCENDING_SOUTH => [
			Vector3::SIDE_NORTH,
			Vector3::SIDE_SOUTH | self::FLAG_ASCEND
		]
	];

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.7;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if(!$blockReplace->getSide(Vector3::SIDE_DOWN)->isTransparent() and $this->getLevel()->setBlock($blockReplace, $this, true, true)){
			$this->tryReconnect();
			return true;
		}

		return false;
	}

	/**
	 * @param int[]   $connections
	 * @param int[][] $lookup
	 * @phpstan-param array<int, list<int>> $lookup
	 */
	protected static function searchState(array $connections, array $lookup) : int{
		$meta = array_search($connections, $lookup, true);
		if($meta === false){
			$meta = array_search(array_reverse($connections), $lookup, true);
		}
		if($meta === false){
			throw new \InvalidArgumentException("No meta value matches connections " . implode(", ", array_map('\dechex', $connections)));
		}

		return $meta;
	}

	/**
	 * Returns a meta value for the rail with the given connections.
	 *
	 * @param int[] $connections
	 *
	 * @throws \InvalidArgumentException if no state matches the given connections
	 */
	protected function getMetaForState(array $connections) : int{
		return self::searchState($connections, self::CONNECTIONS);
	}

	/**
	 * Returns the connection directions of this rail (depending on the current block state)
	 *
	 * @return int[]
	 */
	abstract protected function getConnectionsForState() : array;

	/**
	 * Returns all the directions this rail is already connected in.
	 *
	 * @return int[]
	 */
	private function getConnectedDirections() : array{
		/** @var int[] $connections */
		$connections = [];

		/** @var int $connection */
		foreach($this->getConnectionsForState() as $connection){
			$other = $this->getSide($connection & ~self::FLAG_ASCEND);
			$otherConnection = Vector3::getOppositeSide($connection & ~self::FLAG_ASCEND);

			if(($connection & self::FLAG_ASCEND) !== 0){
				$other = $other->getSide(Vector3::SIDE_UP);

			}elseif(!($other instanceof BaseRail)){ //check for rail sloping up to meet this one
				$other = $other->getSide(Vector3::SIDE_DOWN);
				$otherConnection |= self::FLAG_ASCEND;
			}

			if(
				$other instanceof BaseRail and
				in_array($otherConnection, $other->getConnectionsForState(), true)
			){
				$connections[] = $connection;
			}
		}

		return $connections;
	}

	/**
	 * @param int[] $constraints
	 *
	 * @return true[]
	 * @phpstan-return array<int, true>
	 */
	private function getPossibleConnectionDirections(array $constraints) : array{
		switch(count($constraints)){
			case 0:
				//No constraints, can connect in any direction
				$possible = [
					Vector3::SIDE_NORTH => true,
					Vector3::SIDE_SOUTH => true,
					Vector3::SIDE_WEST => true,
					Vector3::SIDE_EAST => true
				];
				foreach($possible as $p => $_){
					$possible[$p | self::FLAG_ASCEND] = true;
				}

				return $possible;
			case 1:
				return $this->getPossibleConnectionDirectionsOneConstraint(array_shift($constraints));
			case 2:
				return [];
			default:
				throw new \InvalidArgumentException("Expected at most 2 constraints, got " . count($constraints));
		}
	}

	/**
	 * @return true[]
	 * @phpstan-return array<int, true>
	 */
	protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
		$opposite = Vector3::getOppositeSide($constraint & ~self::FLAG_ASCEND);

		$possible = [$opposite => true];

		if(($constraint & self::FLAG_ASCEND) === 0){
			//We can slope the other way if this connection isn't already a slope
			$possible[$opposite | self::FLAG_ASCEND] = true;
		}

		return $possible;
	}

	private function tryReconnect() : void{
		$thisConnections = $this->getConnectedDirections();
		$changed = false;

		do{
			$possible = $this->getPossibleConnectionDirections($thisConnections);
			$continue = false;

			foreach($possible as $thisSide => $_){
				$otherSide = Vector3::getOppositeSide($thisSide & ~self::FLAG_ASCEND);

				$other = $this->getSide($thisSide & ~self::FLAG_ASCEND);

				if(($thisSide & self::FLAG_ASCEND) !== 0){
					$other = $other->getSide(Vector3::SIDE_UP);

				}elseif(!($other instanceof BaseRail)){ //check if other rails can slope up to meet this one
					$other = $other->getSide(Vector3::SIDE_DOWN);
					$otherSide |= self::FLAG_ASCEND;
				}

				if(!($other instanceof BaseRail) or count($otherConnections = $other->getConnectedDirections()) >= 2){
					//we can only connect to a rail that has less than 2 connections
					continue;
				}

				$otherPossible = $other->getPossibleConnectionDirections($otherConnections);

				if(isset($otherPossible[$otherSide])){
					$otherConnections[] = $otherSide;
					$other->updateState($otherConnections);

					$changed = true;
					$thisConnections[] = $thisSide;
					$continue = count($thisConnections) < 2;

					break; //force recomputing possible directions, since this connection could invalidate others
				}
			}
		}while($continue);

		if($changed){
			$this->updateState($thisConnections);
		}
	}

	/**
	 * @param int[] $connections
	 */
	private function updateState(array $connections) : void{
		if(count($connections) === 1){
			$connections[] = Vector3::getOppositeSide($connections[0] & ~self::FLAG_ASCEND);
		}elseif(count($connections) !== 2){
			throw new \InvalidArgumentException("Expected exactly 2 connections, got " . count($connections));
		}

		$this->meta = $this->getMetaForState($connections);
		$this->level->setBlock($this, $this, false, false); //avoid recursion
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() or (
			isset(self::ASCENDING_SIDES[$this->meta & 0x07]) and
			$this->getSide(self::ASCENDING_SIDES[$this->meta & 0x07])->isTransparent()
		)){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class DetectorRail extends RedstoneRail{

	protected $id = self::DETECTOR_RAIL;

	public function getName() : string{
		return "Detector Rail";
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;

class Cobweb extends Flowable{

	protected $id = self::COBWEB;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function hasEntityCollision() : bool{
		return true;
	}

	public function getName() : string{
		return "Cobweb";
	}

	public function getHardness() : float{
		return 4;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SWORD | BlockToolType::TYPE_SHEARS;
	}

	public function getToolHarvestLevel() : int{
		return 1;
	}

	public function onEntityCollide(Entity $entity) : void{
		$entity->resetFallDistance();
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::STRING)
		];
	}

	public function diffusesSkyLight() : bool{
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function mt_rand;

class TallGrass extends Flowable{

	protected $id = self::TALL_GRASS;

	public function __construct(int $meta = 1){
		$this->meta = $meta;
	}

	public function canBeReplaced() : bool{
		return true;
	}

	public function getName() : string{
		static $names = [
			0 => "Dead Shrub",
			1 => "Tall Grass",
			2 => "Fern"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN)->getId();
		if($down === self::GRASS or $down === self::DIRT){
			$this->getLevel()->setBlock($blockReplace, $this, true);

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ //Replace with common break method
			$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
		}
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHEARS;
	}

	public function getToolHarvestLevel() : int{
		return 1;
	}

	public function getDrops(Item $item) : array{
		if($this->isCompatibleWithTool($item)){
			return parent::getDrops($item);
		}

		if(mt_rand(0, 15) === 0){
			return [
				ItemFactory::get(Item::WHEAT_SEEDS)
			];
		}

		return [];
	}

	public function getFlameEncouragement() : int{
		return 60;
	}

	public function getFlammability() : int{
		return 100;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function mt_rand;

class DeadBush extends Flowable{

	protected $id = self::DEAD_BUSH;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Dead Bush";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if(!$this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
			return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHEARS;
	}

	public function getToolHarvestLevel() : int{
		return 1;
	}

	public function getDrops(Item $item) : array{
		if(!$this->isCompatibleWithTool($item)){
			return [
				ItemFactory::get(Item::STICK, 0, mt_rand(0, 2))
			];
		}

		return parent::getDrops($item);
	}

	public function getFlameEncouragement() : int{
		return 60;
	}

	public function getFlammability() : int{
		return 100;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\item\Item;

class Wool extends Solid{

	protected $id = self::WOOL;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.8;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHEARS;
	}

	public function getName() : string{
		return ColorBlockMetaHelper::getColorFromMeta($this->getVariant()) . " Wool";
	}

	public function getBreakTime(Item $item) : float{
		$time = parent::getBreakTime($item);
		if($item->getBlockToolType() === BlockToolType::TYPE_SHEARS){
			$time *= 3; //shears break compatible blocks 15x faster, but wool 5x
		}

		return $time;
	}

	public function getFlameEncouragement() : int{
		return 30;
	}

	public function getFlammability() : int{
		return 60;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Dandelion extends Flowable{

	protected $id = self::DANDELION;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Dandelion";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
			$this->getLevel()->setBlock($blockReplace, $this, true, true);

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function getFlameEncouragement() : int{
		return 60;
	}

	public function getFlammability() : int{
		return 100;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Flower extends Flowable{
	public const TYPE_POPPY = 0;
	public const TYPE_BLUE_ORCHID = 1;
	public const TYPE_ALLIUM = 2;
	public const TYPE_AZURE_BLUET = 3;
	public const TYPE_RED_TULIP = 4;
	public const TYPE_ORANGE_TULIP = 5;
	public const TYPE_WHITE_TULIP = 6;
	public const TYPE_PINK_TULIP = 7;
	public const TYPE_OXEYE_DAISY = 8;

	protected $id = self::RED_FLOWER;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		static $names = [
			self::TYPE_POPPY => "Poppy",
			self::TYPE_BLUE_ORCHID => "Blue Orchid",
			self::TYPE_ALLIUM => "Allium",
			self::TYPE_AZURE_BLUET => "Azure Bluet",
			self::TYPE_RED_TULIP => "Red Tulip",
			self::TYPE_ORANGE_TULIP => "Orange Tulip",
			self::TYPE_WHITE_TULIP => "White Tulip",
			self::TYPE_PINK_TULIP => "Pink Tulip",
			self::TYPE_OXEYE_DAISY => "Oxeye Daisy"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
			$this->getLevel()->setBlock($blockReplace, $this, true);

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function getFlameEncouragement() : int{
		return 60;
	}

	public function getFlammability() : int{
		return 100;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class BrownMushroom extends RedMushroom{

	protected $id = self::BROWN_MUSHROOM;

	public function getName() : string{
		return "Brown Mushroom";
	}

	public function getLightLevel() : int{
		return 1;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

class RedMushroom extends Flowable{

	protected $id = self::RED_MUSHROOM;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Red Mushroom";
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if(!$down->isTransparent()){
			$this->getLevel()->setBlock($blockReplace, $this, true, true);

			return true;
		}

		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Gold extends Solid{

	protected $id = self::GOLD_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Gold Block";
	}

	public function getHardness() : float{
		return 3;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_IRON;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Iron extends Solid{

	protected $id = self::IRON_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Iron Block";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_STONE;
	}

	public function getHardness() : float{
		return 5;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class DoubleStoneSlab extends DoubleSlab{

	protected $id = self::DOUBLE_STONE_SLAB;

	public function getSlabId() : int{
		return self::STONE_SLAB;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;

abstract class DoubleSlab extends Solid{

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	abstract public function getSlabId() : int;

	public function getName() : string{
		return "Double " . BlockFactory::get($this->getSlabId(), $this->getVariant())->getName();
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get($this->getSlabId(), $this->getVariant(), 2)
		];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}

	public function getPickedItem() : Item{
		return ItemFactory::get($this->getSlabId(), $this->getVariant());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class StoneSlab extends Slab{
	public const STONE = 0;
	public const SANDSTONE = 1;
	public const WOODEN = 2;
	public const COBBLESTONE = 3;
	public const BRICK = 4;
	public const STONE_BRICK = 5;
	public const QUARTZ = 6;
	public const NETHER_BRICK = 7;

	protected $id = self::STONE_SLAB;

	public function getDoubleSlabId() : int{
		return self::DOUBLE_STONE_SLAB;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getName() : string{
		static $names = [
			self::STONE => "Stone",
			self::SANDSTONE => "Sandstone",
			self::WOODEN => "Wooden",
			self::COBBLESTONE => "Cobblestone",
			self::BRICK => "Brick",
			self::STONE_BRICK => "Stone Brick",
			self::QUARTZ => "Quartz",
			self::NETHER_BRICK => "Nether Brick"
		];
		return (($this->meta & 0x08) > 0 ? "Upper " : "") . ($names[$this->getVariant()] ?? "") . " Slab";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

abstract class Slab extends Transparent{

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	abstract public function getDoubleSlabId() : int;

	public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
		if(parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock)){
			return true;
		}

		if($blockReplace->getId() === $this->getId() and $blockReplace->getVariant() === $this->getVariant()){
			if(($blockReplace->getDamage() & 0x08) !== 0){ //Trying to combine with top slab
				return $clickVector->y <= 0.5 or (!$isClickedBlock and $face === Vector3::SIDE_UP);
			}else{
				return $clickVector->y >= 0.5 or (!$isClickedBlock and $face === Vector3::SIDE_DOWN);
			}
		}

		return false;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$this->meta &= 0x07;
		if($face === Vector3::SIDE_DOWN){
			if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0x08 and $blockClicked->getVariant() === $this->getVariant()){
				$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);

				return true;
			}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
				$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);

				return true;
			}else{
				$this->meta |= 0x08;
			}
		}elseif($face === Vector3::SIDE_UP){
			if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0 and $blockClicked->getVariant() === $this->getVariant()){
				$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);

				return true;
			}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
				$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);

				return true;
			}
		}else{ //TODO: collision
			if($blockReplace->getId() === $this->id){
				if($blockReplace->getVariant() === $this->getVariant()){
					$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);

					return true;
				}

				return false;
			}else{
				if($clickVector->y > 0.5){
					$this->meta |= 0x08;
				}
			}
		}

		if($blockReplace->getId() === $this->id and $blockClicked->getVariant() !== $this->getVariant()){
			return false;
		}
		$this->getLevel()->setBlock($blockReplace, $this, true, true);

		return true;
	}

	public function getVariantBitmask() : int{
		return 0x07;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		if(($this->meta & 0x08) > 0){
			return new AxisAlignedBB(
				$this->x,
				$this->y + 0.5,
				$this->z,
				$this->x + 1,
				$this->y + 1,
				$this->z + 1
			);
		}else{
			return new AxisAlignedBB(
				$this->x,
				$this->y,
				$this->z,
				$this->x + 1,
				$this->y + 0.5,
				$this->z + 1
			);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Bricks extends Solid{

	protected $id = self::BRICK_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getBlastResistance() : float{
		return 30;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Bricks";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\entity\projectile\Arrow;
use pocketmine\item\Durable;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\FlintSteel;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\Random;
use function cos;
use function sin;
use const M_PI;

class TNT extends Solid{

	protected $id = self::TNT;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "TNT";
	}

	public function getHardness() : float{
		return 0;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($item instanceof FlintSteel or $item->hasEnchantment(Enchantment::FIRE_ASPECT)){
			if($item instanceof Durable){
				$item->applyDamage(1);
			}
			$this->ignite();
			return true;
		}

		return false;
	}

	public function hasEntityCollision() : bool{
		return true;
	}

	public function onEntityCollide(Entity $entity) : void{
		if($entity instanceof Arrow and $entity->isOnFire()){
			$this->ignite();
		}
	}

	/**
	 * @return void
	 */
	public function ignite(int $fuse = 80){
		$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);

		$mot = (new Random())->nextSignedFloat() * M_PI * 2;
		$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
		$nbt->setShort("Fuse", $fuse);

		$tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), $nbt);

		if($tnt !== null){
			$tnt->spawnToAll();
		}
	}

	public function getFlameEncouragement() : int{
		return 15;
	}

	public function getFlammability() : int{
		return 100;
	}

	public function onIncinerate() : void{
		$this->ignite();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;

class Bookshelf extends Solid{

	protected $id = self::BOOKSHELF;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Bookshelf";
	}

	public function getHardness() : float{
		return 1.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::BOOK, 0, 3)
		];
	}

	public function getFuelTime() : int{
		return 300;
	}

	public function getFlameEncouragement() : int{
		return 30;
	}

	public function getFlammability() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class MossyCobblestone extends Cobblestone{

	protected $id = self::MOSSY_COBBLESTONE;

	public function getName() : string{
		return "Moss Stone";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Obsidian extends Solid{

	protected $id = self::OBSIDIAN;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Obsidian";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_DIAMOND;
	}

	public function getHardness() : float{
		return 35; //50 in PC
	}

	public function getBlastResistance() : float{
		return 6000;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Torch extends Flowable{

	protected $id = self::TORCH;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getLightLevel() : int{
		return 14;
	}

	public function getName() : string{
		return "Torch";
	}

	public function onNearbyBlockChange() : void{
		$below = $this->getSide(Vector3::SIDE_DOWN);
		$meta = $this->getDamage();
		static $faces = [
			0 => Vector3::SIDE_DOWN,
			1 => Vector3::SIDE_WEST,
			2 => Vector3::SIDE_EAST,
			3 => Vector3::SIDE_NORTH,
			4 => Vector3::SIDE_SOUTH,
			5 => Vector3::SIDE_DOWN
		];
		$face = $faces[$meta] ?? Vector3::SIDE_DOWN;

		if($this->getSide($face)->isTransparent() and !($face === Vector3::SIDE_DOWN and ($below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL))){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$below = $this->getSide(Vector3::SIDE_DOWN);

		if(!$blockClicked->isTransparent() and $face !== Vector3::SIDE_DOWN){
			$faces = [
				Vector3::SIDE_UP => 5,
				Vector3::SIDE_NORTH => 4,
				Vector3::SIDE_SOUTH => 3,
				Vector3::SIDE_WEST => 2,
				Vector3::SIDE_EAST => 1
			];
			$this->meta = $faces[$face];
			$this->getLevel()->setBlock($blockReplace, $this, true, true);

			return true;
		}elseif(!$below->isTransparent() or $below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL){
			$this->meta = 0;
			$this->getLevel()->setBlock($blockReplace, $this, true, true);

			return true;
		}

		return false;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\entity\projectile\Arrow;
use pocketmine\event\block\BlockBurnEvent;
use pocketmine\event\entity\EntityCombustByBlockEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use function min;
use function mt_rand;

class Fire extends Flowable{

	protected $id = self::FIRE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function hasEntityCollision() : bool{
		return true;
	}

	public function getName() : string{
		return "Fire Block";
	}

	public function getLightLevel() : int{
		return 15;
	}

	public function isBreakable(Item $item) : bool{
		return false;
	}

	public function canBeReplaced() : bool{
		return true;
	}

	public function onEntityCollide(Entity $entity) : void{
		$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
		$entity->attack($ev);

		$ev = new EntityCombustByBlockEvent($this, $entity, 8);
		if($entity instanceof Arrow){
			$ev->setCancelled();
		}
		$ev->call();
		if(!$ev->isCancelled()){
			$entity->setOnFire($ev->getDuration());
		}
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [];
	}

	public function onNearbyBlockChange() : void{
		if(!$this->getSide(Vector3::SIDE_DOWN)->isSolid() and !$this->hasAdjacentFlammableBlocks()){
			$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
		}else{
			$this->level->scheduleDelayedBlockUpdate($this, mt_rand(30, 40));
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		$down = $this->getSide(Vector3::SIDE_DOWN);

		$result = null;
		if($this->meta < 15 and mt_rand(0, 2) === 0){
			$this->meta++;
			$result = $this;
		}
		$canSpread = true;

		if(!$down->burnsForever()){
			//TODO: check rain
			if($this->meta === 15){
				if(!$down->isFlammable() and mt_rand(0, 3) === 3){ //1/4 chance to extinguish
					$canSpread = false;
					$result = BlockFactory::get(Block::AIR);
				}
			}elseif(!$this->hasAdjacentFlammableBlocks()){
				$canSpread = false;
				if(!$down->isSolid() or $this->meta > 3){ //fire older than 3, or without a solid block below
					$result = BlockFactory::get(Block::AIR);
				}
			}
		}

		if($result !== null){
			$this->level->setBlock($this, $result);
		}

		$this->level->scheduleDelayedBlockUpdate($this, mt_rand(30, 40));

		if($canSpread){
			//TODO: raise upper bound for chance in humid biomes

			foreach($this->getHorizontalSides() as $side){
				$this->burnBlock($side, 300);
			}

			//vanilla uses a 250 upper bound here, but I don't think they intended to increase the chance of incineration
			$this->burnBlock($this->getSide(Vector3::SIDE_UP), 350);
			$this->burnBlock($this->getSide(Vector3::SIDE_DOWN), 350);

			//TODO: fire spread
		}
	}

	public function onScheduledUpdate() : void{
		$this->onRandomTick();
	}

	private function hasAdjacentFlammableBlocks() : bool{
		for($i = 0; $i <= 5; ++$i){
			if($this->getSide($i)->isFlammable()){
				return true;
			}
		}

		return false;
	}

	private function burnBlock(Block $block, int $chanceBound) : void{
		if(mt_rand(0, $chanceBound) < $block->getFlammability()){
			$ev = new BlockBurnEvent($block, $this);
			$ev->call();
			if(!$ev->isCancelled()){
				$block->onIncinerate();

				if(mt_rand(0, $this->meta + 9) < 5){ //TODO: check rain
					$this->level->setBlock($block, BlockFactory::get(Block::FIRE, min(15, $this->meta + (mt_rand(0, 4) >> 2))));
				}else{
					$this->level->setBlock($block, BlockFactory::get(Block::AIR));
				}
			}
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use function mt_rand;

class MonsterSpawner extends Transparent{

	protected $id = self::MONSTER_SPAWNER;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Monster Spawner";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}

	protected function getXpDropAmount() : int{
		return mt_rand(15, 43);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class WoodenStairs extends Stair{

	public function getHardness() : float{
		return 2;
	}

	public function getBlastResistance() : float{
		return 15;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getFlameEncouragement() : int{
		return 5;
	}

	public function getFlammability() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

abstract class Stair extends Transparent{

	protected function recalculateCollisionBoxes() : array{
		//TODO: handle corners

		$minYSlab = ($this->meta & 0x04) === 0 ? 0 : 0.5;
		$maxYSlab = $minYSlab + 0.5;

		$bbs = [
			new AxisAlignedBB(
				$this->x,
				$this->y + $minYSlab,
				$this->z,
				$this->x + 1,
				$this->y + $maxYSlab,
				$this->z + 1
			)
		];

		$minY = ($this->meta & 0x04) === 0 ? 0.5 : 0;
		$maxY = $minY + 0.5;

		$rotationMeta = $this->meta & 0x03;

		$minX = $minZ = 0;
		$maxX = $maxZ = 1;

		switch($rotationMeta){
			case 0:
				$minX = 0.5;
				break;
			case 1:
				$maxX = 0.5;
				break;
			case 2:
				$minZ = 0.5;
				break;
			case 3:
				$maxZ = 0.5;
				break;
		}

		$bbs[] = new AxisAlignedBB(
			$this->x + $minX,
			$this->y + $minY,
			$this->z + $minZ,
			$this->x + $maxX,
			$this->y + $maxY,
			$this->z + $maxZ
		);

		return $bbs;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$faces = [
			0 => 0,
			1 => 2,
			2 => 1,
			3 => 3
		];
		$this->meta = $player !== null ? $faces[$player->getDirection()] & 0x03 : 0;
		if(($clickVector->y > 0.5 and $face !== Vector3::SIDE_UP) or $face === Vector3::SIDE_DOWN){
			$this->meta |= 0x04; //Upside-down stairs
		}
		$this->getLevel()->setBlock($blockReplace, $this, true, true);

		return true;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\Chest as TileChest;
use pocketmine\tile\Tile;

class Chest extends Transparent{

	protected $id = self::CHEST;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 2.5;
	}

	public function getName() : string{
		return "Chest";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		//these are slightly bigger than in PC
		return new AxisAlignedBB(
			$this->x + 0.025,
			$this->y,
			$this->z + 0.025,
			$this->x + 0.975,
			$this->y + 0.95,
			$this->z + 0.975
		);
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$faces = [
			0 => 4,
			1 => 2,
			2 => 5,
			3 => 3
		];

		$chest = null;
		$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];

		for($side = 2; $side <= 5; ++$side){
			if(($this->meta === 4 or $this->meta === 5) and ($side === 4 or $side === 5)){
				continue;
			}elseif(($this->meta === 3 or $this->meta === 2) and ($side === 2 or $side === 3)){
				continue;
			}
			$c = $this->getSide($side);
			if($c->getId() === $this->id and $c->getDamage() === $this->meta){
				$tile = $this->getLevel()->getTile($c);
				if($tile instanceof TileChest and !$tile->isPaired()){
					$chest = $tile;
					break;
				}
			}
		}

		$this->getLevel()->setBlock($blockReplace, $this, true, true);
		$tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player));

		if($chest instanceof TileChest and $tile instanceof TileChest){
			$chest->pairWith($tile);
			$tile->pairWith($chest);
		}

		return true;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($player instanceof Player){

			$t = $this->getLevel()->getTile($this);
			$chest = null;
			if($t instanceof TileChest){
				$chest = $t;
			}else{
				$chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this));
				if(!($chest instanceof TileChest)){
					return true;
				}
			}

			if(
				!$this->getSide(Vector3::SIDE_UP)->isTransparent() or
				(($pair = $chest->getPair()) !== null and !$pair->getBlock()->getSide(Vector3::SIDE_UP)->isTransparent()) or
				!$chest->canOpenWith($item->getCustomName())
			){
				return true;
			}

			$player->addWindow($chest->getInventory());
		}

		return true;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function getFuelTime() : int{
		return 300;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;
use function mt_rand;

class DiamondOre extends Solid{

	protected $id = self::DIAMOND_ORE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 3;
	}

	public function getName() : string{
		return "Diamond Ore";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_IRON;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::DIAMOND)
		];
	}

	protected function getXpDropAmount() : int{
		return mt_rand(3, 7);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Diamond extends Solid{

	protected $id = self::DIAMOND_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 5;
	}

	public function getName() : string{
		return "Diamond Block";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_IRON;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\inventory\CraftingGrid;
use pocketmine\item\Item;
use pocketmine\Player;

class CraftingTable extends Solid{

	protected $id = self::CRAFTING_TABLE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 2.5;
	}

	public function getName() : string{
		return "Crafting Table";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($player instanceof Player){
			$player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG));
		}

		return true;
	}

	public function getFuelTime() : int{
		return 300;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use function mt_rand;

class Wheat extends Crops{

	protected $id = self::WHEAT_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Wheat Block";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		if($this->meta >= 0x07){
			return [
				ItemFactory::get(Item::WHEAT),
				ItemFactory::get(Item::WHEAT_SEEDS, 0, mt_rand(0, 3))
			];
		}else{
			return [
				ItemFactory::get(Item::WHEAT_SEEDS)
			];
		}
	}

	public function getPickedItem() : Item{
		return ItemFactory::get(Item::WHEAT_SEEDS);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function mt_rand;

abstract class Crops extends Flowable{

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($blockReplace->getSide(Vector3::SIDE_DOWN)->getId() === Block::FARMLAND){
			$this->getLevel()->setBlock($blockReplace, $this, true, true);

			return true;
		}

		return false;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($this->meta < 7 and $item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
			$block = clone $this;
			$block->meta += mt_rand(2, 5);
			if($block->meta > 7){
				$block->meta = 7;
			}

			$ev = new BlockGrowEvent($this, $block);
			$ev->call();
			if(!$ev->isCancelled()){
				$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
			}

			$item->count--;

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::FARMLAND){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		if(mt_rand(0, 2) === 1){
			if($this->meta < 0x07){
				$block = clone $this;
				++$block->meta;
				$ev = new BlockGrowEvent($this, $block);
				$ev->call();
				if(!$ev->isCancelled()){
					$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
				}
			}
		}
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;

class Farmland extends Transparent{

	protected $id = self::FARMLAND;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Farmland";
	}

	public function getHardness() : float{
		return 0.6;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return new AxisAlignedBB(
			$this->x,
			$this->y,
			$this->z,
			$this->x + 1,
			$this->y + 1, //TODO: this should be 0.9375, but MCPE currently treats them as a full block (https://bugs.mojang.com/browse/MCPE-12109)
			$this->z + 1
		);
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_UP)->isSolid()){
			$this->level->setBlock($this, BlockFactory::get(Block::DIRT), true);
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		if(!$this->canHydrate()){
			if($this->meta > 0){
				$this->meta--;
				$this->level->setBlock($this, $this, false, false);
			}else{
				$this->level->setBlock($this, BlockFactory::get(Block::DIRT), false, true);
			}
		}elseif($this->meta < 7){
			$this->meta = 7;
			$this->level->setBlock($this, $this, false, false);
		}
	}

	protected function canHydrate() : bool{
		//TODO: check rain
		$start = $this->add(-4, 0, -4);
		$end = $this->add(4, 1, 4);
		for($y = $start->y; $y <= $end->y; ++$y){
			for($z = $start->z; $z <= $end->z; ++$z){
				for($x = $start->x; $x <= $end->x; ++$x){
					$id = $this->level->getBlockIdAt($x, $y, $z);
					if($id === Block::STILL_WATER or $id === Block::FLOWING_WATER){
						return true;
					}
				}
			}
		}

		return false;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::DIRT)
		];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}

	public function getPickedItem() : Item{
		return ItemFactory::get(Item::DIRT);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class Furnace extends BurningFurnace{

	protected $id = self::FURNACE;

	public function getName() : string{
		return "Furnace";
	}

	public function getLightLevel() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\Furnace as TileFurnace;
use pocketmine\tile\Tile;

class BurningFurnace extends Solid{

	protected $id = self::BURNING_FURNACE;

	protected $itemId = self::FURNACE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Burning Furnace";
	}

	public function getHardness() : float{
		return 3.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getLightLevel() : int{
		return 13;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$faces = [
			0 => 4,
			1 => 2,
			2 => 5,
			3 => 3
		];
		$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
		$this->getLevel()->setBlock($blockReplace, $this, true, true);

		Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));

		return true;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($player instanceof Player){
			$furnace = $this->getLevel()->getTile($this);
			if(!($furnace instanceof TileFurnace)){
				$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
				if(!($furnace instanceof TileFurnace)){
					return true;
				}
			}

			if(!$furnace->canOpenWith($item->getCustomName())){
				return true;
			}

			$player->addWindow($furnace->getInventory());
		}

		return true;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\Sign as TileSign;
use pocketmine\tile\Tile;
use function floor;

class SignPost extends Transparent{

	protected $id = self::SIGN_POST;

	protected $itemId = Item::SIGN;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 1;
	}

	public function isSolid() : bool{
		return false;
	}

	public function getName() : string{
		return "Sign Post";
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return null;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($face !== Vector3::SIDE_DOWN){

			if($face === Vector3::SIDE_UP){
				$this->meta = $player !== null ? (floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f) : 0;
				$this->getLevel()->setBlock($blockReplace, $this, true);
			}else{
				$this->meta = $face;
				$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
			}

			Tile::createTile(Tile::SIGN, $this->getLevel(), TileSign::createNBT($this, $face, $item, $player));

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class WoodenDoor extends Door{

	public function getHardness() : float{
		return 3;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\level\sound\DoorSound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

abstract class Door extends Transparent{

	public function isSolid() : bool{
		return false;
	}

	private function getFullDamage() : int{
		$damage = $this->getDamage();
		$isUp = ($damage & 0x08) > 0;

		if($isUp){
			$down = $this->getSide(Vector3::SIDE_DOWN)->getDamage();
			$up = $damage;
		}else{
			$down = $damage;
			$up = $this->getSide(Vector3::SIDE_UP)->getDamage();
		}

		$isRight = ($up & 0x01) > 0;

		return $down & 0x07 | ($isUp ? 8 : 0) | ($isRight ? 0x10 : 0);
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		$f = 0.1875;
		$damage = $this->getFullDamage();

		$bb = new AxisAlignedBB(
			$this->x,
			$this->y,
			$this->z,
			$this->x + 1,
			$this->y + 2,
			$this->z + 1
		);

		$j = $damage & 0x03;
		$isOpen = (($damage & 0x04) > 0);
		$isRight = (($damage & 0x10) > 0);

		if($j === 0){
			if($isOpen){
				if(!$isRight){
					$bb->setBounds(
						$this->x,
						$this->y,
						$this->z,
						$this->x + 1,
						$this->y + 1,
						$this->z + $f
					);
				}else{
					$bb->setBounds(
						$this->x,
						$this->y,
						$this->z + 1 - $f,
						$this->x + 1,
						$this->y + 1,
						$this->z + 1
					);
				}
			}else{
				$bb->setBounds(
					$this->x,
					$this->y,
					$this->z,
					$this->x + $f,
					$this->y + 1,
					$this->z + 1
				);
			}
		}elseif($j === 1){
			if($isOpen){
				if(!$isRight){
					$bb->setBounds(
						$this->x + 1 - $f,
						$this->y,
						$this->z,
						$this->x + 1,
						$this->y + 1,
						$this->z + 1
					);
				}else{
					$bb->setBounds(
						$this->x,
						$this->y,
						$this->z,
						$this->x + $f,
						$this->y + 1,
						$this->z + 1
					);
				}
			}else{
				$bb->setBounds(
					$this->x,
					$this->y,
					$this->z,
					$this->x + 1,
					$this->y + 1,
					$this->z + $f
				);
			}
		}elseif($j === 2){
			if($isOpen){
				if(!$isRight){
					$bb->setBounds(
						$this->x,
						$this->y,
						$this->z + 1 - $f,
						$this->x + 1,
						$this->y + 1,
						$this->z + 1
					);
				}else{
					$bb->setBounds(
						$this->x,
						$this->y,
						$this->z,
						$this->x + 1,
						$this->y + 1,
						$this->z + $f
					);
				}
			}else{
				$bb->setBounds(
					$this->x + 1 - $f,
					$this->y,
					$this->z,
					$this->x + 1,
					$this->y + 1,
					$this->z + 1
				);
			}
		}elseif($j === 3){
			if($isOpen){
				if(!$isRight){
					$bb->setBounds(
						$this->x,
						$this->y,
						$this->z,
						$this->x + $f,
						$this->y + 1,
						$this->z + 1
					);
				}else{
					$bb->setBounds(
						$this->x + 1 - $f,
						$this->y,
						$this->z,
						$this->x + 1,
						$this->y + 1,
						$this->z + 1
					);
				}
			}else{
				$bb->setBounds(
					$this->x,
					$this->y,
					$this->z + 1 - $f,
					$this->x + 1,
					$this->y + 1,
					$this->z + 1
				);
			}
		}

		return $bb;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
			$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false);
			if($this->getSide(Vector3::SIDE_UP) instanceof Door){
				$this->getLevel()->setBlock($this->getSide(Vector3::SIDE_UP), BlockFactory::get(Block::AIR), false);
			}
		}
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($face === Vector3::SIDE_UP){
			$blockUp = $this->getSide(Vector3::SIDE_UP);
			$blockDown = $this->getSide(Vector3::SIDE_DOWN);
			if(!$blockUp->canBeReplaced() or $blockDown->isTransparent()){
				return false;
			}
			$direction = $player instanceof Player ? $player->getDirection() : 0;
			$faces = [
				0 => 3,
				1 => 4,
				2 => 2,
				3 => 5
			];
			$next = $this->getSide($faces[($direction + 2) % 4]);
			$next2 = $this->getSide($faces[$direction]);
			$metaUp = 0x08;
			if($next->getId() === $this->getId() or (!$next2->isTransparent() and $next->isTransparent())){ //Door hinge
				$metaUp |= 0x01;
			}

			$this->setDamage($player->getDirection() & 0x03);
			$this->getLevel()->setBlock($blockReplace, $this, true, true); //Bottom
			$this->getLevel()->setBlock($blockUp, BlockFactory::get($this->getId(), $metaUp), true); //Top
			return true;
		}

		return false;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if(($this->getDamage() & 0x08) === 0x08){ //Top
			$down = $this->getSide(Vector3::SIDE_DOWN);
			if($down->getId() === $this->getId()){
				$meta = $down->getDamage() ^ 0x04;
				$this->level->setBlock($down, BlockFactory::get($this->getId(), $meta), true);
				$this->level->addSound(new DoorSound($this));
				return true;
			}

			return false;
		}else{
			$this->meta ^= 0x04;
			$this->level->setBlock($this, $this, true);
			$this->level->addSound(new DoorSound($this));
		}

		return true;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		if(($this->meta & 0x08) === 0){ //bottom half only
			return parent::getDropsForCompatibleTool($item);
		}

		return [];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}

	public function getAffectedBlocks() : array{
		if(($this->getDamage() & 0x08) === 0x08){
			$down = $this->getSide(Vector3::SIDE_DOWN);
			if($down->getId() === $this->getId()){
				return [$this, $down];
			}
		}else{
			$up = $this->getSide(Vector3::SIDE_UP);
			if($up->getId() === $this->getId()){
				return [$this, $up];
			}
		}

		return parent::getAffectedBlocks();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Ladder extends Transparent{

	protected $id = self::LADDER;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Ladder";
	}

	public function hasEntityCollision() : bool{
		return true;
	}

	public function isSolid() : bool{
		return false;
	}

	public function getHardness() : float{
		return 0.4;
	}

	public function canClimb() : bool{
		return true;
	}

	public function onEntityCollide(Entity $entity) : void{
		if($entity->asVector3()->floor()->distanceSquared($this) < 1){ //entity coordinates must be inside block
			$entity->resetFallDistance();
			$entity->onGround = true;
		}
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		$f = 0.1875;

		$minX = $minZ = 0;
		$maxX = $maxZ = 1;

		if($this->meta === 2){
			$minZ = 1 - $f;
		}elseif($this->meta === 3){
			$maxZ = $f;
		}elseif($this->meta === 4){
			$minX = 1 - $f;
		}elseif($this->meta === 5){
			$maxX = $f;
		}

		return new AxisAlignedBB(
			$this->x + $minX,
			$this->y,
			$this->z + $minZ,
			$this->x + $maxX,
			$this->y + 1,
			$this->z + $maxZ
		);
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if(!$blockClicked->isTransparent()){
			$faces = [
				2 => 2,
				3 => 3,
				4 => 4,
				5 => 5
			];
			if(isset($faces[$face])){
				$this->meta = $faces[$face];
				$this->getLevel()->setBlock($blockReplace, $this, true, true);

				return true;
			}
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if(!$this->getSide($this->meta ^ 0x01)->isSolid()){ //Replace with common break method
			$this->level->useBreakOn($this);
		}
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\math\Vector3;

class Rail extends BaseRail{

	/* extended meta values for regular rails, to allow curving */
	public const CURVE_SOUTHEAST = 6;
	public const CURVE_SOUTHWEST = 7;
	public const CURVE_NORTHWEST = 8;
	public const CURVE_NORTHEAST = 9;

	private const CURVE_CONNECTIONS = [
		self::CURVE_SOUTHEAST => [
			Vector3::SIDE_SOUTH,
			Vector3::SIDE_EAST
		],
		self::CURVE_SOUTHWEST => [
			Vector3::SIDE_SOUTH,
			Vector3::SIDE_WEST
		],
		self::CURVE_NORTHWEST => [
			Vector3::SIDE_NORTH,
			Vector3::SIDE_WEST
		],
		self::CURVE_NORTHEAST => [
			Vector3::SIDE_NORTH,
			Vector3::SIDE_EAST
		]
	];

	protected $id = self::RAIL;

	public function getName() : string{
		return "Rail";
	}

	protected function getMetaForState(array $connections) : int{
		try{
			return self::searchState($connections, self::CURVE_CONNECTIONS);
		}catch(\InvalidArgumentException $e){
			return parent::getMetaForState($connections);
		}
	}

	protected function getConnectionsForState() : array{
		return self::CURVE_CONNECTIONS[$this->meta] ?? self::CONNECTIONS[$this->meta];
	}

	protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
		static $horizontal = [
			Vector3::SIDE_NORTH,
			Vector3::SIDE_SOUTH,
			Vector3::SIDE_WEST,
			Vector3::SIDE_EAST
		];

		$possible = parent::getPossibleConnectionDirectionsOneConstraint($constraint);

		if(($constraint & self::FLAG_ASCEND) === 0){
			foreach($horizontal as $d){
				if($constraint !== $d){
					$possible[$d] = true;
				}
			}
		}

		return $possible;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class CobblestoneStairs extends Stair{

	protected $id = self::COBBLESTONE_STAIRS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Cobblestone Stairs";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class WallSign extends SignPost{

	protected $id = self::WALL_SIGN;

	public function getName() : string{
		return "Wall Sign";
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){
			$this->getLevel()->useBreakOn($this);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Lever extends Flowable{

	protected $id = self::LEVER;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Lever";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if(!$blockClicked->isSolid()){
			return false;
		}

		if($face === Vector3::SIDE_DOWN){
			$this->meta = 0;
		}else{
			$this->meta = 6 - $face;
		}

		if($player !== null){
			if(($player->getDirection() & 0x01) === 0){
				if($face === Vector3::SIDE_UP){
					$this->meta = 6;
				}
			}else{
				if($face === Vector3::SIDE_DOWN){
					$this->meta = 7;
				}
			}
		}

		return $this->level->setBlock($blockReplace, $this, true, true);
	}

	public function onNearbyBlockChange() : void{
		$faces = [
			0 => Vector3::SIDE_UP,
			1 => Vector3::SIDE_WEST,
			2 => Vector3::SIDE_EAST,
			3 => Vector3::SIDE_NORTH,
			4 => Vector3::SIDE_SOUTH,
			5 => Vector3::SIDE_DOWN,
			6 => Vector3::SIDE_DOWN,
			7 => Vector3::SIDE_UP
		];
		if(!$this->getSide($faces[$this->meta & 0x07])->isSolid()){
			$this->level->useBreakOn($this);
		}
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class StonePressurePlate extends Transparent{

	protected $id = self::STONE_PRESSURE_PLATE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Stone Pressure Plate";
	}

	public function isSolid() : bool{
		return false;
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\TieredTool;

class IronDoor extends Door{

	protected $id = self::IRON_DOOR_BLOCK;

	protected $itemId = Item::IRON_DOOR;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Iron Door";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getHardness() : float{
		return 5;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class WoodenPressurePlate extends StonePressurePlate{

	protected $id = self::WOODEN_PRESSURE_PLATE;

	public function getName() : string{
		return "Wooden Pressure Plate";
	}

	public function getFuelTime() : int{
		return 300;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getToolHarvestLevel() : int{
		return 0; //TODO: fix hierarchy problem
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function mt_rand;

class RedstoneOre extends Solid{

	protected $id = self::REDSTONE_ORE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Redstone Ore";
	}

	public function getHardness() : float{
		return 3;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		return $this->getLevel()->setBlock($this, $this, true, false);
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		$this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
		return false; //this shouldn't prevent block placement
	}

	public function onNearbyBlockChange() : void{
		$this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_IRON;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::REDSTONE_DUST, 0, mt_rand(4, 5))
		];
	}

	protected function getXpDropAmount() : int{
		return mt_rand(1, 5);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\Player;

class GlowingRedstoneOre extends RedstoneOre{

	protected $id = self::GLOWING_REDSTONE_ORE;

	protected $itemId = self::REDSTONE_ORE;

	public function getName() : string{
		return "Glowing Redstone Ore";
	}

	public function getLightLevel() : int{
		return 9;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		return false;
	}

	public function onNearbyBlockChange() : void{

	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		$this->getLevel()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class RedstoneTorchUnlit extends Torch{

	protected $id = self::UNLIT_REDSTONE_TORCH;

	public function getName() : string{
		return "Unlit Redstone Torch";
	}

	public function getLightLevel() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class RedstoneTorch extends Torch{

	protected $id = self::LIT_REDSTONE_TORCH;

	public function getName() : string{
		return "Redstone Torch";
	}

	public function getLightLevel() : int{
		return 7;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class StoneButton extends Button{

	protected $id = self::STONE_BUTTON;

	public function getName() : string{
		return "Stone Button";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

abstract class Button extends Flowable{

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		//TODO: check valid target block
		$this->meta = $face;

		return $this->level->setBlock($this, $this, true, true);
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		//TODO
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;

class SnowLayer extends Flowable{

	protected $id = self::SNOW_LAYER;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Snow Layer";
	}

	public function canBeReplaced() : bool{
		return true;
	}

	public function getHardness() : float{
		return 0.1;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($blockReplace->getSide(Vector3::SIDE_DOWN)->isSolid()){
			//TODO: fix placement
			$this->getLevel()->setBlock($blockReplace, $this, true);

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if(!$this->getSide(Vector3::SIDE_DOWN)->isSolid()){
			$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		if($this->level->getBlockLightAt($this->x, $this->y, $this->z) >= 12){
			$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
		}
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::SNOWBALL) //TODO: check layer count
		];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\Item;
use pocketmine\Player;

class Ice extends Transparent{

	protected $id = self::ICE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Ice";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getLightFilter() : int{
		return 2;
	}

	public function getFrictionFactor() : float{
		return 0.98;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function onBreak(Item $item, Player $player = null) : bool{
		if(($player === null or $player->isSurvival()) and !$item->hasEnchantment(Enchantment::SILK_TOUCH)){
			return $this->getLevel()->setBlock($this, BlockFactory::get(Block::WATER), true);
		}
		return parent::onBreak($item, $player);
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		if($this->level->getHighestAdjacentBlockLight($this->x, $this->y, $this->z) >= 12){
			$this->level->useBreakOn($this);
		}
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;

class Snow extends Solid{

	protected $id = self::SNOW_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Snow Block";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::SNOWBALL, 0, 4)
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Cactus extends Transparent{

	protected $id = self::CACTUS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.4;
	}

	public function hasEntityCollision() : bool{
		return true;
	}

	public function getName() : string{
		return "Cactus";
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		return new AxisAlignedBB(
			$this->x + 0.0625,
			$this->y + 0.0625,
			$this->z + 0.0625,
			$this->x + 0.9375,
			$this->y + 0.9375,
			$this->z + 0.9375
		);
	}

	public function onEntityCollide(Entity $entity) : void{
		$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
		$entity->attack($ev);
	}

	public function onNearbyBlockChange() : void{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() !== self::SAND and $down->getId() !== self::CACTUS){
			$this->getLevel()->useBreakOn($this);
		}else{
			for($side = 2; $side <= 5; ++$side){
				$b = $this->getSide($side);
				if($b->isSolid()){
					$this->getLevel()->useBreakOn($this);
					break;
				}
			}
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
			if($this->meta === 0x0f){
				for($y = 1; $y < 3; ++$y){
					$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
					if($b->getId() === self::AIR){
						$ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS));
						$ev->call();
						if($ev->isCancelled()){
							break;
						}
						$this->getLevel()->setBlock($b, $ev->getNewState(), true);
					}else{
						break;
					}
				}
				$this->meta = 0;
				$this->getLevel()->setBlock($this, $this);
			}else{
				++$this->meta;
				$this->getLevel()->setBlock($this, $this);
			}
		}
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() === self::SAND or $down->getId() === self::CACTUS){
			$block0 = $this->getSide(Vector3::SIDE_NORTH);
			$block1 = $this->getSide(Vector3::SIDE_SOUTH);
			$block2 = $this->getSide(Vector3::SIDE_WEST);
			$block3 = $this->getSide(Vector3::SIDE_EAST);
			if(!$block0->isSolid() and !$block1->isSolid() and !$block2->isSolid() and !$block3->isSolid()){
				$this->getLevel()->setBlock($this, $this, true);

				return true;
			}
		}

		return false;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;

class Clay extends Solid{

	protected $id = self::CLAY_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.6;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getName() : string{
		return "Clay Block";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::CLAY_BALL, 0, 4)
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Sugarcane extends Flowable{

	protected $id = self::SUGARCANE_BLOCK;

	protected $itemId = Item::SUGARCANE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Sugarcane";
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
			if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
				for($y = 1; $y < 3; ++$y){
					$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
					if($b->getId() === self::AIR){
						$ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK));
						$ev->call();
						if($ev->isCancelled()){
							break;
						}
						$this->getLevel()->setBlock($b, $ev->getNewState(), true);
					}else{
						break;
					}
				}
				$this->meta = 0;
				$this->getLevel()->setBlock($this, $this, true);
			}

			$item->count--;

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->isTransparent() and $down->getId() !== self::SUGARCANE_BLOCK){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
			if($this->meta === 0x0F){
				for($y = 1; $y < 3; ++$y){
					$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
					if($b->getId() === self::AIR){
						$this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
						break;
					}
				}
				$this->meta = 0;
				$this->getLevel()->setBlock($this, $this, true);
			}else{
				++$this->meta;
				$this->getLevel()->setBlock($this, $this, true);
			}
		}
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() === self::SUGARCANE_BLOCK){
			$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);

			return true;
		}elseif($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::SAND){
			$block0 = $down->getSide(Vector3::SIDE_NORTH);
			$block1 = $down->getSide(Vector3::SIDE_SOUTH);
			$block2 = $down->getSide(Vector3::SIDE_WEST);
			$block3 = $down->getSide(Vector3::SIDE_EAST);
			if(($block0 instanceof Water) or ($block1 instanceof Water) or ($block2 instanceof Water) or ($block3 instanceof Water)){
				$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);

				return true;
			}
		}

		return false;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class WoodenFence extends Fence{
	public const FENCE_OAK = 0;
	public const FENCE_SPRUCE = 1;
	public const FENCE_BIRCH = 2;
	public const FENCE_JUNGLE = 3;
	public const FENCE_ACACIA = 4;
	public const FENCE_DARKOAK = 5;

	protected $id = self::FENCE;

	public function getHardness() : float{
		return 2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getName() : string{
		static $names = [
			self::FENCE_OAK => "Oak Fence",
			self::FENCE_SPRUCE => "Spruce Fence",
			self::FENCE_BIRCH => "Birch Fence",
			self::FENCE_JUNGLE => "Jungle Fence",
			self::FENCE_ACACIA => "Acacia Fence",
			self::FENCE_DARKOAK => "Dark Oak Fence"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function getFuelTime() : int{
		return 300;
	}

	public function getFlameEncouragement() : int{
		return 5;
	}

	public function getFlammability() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use function count;

abstract class Fence extends Transparent{

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getThickness() : float{
		return 0.25;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		$width = 0.5 - $this->getThickness() / 2;

		return new AxisAlignedBB(
			$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
			$this->y,
			$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
			$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
			$this->y + 1.5,
			$this->z + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_SOUTH)) ? 0 : $width)
		);
	}

	protected function recalculateCollisionBoxes() : array{
		$inset = 0.5 - $this->getThickness() / 2;

		/** @var AxisAlignedBB[] $bbs */
		$bbs = [];

		$connectWest = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
		$connectEast = $this->canConnect($this->getSide(Vector3::SIDE_EAST));

		if($connectWest or $connectEast){
			//X axis (west/east)
			$bbs[] = new AxisAlignedBB(
				$this->x + ($connectWest ? 0 : $inset),
				$this->y,
				$this->z + $inset,
				$this->x + 1 - ($connectEast ? 0 : $inset),
				$this->y + 1.5,
				$this->z + 1 - $inset
			);
		}

		$connectNorth = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
		$connectSouth = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));

		if($connectNorth or $connectSouth){
			//Z axis (north/south)
			$bbs[] = new AxisAlignedBB(
				$this->x + $inset,
				$this->y,
				$this->z + ($connectNorth ? 0 : $inset),
				$this->x + 1 - $inset,
				$this->y + 1.5,
				$this->z + 1 - ($connectSouth ? 0 : $inset)
			);
		}

		if(count($bbs) === 0){
			//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
			return [
				new AxisAlignedBB(
					$this->x + $inset,
					$this->y,
					$this->z + $inset,
					$this->x + 1 - $inset,
					$this->y + 1.5,
					$this->z + 1 - $inset
				)
			];
		}

		return $bbs;
	}

	/**
	 * @return bool
	 */
	public function canConnect(Block $block){
		return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Pumpkin extends Solid{

	protected $id = self::PUMPKIN;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 1;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getName() : string{
		return "Pumpkin";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($player instanceof Player){
			$this->meta = ((int) $player->getDirection() + 1) % 4;
		}
		$this->getLevel()->setBlock($blockReplace, $this, true, true);

		return true;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Netherrack extends Solid{

	protected $id = self::NETHERRACK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Netherrack";
	}

	public function getHardness() : float{
		return 0.4;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function burnsForever() : bool{
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\math\AxisAlignedBB;

class SoulSand extends Solid{

	protected $id = self::SOUL_SAND;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Soul Sand";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		return new AxisAlignedBB(
			$this->x,
			$this->y,
			$this->z,
			$this->x + 1,
			$this->y + 1 - 0.125,
			$this->z + 1
		);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use function mt_rand;

class Glowstone extends Transparent{

	protected $id = self::GLOWSTONE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Glowstone";
	}

	public function getHardness() : float{
		return 0.3;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getLightLevel() : int{
		return 15;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::GLOWSTONE_DUST, 0, mt_rand(2, 4))
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class LitPumpkin extends Pumpkin{

	protected $id = self::LIT_PUMPKIN;

	public function getLightLevel() : int{
		return 15;
	}

	public function getName() : string{
		return "Jack o'Lantern";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\EffectInstance;
use pocketmine\entity\Living;
use pocketmine\item\FoodSource;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Cake extends Transparent implements FoodSource{

	protected $id = self::CAKE_BLOCK;

	protected $itemId = Item::CAKE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getName() : string{
		return "Cake";
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		$f = $this->getDamage() * 0.125; //1 slice width

		return new AxisAlignedBB(
			$this->x + 0.0625 + $f,
			$this->y,
			$this->z + 0.0625,
			$this->x + 1 - 0.0625,
			$this->y + 0.5,
			$this->z + 1 - 0.0625
		);
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() !== self::AIR){
			$this->getLevel()->setBlock($blockReplace, $this, true, true);

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
			$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
		}
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($player !== null){
			$player->consumeObject($this);
			return true;
		}

		return false;
	}

	public function getFoodRestore() : int{
		return 2;
	}

	public function getSaturationRestore() : float{
		return 0.4;
	}

	public function requiresHunger() : bool{
		return true;
	}

	/**
	 * @return Block
	 */
	public function getResidue(){
		$clone = clone $this;
		$clone->meta++;
		if($clone->meta > 0x06){
			$clone = BlockFactory::get(Block::AIR);
		}
		return $clone;
	}

	/**
	 * @return EffectInstance[]
	 */
	public function getAdditionalEffects() : array{
		return [];
	}

	public function onConsume(Living $consumer) : void{
		$this->level->setBlock($this, $this->getResidue());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

/**
 * Interface implemented by objects that can be consumed by players, giving them food and saturation.
 */
interface FoodSource extends Consumable{

	public function getFoodRestore() : int;

	public function getSaturationRestore() : float;

	/**
	 * Returns whether a Human eating this FoodSource must have a non-full hunger bar.
	 */
	public function requiresHunger() : bool;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\entity\EffectInstance;
use pocketmine\entity\Living;

/**
 * Interface implemented by objects that can be consumed by mobs.
 */
interface Consumable{

	/**
	 * Returns the leftover that this Consumable produces when it is consumed. For Items, this is usually air, but could
	 * be an Item to add to a Player's inventory afterwards (such as a bowl).
	 *
	 * @return Item|Block|mixed
	 */
	public function getResidue();

	/**
	 * @return EffectInstance[]
	 */
	public function getAdditionalEffects() : array;

	/**
	 * Called when this Consumable is consumed by mob, after standard resulting effects have been applied.
	 *
	 * @return void
	 */
	public function onConsume(Living $consumer);
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;

class InvisibleBedrock extends Transparent{

	protected $id = self::INVISIBLE_BEDROCK;

	public function __construct(){

	}

	public function getName() : string{
		return "Invisible Bedrock";
	}

	public function getHardness() : float{
		return -1;
	}

	public function getBlastResistance() : float{
		return 18000000;
	}

	public function isBreakable(Item $item) : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\level\sound\DoorSound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Trapdoor extends Transparent{
	public const MASK_UPPER = 0x04;
	public const MASK_OPENED = 0x08;
	public const MASK_SIDE = 0x03;
	public const MASK_SIDE_SOUTH = 2;
	public const MASK_SIDE_NORTH = 3;
	public const MASK_SIDE_EAST = 0;
	public const MASK_SIDE_WEST = 1;

	protected $id = self::TRAPDOOR;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Wooden Trapdoor";
	}

	public function getHardness() : float{
		return 3;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		$damage = $this->getDamage();

		$f = 0.1875;

		if(($damage & self::MASK_UPPER) > 0){
			$bb = new AxisAlignedBB(
				$this->x,
				$this->y + 1 - $f,
				$this->z,
				$this->x + 1,
				$this->y + 1,
				$this->z + 1
			);
		}else{
			$bb = new AxisAlignedBB(
				$this->x,
				$this->y,
				$this->z,
				$this->x + 1,
				$this->y + $f,
				$this->z + 1
			);
		}

		if(($damage & self::MASK_OPENED) > 0){
			if(($damage & 0x03) === self::MASK_SIDE_NORTH){
				$bb->setBounds(
					$this->x,
					$this->y,
					$this->z + 1 - $f,
					$this->x + 1,
					$this->y + 1,
					$this->z + 1
				);
			}elseif(($damage & 0x03) === self::MASK_SIDE_SOUTH){
				$bb->setBounds(
					$this->x,
					$this->y,
					$this->z,
					$this->x + 1,
					$this->y + 1,
					$this->z + $f
				);
			}
			if(($damage & 0x03) === self::MASK_SIDE_WEST){
				$bb->setBounds(
					$this->x + 1 - $f,
					$this->y,
					$this->z,
					$this->x + 1,
					$this->y + 1,
					$this->z + 1
				);
			}
			if(($damage & 0x03) === self::MASK_SIDE_EAST){
				$bb->setBounds(
					$this->x,
					$this->y,
					$this->z,
					$this->x + $f,
					$this->y + 1,
					$this->z + 1
				);
			}
		}

		return $bb;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$directions = [
			0 => 1,
			1 => 3,
			2 => 0,
			3 => 2
		];
		if($player !== null){
			$this->meta = $directions[$player->getDirection() & 0x03];
		}
		if(($clickVector->y > 0.5 and $face !== self::SIDE_UP) or $face === self::SIDE_DOWN){
			$this->meta |= self::MASK_UPPER; //top half of block
		}
		$this->getLevel()->setBlock($blockReplace, $this, true, true);
		return true;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		$this->meta ^= self::MASK_OPENED;
		$this->getLevel()->setBlock($this, $this, true);
		$this->level->addSound(new DoorSound($this));
		return true;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getFuelTime() : int{
		return 300;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class StoneBricks extends Solid{
	public const NORMAL = 0;
	public const MOSSY = 1;
	public const CRACKED = 2;
	public const CHISELED = 3;

	protected $id = self::STONE_BRICKS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 1.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		static $names = [
			self::NORMAL => "Stone Bricks",
			self::MOSSY => "Mossy Stone Bricks",
			self::CRACKED => "Cracked Stone Bricks",
			self::CHISELED => "Chiseled Stone Bricks"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use function mt_rand;

class BrownMushroomBlock extends RedMushroomBlock{

	protected $id = Block::BROWN_MUSHROOM_BLOCK;

	public function getName() : string{
		return "Brown Mushroom Block";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			Item::get(Item::BROWN_MUSHROOM, 0, mt_rand(0, 2))
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use function mt_rand;

class RedMushroomBlock extends Solid{

	protected $id = Block::RED_MUSHROOM_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Red Mushroom Block";
	}

	public function getHardness() : float{
		return 0.2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			Item::get(Item::RED_MUSHROOM, 0, mt_rand(0, 2))
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class IronBars extends Thin{

	protected $id = self::IRON_BARS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Iron Bars";
	}

	public function getHardness() : float{
		return 5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use function count;

abstract class Thin extends Transparent{

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		$width = 0.5 - 0.125 / 2;

		return new AxisAlignedBB(
			$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
			$this->y,
			$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
			$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
			$this->y + 1,
			$this->z + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_SOUTH)) ? 0 : $width)
		);
	}

	protected function recalculateCollisionBoxes() : array{
		$inset = 0.5 - 0.125 / 2;

		/** @var AxisAlignedBB[] $bbs */
		$bbs = [];

		$connectWest = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
		$connectEast = $this->canConnect($this->getSide(Vector3::SIDE_EAST));

		if($connectWest or $connectEast){
			//X axis (west/east)
			$bbs[] = new AxisAlignedBB(
				$this->x + ($connectWest ? 0 : $inset),
				$this->y,
				$this->z + $inset,
				$this->x + 1 - ($connectEast ? 0 : $inset),
				$this->y + 1,
				$this->z + 1 - $inset
			);
		}

		$connectNorth = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
		$connectSouth = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));

		if($connectNorth or $connectSouth){
			//Z axis (north/south)
			$bbs[] = new AxisAlignedBB(
				$this->x + $inset,
				$this->y,
				$this->z + ($connectNorth ? 0 : $inset),
				$this->x + 1 - $inset,
				$this->y + 1,
				$this->z + 1 - ($connectSouth ? 0 : $inset)
			);
		}

		if(count($bbs) === 0){
			//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
			return [
				new AxisAlignedBB(
					$this->x + $inset,
					$this->y,
					$this->z + $inset,
					$this->x + 1 - $inset,
					$this->y + 1,
					$this->z + 1 - $inset
				)
			];
		}

		return $bbs;
	}

	public function canConnect(Block $block) : bool{
		if($block instanceof Thin){
			return true;
		}

		//FIXME: currently there's no proper way to tell if a block is a full-block, so we check the bounding box size
		$bb = $block->getBoundingBox();
		return $bb !== null and $bb->getAverageEdgeLength() >= 1;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;

class GlassPane extends Thin{

	protected $id = self::GLASS_PANE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Glass Pane";
	}

	public function getHardness() : float{
		return 0.3;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use function mt_rand;

class Melon extends Transparent{

	protected $id = self::MELON_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Melon Block";
	}

	public function getHardness() : float{
		return 1;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::MELON_SLICE, 0, mt_rand(3, 7))
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use function mt_rand;

class PumpkinStem extends Crops{

	protected $id = self::PUMPKIN_STEM;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Pumpkin Stem";
	}

	public function onRandomTick() : void{
		if(mt_rand(0, 2) === 1){
			if($this->meta < 0x07){
				$block = clone $this;
				++$block->meta;
				$ev = new BlockGrowEvent($this, $block);
				$ev->call();
				if(!$ev->isCancelled()){
					$this->getLevel()->setBlock($this, $ev->getNewState(), true);
				}
			}else{
				for($side = 2; $side <= 5; ++$side){
					$b = $this->getSide($side);
					if($b->getId() === self::PUMPKIN){
						return;
					}
				}
				$side = $this->getSide(mt_rand(2, 5));
				$d = $side->getSide(Vector3::SIDE_DOWN);
				if($side->getId() === self::AIR and ($d->getId() === self::FARMLAND or $d->getId() === self::GRASS or $d->getId() === self::DIRT)){
					$ev = new BlockGrowEvent($side, BlockFactory::get(Block::PUMPKIN));
					$ev->call();
					if(!$ev->isCancelled()){
						$this->getLevel()->setBlock($side, $ev->getNewState(), true);
					}
				}
			}
		}
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::PUMPKIN_SEEDS, 0, mt_rand(0, 2))
		];
	}

	public function getPickedItem() : Item{
		return ItemFactory::get(Item::PUMPKIN_SEEDS);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use function mt_rand;

class MelonStem extends Crops{

	protected $id = self::MELON_STEM;

	public function getName() : string{
		return "Melon Stem";
	}

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function onRandomTick() : void{
		if(mt_rand(0, 2) === 1){
			if($this->meta < 0x07){
				$block = clone $this;
				++$block->meta;
				$ev = new BlockGrowEvent($this, $block);
				$ev->call();
				if(!$ev->isCancelled()){
					$this->getLevel()->setBlock($this, $ev->getNewState(), true);
				}
			}else{
				for($side = 2; $side <= 5; ++$side){
					$b = $this->getSide($side);
					if($b->getId() === self::MELON_BLOCK){
						return;
					}
				}
				$side = $this->getSide(mt_rand(2, 5));
				$d = $side->getSide(Vector3::SIDE_DOWN);
				if($side->getId() === self::AIR and ($d->getId() === self::FARMLAND or $d->getId() === self::GRASS or $d->getId() === self::DIRT)){
					$ev = new BlockGrowEvent($side, BlockFactory::get(Block::MELON_BLOCK));
					$ev->call();
					if(!$ev->isCancelled()){
						$this->getLevel()->setBlock($side, $ev->getNewState(), true);
					}
				}
			}
		}
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::MELON_SEEDS, 0, mt_rand(0, 2))
		];
	}

	public function getPickedItem() : Item{
		return ItemFactory::get(Item::MELON_SEEDS);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function max;
use function min;

class Vine extends Flowable{
	public const FLAG_SOUTH = 0x01;
	public const FLAG_WEST = 0x02;
	public const FLAG_NORTH = 0x04;
	public const FLAG_EAST = 0x08;

	protected $id = self::VINE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Vines";
	}

	public function getHardness() : float{
		return 0.2;
	}

	public function canPassThrough() : bool{
		return true;
	}

	public function hasEntityCollision() : bool{
		return true;
	}

	public function canClimb() : bool{
		return true;
	}

	public function canBeReplaced() : bool{
		return true;
	}

	public function onEntityCollide(Entity $entity) : void{
		$entity->resetFallDistance();
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		$minX = 1;
		$minY = 1;
		$minZ = 1;
		$maxX = 0;
		$maxY = 0;
		$maxZ = 0;

		$flag = $this->meta > 0;

		if(($this->meta & self::FLAG_WEST) > 0){
			$maxX = max($maxX, 0.0625);
			$minX = 0;
			$minY = 0;
			$maxY = 1;
			$minZ = 0;
			$maxZ = 1;
			$flag = true;
		}

		if(($this->meta & self::FLAG_EAST) > 0){
			$minX = min($minX, 0.9375);
			$maxX = 1;
			$minY = 0;
			$maxY = 1;
			$minZ = 0;
			$maxZ = 1;
			$flag = true;
		}

		if(($this->meta & self::FLAG_SOUTH) > 0){
			$minZ = min($minZ, 0.9375);
			$maxZ = 1;
			$minX = 0;
			$maxX = 1;
			$minY = 0;
			$maxY = 1;
			$flag = true;
		}

		//TODO: Missing NORTH check

		if(!$flag and $this->getSide(Vector3::SIDE_UP)->isSolid()){
			$minY = min($minY, 0.9375);
			$maxY = 1;
			$minX = 0;
			$maxX = 1;
			$minZ = 0;
			$maxZ = 1;
		}

		return new AxisAlignedBB(
			$this->x + $minX,
			$this->y + $minY,
			$this->z + $minZ,
			$this->x + $maxX,
			$this->y + $maxY,
			$this->z + $maxZ
		);
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if(!$blockClicked->isSolid() or $face === Vector3::SIDE_UP or $face === Vector3::SIDE_DOWN){
			return false;
		}

		$faces = [
			Vector3::SIDE_NORTH => self::FLAG_SOUTH,
			Vector3::SIDE_SOUTH => self::FLAG_NORTH,
			Vector3::SIDE_WEST => self::FLAG_EAST,
			Vector3::SIDE_EAST => self::FLAG_WEST
		];

		$this->meta = $faces[$face] ?? 0;
		if($blockReplace->getId() === $this->getId()){
			$this->meta |= $blockReplace->meta;
		}

		$this->getLevel()->setBlock($blockReplace, $this, true, true);
		return true;
	}

	public function onNearbyBlockChange() : void{
		$sides = [
			self::FLAG_SOUTH => Vector3::SIDE_SOUTH,
			self::FLAG_WEST => Vector3::SIDE_WEST,
			self::FLAG_NORTH => Vector3::SIDE_NORTH,
			self::FLAG_EAST => Vector3::SIDE_EAST
		];

		$meta = $this->meta;

		foreach($sides as $flag => $side){
			if(($meta & $flag) === 0){
				continue;
			}

			if(!$this->getSide($side)->isSolid()){
				$meta &= ~$flag;
			}
		}

		if($meta !== $this->meta){
			if($meta === 0){
				$this->level->useBreakOn($this);
			}else{
				$this->meta = $meta;
				$this->level->setBlock($this, $this);
			}
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		//TODO: vine growth
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function getDrops(Item $item) : array{
		if(($item->getBlockToolType() & BlockToolType::TYPE_SHEARS) !== 0){
			return $this->getDropsForCompatibleTool($item);
		}

		return [];
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getFlameEncouragement() : int{
		return 15;
	}

	public function getFlammability() : int{
		return 100;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\level\sound\DoorSound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

class FenceGate extends Transparent{

	public function getHardness() : float{
		return 2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		if(($this->getDamage() & 0x04) > 0){
			return null;
		}

		$i = ($this->getDamage() & 0x03);
		if($i === 2 or $i === 0){
			return new AxisAlignedBB(
				$this->x,
				$this->y,
				$this->z + 0.375,
				$this->x + 1,
				$this->y + 1.5,
				$this->z + 0.625
			);
		}else{
			return new AxisAlignedBB(
				$this->x + 0.375,
				$this->y,
				$this->z,
				$this->x + 0.625,
				$this->y + 1.5,
				$this->z + 1
			);
		}
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$this->meta = ($player instanceof Player ? ($player->getDirection() - 1) & 0x03 : 0);
		$this->getLevel()->setBlock($blockReplace, $this, true, true);

		return true;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		$this->meta = (($this->meta ^ 0x04) & ~0x02);

		if($player !== null){
			$this->meta |= (($player->getDirection() - 1) & 0x02);
		}

		$this->getLevel()->setBlock($this, $this, true);
		$this->level->addSound(new DoorSound($this));
		return true;
	}

	public function getFuelTime() : int{
		return 300;
	}

	public function getFlameEncouragement() : int{
		return 5;
	}

	public function getFlammability() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class BrickStairs extends Stair{

	protected $id = self::BRICK_STAIRS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getBlastResistance() : float{
		return 30;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Brick Stairs";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class StoneBrickStairs extends Stair{

	protected $id = self::STONE_BRICK_STAIRS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getHardness() : float{
		return 1.5;
	}

	public function getName() : string{
		return "Stone Brick Stairs";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use function mt_rand;

class Mycelium extends Solid{

	protected $id = self::MYCELIUM;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Mycelium";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getHardness() : float{
		return 0.6;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::DIRT)
		];
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		//TODO: light levels
		$x = mt_rand($this->x - 1, $this->x + 1);
		$y = mt_rand($this->y - 2, $this->y + 2);
		$z = mt_rand($this->z - 1, $this->z + 1);
		$block = $this->getLevel()->getBlockAt($x, $y, $z);
		if($block->getId() === Block::DIRT){
			if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
				$ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM));
				$ev->call();
				if(!$ev->isCancelled()){
					$this->getLevel()->setBlock($block, $ev->getNewState());
				}
			}
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

class WaterLily extends Flowable{

	protected $id = self::WATER_LILY;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Lily Pad";
	}

	public function getHardness() : float{
		return 0.6;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return new AxisAlignedBB(
			$this->x + 0.0625,
			$this->y,
			$this->z + 0.0625,
			$this->x + 0.9375,
			$this->y + 0.015625,
			$this->z + 0.9375
		);
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($blockClicked instanceof Water){
			$up = $blockClicked->getSide(Vector3::SIDE_UP);
			if($up->getId() === Block::AIR){
				$this->getLevel()->setBlock($up, $this, true, true);
				return true;
			}
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if(!($this->getSide(Vector3::SIDE_DOWN) instanceof Water)){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class NetherBrick extends Solid{

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getHardness() : float{
		return 2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class NetherBrickFence extends Fence{

	protected $id = self::NETHER_BRICK_FENCE;

	public function getHardness() : float{
		return 2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Nether Brick Fence";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class NetherBrickStairs extends Stair{

	protected $id = self::NETHER_BRICK_STAIRS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Nether Brick Stairs";
	}

	public function getHardness() : float{
		return 2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function mt_rand;

class NetherWartPlant extends Flowable{
	protected $id = Block::NETHER_WART_PLANT;

	protected $itemId = Item::NETHER_WART;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Nether Wart";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() === Block::SOUL_SAND){
			$this->getLevel()->setBlock($blockReplace, $this, false, true);

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::SOUL_SAND){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function ticksRandomly() : bool{
		return true;
	}

	public function onRandomTick() : void{
		if($this->meta < 3 and mt_rand(0, 10) === 0){ //Still growing
			$block = clone $this;
			$block->meta++;
			$ev = new BlockGrowEvent($this, $block);
			$ev->call();
			if(!$ev->isCancelled()){
				$this->getLevel()->setBlock($this, $ev->getNewState(), false, true);
			}
		}
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get($this->getItemId(), 0, ($this->getDamage() === 3 ? mt_rand(2, 4) : 1))
		];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\inventory\EnchantInventory;
use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\EnchantTable as TileEnchantTable;
use pocketmine\tile\Tile;

class EnchantingTable extends Transparent{

	protected $id = self::ENCHANTING_TABLE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$this->getLevel()->setBlock($blockReplace, $this, true, true);

		Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player));

		return true;
	}

	public function getHardness() : float{
		return 5;
	}

	public function getBlastResistance() : float{
		return 6000;
	}

	public function getName() : string{
		return "Enchanting Table";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($player instanceof Player){
			//TODO lock

			$player->addWindow(new EnchantInventory($this));
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\TieredTool;

class BrewingStand extends Transparent{

	protected $id = self::BREWING_STAND_BLOCK;

	protected $itemId = Item::BREWING_STAND;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Brewing Stand";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;

class EndPortalFrame extends Solid{

	protected $id = self::END_PORTAL_FRAME;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getLightLevel() : int{
		return 1;
	}

	public function getName() : string{
		return "End Portal Frame";
	}

	public function getHardness() : float{
		return -1;
	}

	public function getBlastResistance() : float{
		return 18000000;
	}

	public function isBreakable(Item $item) : bool{
		return false;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		return new AxisAlignedBB(
			$this->x,
			$this->y,
			$this->z,
			$this->x + 1,
			$this->y + (($this->getDamage() & 0x04) > 0 ? 1 : 0.8125),
			$this->z + 1
		);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class EndStone extends Solid{

	protected $id = self::END_STONE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "End Stone";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getHardness() : float{
		return 3;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class RedstoneLamp extends Solid{

	protected $id = self::REDSTONE_LAMP;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Redstone Lamp";
	}

	public function getHardness() : float{
		return 0.3;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class LitRedstoneLamp extends RedstoneLamp{

	protected $id = self::LIT_REDSTONE_LAMP;

	public function getName() : string{
		return "Lit Redstone Lamp";
	}

	public function getLightLevel() : int{
		return 15;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class ActivatorRail extends RedstoneRail{

	protected $id = self::ACTIVATOR_RAIL;

	public function getName() : string{
		return "Activator Rail";
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class CocoaBlock extends Transparent{

	protected $id = self::COCOA_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Cocoa Block";
	}

	public function getHardness() : float{
		return 0.2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	//TODO

	public function isAffectedBySilkTouch() : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class SandstoneStairs extends Stair{

	protected $id = self::SANDSTONE_STAIRS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.8;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Sandstone Stairs";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;
use function mt_rand;

class EmeraldOre extends Solid{

	protected $id = self::EMERALD_ORE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Emerald Ore";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_IRON;
	}

	public function getHardness() : float{
		return 3;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::EMERALD)
		];
	}

	protected function getXpDropAmount() : int{
		return mt_rand(3, 7);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\EnderChest as TileEnderChest;
use pocketmine\tile\Tile;

class EnderChest extends Chest{

	protected $id = self::ENDER_CHEST;

	public function getHardness() : float{
		return 22.5;
	}

	public function getBlastResistance() : float{
		return 3000;
	}

	public function getLightLevel() : int{
		return 7;
	}

	public function getName() : string{
		return "Ender Chest";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$faces = [
			0 => 4,
			1 => 2,
			2 => 5,
			3 => 3
		];

		$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];

		$this->getLevel()->setBlock($blockReplace, $this, true, true);
		Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this, $face, $item, $player));

		return true;
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($player instanceof Player){

			$t = $this->getLevel()->getTile($this);
			$enderChest = null;
			if($t instanceof TileEnderChest){
				$enderChest = $t;
			}else{
				$enderChest = Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this));
				if(!($enderChest instanceof TileEnderChest)){
					return true;
				}
			}

			if(!$this->getSide(Vector3::SIDE_UP)->isTransparent()){
				return true;
			}

			$player->getEnderChestInventory()->setHolderPosition($enderChest);
			$player->addWindow($player->getEnderChestInventory());
		}

		return true;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::OBSIDIAN, 0, 8)
		];
	}

	public function getFuelTime() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class TripwireHook extends Flowable{

	protected $id = self::TRIPWIRE_HOOK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Tripwire Hook";
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;

class Tripwire extends Flowable{

	protected $id = self::TRIPWIRE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Tripwire";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::STRING)
		];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Emerald extends Solid{

	protected $id = self::EMERALD_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_IRON;
	}

	public function getName() : string{
		return "Emerald Block";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;

class CobblestoneWall extends Transparent{
	public const NONE_MOSSY_WALL = 0;
	public const MOSSY_WALL = 1;
	public const GRANITE_WALL = 2;
	public const DIORITE_WALL = 3;
	public const ANDESITE_WALL = 4;
	public const SANDSTONE_WALL = 5;
	public const BRICK_WALL = 6;
	public const STONE_BRICK_WALL = 7;
	public const MOSSY_STONE_BRICK_WALL = 8;
	public const NETHER_BRICK_WALL = 9;
	public const END_STONE_BRICK_WALL = 10;
	public const PRISMARINE_WALL = 11;
	public const RED_SANDSTONE_WALL = 12;
	public const RED_NETHER_BRICK_WALL = 13;

	protected $id = self::COBBLESTONE_WALL;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getName() : string{
		static $names = [
			self::NONE_MOSSY_WALL => "Cobblestone",
			self::MOSSY_WALL => "Mossy Cobblestone",
			self::GRANITE_WALL => "Granite",
			self::DIORITE_WALL => "Diorite",
			self::ANDESITE_WALL => "Andesite",
			self::SANDSTONE_WALL => "Sandstone",
			self::BRICK_WALL => "Brick",
			self::STONE_BRICK_WALL => "Stone Brick",
			self::MOSSY_STONE_BRICK_WALL => "Mossy Stone Brick",
			self::NETHER_BRICK_WALL => "Nether Brick",
			self::END_STONE_BRICK_WALL => "End Stone Brick",
			self::PRISMARINE_WALL => "Prismarine",
			self::RED_SANDSTONE_WALL => "Red Sandstone",
			self::RED_NETHER_BRICK_WALL => "Red Nether Brick"
		];
		return ($names[$this->getVariant()] ?? "Unknown") . " Wall";
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		//walls don't have any special collision boxes like fences do

		$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
		$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
		$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
		$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));

		$inset = 0.25;
		if(
			$this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR and //if there is a block on top, it stays as a post
			(
				($north and $south and !$west and !$east) or
				(!$north and !$south and $west and $east)
			)
		){
			//If connected to two sides on the same axis but not any others, AND there is not a block on top, there is no post and the wall is thinner
			$inset = 0.3125;
		}

		return new AxisAlignedBB(
			$this->x + ($west ? 0 : $inset),
			$this->y,
			$this->z + ($north ? 0 : $inset),
			$this->x + 1 - ($east ? 0 : $inset),
			$this->y + 1.5,
			$this->z + 1 - ($south ? 0 : $inset)
		);
	}

	/**
	 * @return bool
	 */
	public function canConnect(Block $block){
		return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\FlowerPot as TileFlowerPot;
use pocketmine\tile\Tile;

class FlowerPot extends Flowable{

	public const STATE_EMPTY = 0;
	public const STATE_FULL = 1;

	protected $id = self::FLOWER_POT_BLOCK;
	protected $itemId = Item::FLOWER_POT;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Flower Pot";
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return new AxisAlignedBB(
			$this->x + 0.3125,
			$this->y,
			$this->z + 0.3125,
			$this->x + 0.6875,
			$this->y + 0.375,
			$this->z + 0.6875
		);
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
			return false;
		}

		$this->getLevel()->setBlock($blockReplace, $this, true, true);
		Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player));
		return true;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		$pot = $this->getLevel()->getTile($this);
		if(!($pot instanceof TileFlowerPot)){
			return false;
		}
		if(!$pot->canAddItem($item)){
			return true;
		}

		$this->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item.
		$this->getLevel()->setBlock($this, $this, true, false);
		$pot->setItem($item->pop());

		return true;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		$items = parent::getDropsForCompatibleTool($item);

		$tile = $this->getLevel()->getTile($this);
		if($tile instanceof TileFlowerPot){
			$item = $tile->getItem();
			if($item->getId() !== Item::AIR){
				$items[] = $item;
			}
		}

		return $items;
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use function mt_rand;

class Carrot extends Crops{

	protected $id = self::CARROT_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Carrot Block";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::CARROT, 0, $this->meta >= 0x07 ? mt_rand(1, 4) : 1)
		];
	}

	public function getPickedItem() : Item{
		return ItemFactory::get(Item::CARROT);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use function mt_rand;

class Potato extends Crops{

	protected $id = self::POTATO_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Potato Block";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::POTATO, 0, $this->getDamage() >= 0x07 ? mt_rand(1, 4) : 1)
		];
	}

	public function getPickedItem() : Item{
		return ItemFactory::get(Item::POTATO);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class WoodenButton extends Button{

	protected $id = self::WOODEN_BUTTON;

	public function getName() : string{
		return "Wooden Button";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\Skull as TileSkull;
use pocketmine\tile\Tile;

class Skull extends Flowable{

	protected $id = self::SKULL_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 1;
	}

	public function getName() : string{
		return "Mob Head";
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		//TODO: different bounds depending on attached face (meta)
		return new AxisAlignedBB(
			$this->x + 0.25,
			$this->y,
			$this->z + 0.25,
			$this->x + 0.75,
			$this->y + 0.5,
			$this->z + 0.75
		);
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($face === Vector3::SIDE_DOWN){
			return false;
		}

		$this->meta = $face;
		$this->getLevel()->setBlock($blockReplace, $this, true);
		Tile::createTile(Tile::SKULL, $this->getLevel(), TileSkull::createNBT($this, $face, $item, $player));

		return true;
	}

	private function getItem() : Item{
		$tile = $this->level->getTile($this);
		return ItemFactory::get(Item::SKULL, $tile instanceof TileSkull ? $tile->getType() : 0);
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [$this->getItem()];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}

	public function getPickedItem() : Item{
		return $this->getItem();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\inventory\AnvilInventory;
use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Anvil extends Fallable{

	public const TYPE_NORMAL = 0;
	public const TYPE_SLIGHTLY_DAMAGED = 4;
	public const TYPE_VERY_DAMAGED = 8;

	protected $id = self::ANVIL;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function isTransparent() : bool{
		return true;
	}

	public function getHardness() : float{
		return 5;
	}

	public function getBlastResistance() : float{
		return 6000;
	}

	public function getVariantBitmask() : int{
		return 0x0c;
	}

	public function getName() : string{
		static $names = [
			self::TYPE_NORMAL => "Anvil",
			self::TYPE_SLIGHTLY_DAMAGED => "Slightly Damaged Anvil",
			self::TYPE_VERY_DAMAGED => "Very Damaged Anvil"
		];
		return $names[$this->getVariant()] ?? "Anvil";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function recalculateBoundingBox() : ?AxisAlignedBB{
		$inset = 0.125;

		if(($this->meta & 0x01) !== 0){ //east/west
			return new AxisAlignedBB(
				$this->x,
				$this->y,
				$this->z + $inset,
				$this->x + 1,
				$this->y + 1,
				$this->z + 1 - $inset
			);
		}else{
			return new AxisAlignedBB(
				$this->x + $inset,
				$this->y,
				$this->z,
				$this->x + 1 - $inset,
				$this->y + 1,
				$this->z + 1
			);
		}
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		if($player instanceof Player){
			$player->addWindow(new AnvilInventory($this));
		}

		return true;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$direction = ($player !== null ? $player->getDirection() : 0) & 0x03;
		$this->meta = $this->getVariant() | $direction;
		return $this->getLevel()->setBlock($blockReplace, $this, true, true);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class TrappedChest extends Chest{

	//TODO: Redstone!

	protected $id = self::TRAPPED_CHEST;

	public function getName() : string{
		return "Trapped Chest";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class WeightedPressurePlateLight extends Transparent{

	protected $id = self::LIGHT_WEIGHTED_PRESSURE_PLATE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Weighted Pressure Plate Light";
	}

	public function isSolid() : bool{
		return false;
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class WeightedPressurePlateHeavy extends WeightedPressurePlateLight{

	protected $id = self::HEAVY_WEIGHTED_PRESSURE_PLATE;

	public function getName() : string{
		return "Weighted Pressure Plate Heavy";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class DaylightSensor extends Transparent{

	protected $id = self::DAYLIGHT_SENSOR;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Daylight Sensor";
	}

	public function getHardness() : float{
		return 0.2;
	}

	public function getFuelTime() : int{
		return 300;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Redstone extends Solid{

	protected $id = self::REDSTONE_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Redstone Block";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;
use function mt_rand;

class NetherQuartzOre extends Solid{

	protected $id = Block::NETHER_QUARTZ_ORE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Nether Quartz Ore";
	}

	public function getHardness() : float{
		return 3;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::QUARTZ)
		];
	}

	protected function getXpDropAmount() : int{
		return mt_rand(2, 5);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\PillarRotationHelper;
use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Quartz extends Solid{

	public const NORMAL = 0;
	public const CHISELED = 1;
	public const PILLAR = 2;

	protected $id = self::QUARTZ_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.8;
	}

	public function getName() : string{
		static $names = [
			self::NORMAL => "Quartz Block",
			self::CHISELED => "Chiseled Quartz Block",
			self::PILLAR => "Quartz Pillar"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($this->getVariant() !== self::NORMAL){
			$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
		}
		return $this->getLevel()->setBlock($blockReplace, $this, true, true);
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getVariantBitmask() : int{
		return 0x03;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class QuartzStairs extends Stair{

	protected $id = self::QUARTZ_STAIRS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.8;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Quartz Stairs";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class DoubleWoodenSlab extends DoubleSlab{

	protected $id = self::DOUBLE_WOODEN_SLAB;

	public function getSlabId() : int{
		return self::WOODEN_SLAB;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getFlameEncouragement() : int{
		return 5;
	}

	public function getFlammability() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class WoodenSlab extends Slab{

	protected $id = self::WOODEN_SLAB;

	public function getDoubleSlabId() : int{
		return self::DOUBLE_WOODEN_SLAB;
	}

	public function getHardness() : float{
		return 2;
	}

	public function getName() : string{
		static $names = [
			0 => "Oak",
			1 => "Spruce",
			2 => "Birch",
			3 => "Jungle",
			4 => "Acacia",
			5 => "Dark Oak"
		];
		return (($this->meta & 0x08) === 0x08 ? "Upper " : "") . ($names[$this->getVariant()] ?? "") . " Wooden Slab";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getFuelTime() : int{
		return 300;
	}

	public function getFlameEncouragement() : int{
		return 5;
	}

	public function getFlammability() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\ColorBlockMetaHelper;

class StainedClay extends HardenedClay{

	protected $id = self::STAINED_CLAY;

	public function getName() : string{
		return ColorBlockMetaHelper::getColorFromMeta($this->getVariant()) . " Stained Clay";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class HardenedClay extends Solid{

	protected $id = self::HARDENED_CLAY;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Hardened Clay";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getHardness() : float{
		return 1.25;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\ColorBlockMetaHelper;

class StainedGlassPane extends GlassPane{

	protected $id = self::STAINED_GLASS_PANE;

	public function getName() : string{
		return ColorBlockMetaHelper::getColorFromMeta($this->getVariant()) . " Stained Glass Pane";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;

class Leaves2 extends Leaves{

	protected $id = self::LEAVES2;
	/** @var int */
	protected $woodType = self::WOOD2;

	public function getName() : string{
		static $names = [
			self::ACACIA => "Acacia Leaves",
			self::DARK_OAK => "Dark Oak Leaves"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function getSaplingItem() : Item{
		return ItemFactory::get(Item::SAPLING, $this->getVariant() + 4);
	}

	public function canDropApples() : bool{
		return $this->getVariant() === self::DARK_OAK;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class Wood2 extends Wood{

	public const ACACIA = 0;
	public const DARK_OAK = 1;

	protected $id = self::WOOD2;

	public function getName() : string{
		static $names = [
			0 => "Acacia Wood",
			1 => "Dark Oak Wood"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class IronTrapdoor extends Trapdoor{

	protected $id = self::IRON_TRAPDOOR;

	public function getName() : string{
		return "Iron Trapdoor";
	}

	public function getHardness() : float{
		return 5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getFuelTime() : int{
		return 0; //TODO: remove this hack on 4.0
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Prismarine extends Solid{

	public const NORMAL = 0;
	public const DARK = 1;
	public const BRICKS = 2;

	protected $id = self::PRISMARINE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 1.5;
	}

	public function getName() : string{
		static $names = [
			self::NORMAL => "Prismarine",
			self::DARK => "Dark Prismarine",
			self::BRICKS => "Prismarine Bricks"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getVariantBitmask() : int{
		return 0x03;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;

class SeaLantern extends Transparent{

	protected $id = self::SEA_LANTERN;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Sea Lantern";
	}

	public function getHardness() : float{
		return 0.3;
	}

	public function getLightLevel() : int{
		return 15;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::PRISMARINE_CRYSTALS, 0, 3)
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\PillarRotationHelper;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;

class HayBale extends Solid{

	protected $id = self::HAY_BALE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Hay Bale";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
		$this->getLevel()->setBlock($blockReplace, $this, true, true);

		return true;
	}

	public function getVariantBitmask() : int{
		return 0x03;
	}

	public function getFlameEncouragement() : int{
		return 60;
	}

	public function getFlammability() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Carpet extends Flowable{

	protected $id = self::CARPET;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 0.1;
	}

	public function isSolid() : bool{
		return true;
	}

	public function getName() : string{
		return ColorBlockMetaHelper::getColorFromMeta($this->getVariant()) . " Carpet";
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{

		return new AxisAlignedBB(
			$this->x,
			$this->y,
			$this->z,
			$this->x + 1,
			$this->y + 0.0625,
			$this->z + 1
		);
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$down = $this->getSide(Vector3::SIDE_DOWN);
		if($down->getId() !== self::AIR){
			$this->getLevel()->setBlock($blockReplace, $this, true, true);

			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function getFlameEncouragement() : int{
		return 30;
	}

	public function getFlammability() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Coal extends Solid{

	protected $id = self::COAL_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getName() : string{
		return "Coal Block";
	}

	public function getFuelTime() : int{
		return 16000;
	}

	public function getFlameEncouragement() : int{
		return 5;
	}

	public function getFlammability() : int{
		return 5;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;

class PackedIce extends Solid{

	protected $id = self::PACKED_ICE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Packed Ice";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getFrictionFactor() : float{
		return 0.98;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function mt_rand;

class DoublePlant extends Flowable{
	public const BITFLAG_TOP = 0x08;

	protected $id = self::DOUBLE_PLANT;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function canBeReplaced() : bool{
		return $this->getVariant() === 2 or $this->getVariant() === 3; //grass or fern
	}

	public function getName() : string{
		static $names = [
			0 => "Sunflower",
			1 => "Lilac",
			2 => "Double Tallgrass",
			3 => "Large Fern",
			4 => "Rose Bush",
			5 => "Peony"
		];
		return $names[$this->getVariant()] ?? "";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$id = $blockReplace->getSide(Vector3::SIDE_DOWN)->getId();
		if(($id === Block::GRASS or $id === Block::DIRT) and $blockReplace->getSide(Vector3::SIDE_UP)->canBeReplaced()){
			$this->getLevel()->setBlock($blockReplace, $this, false, false);
			$this->getLevel()->setBlock($blockReplace->getSide(Vector3::SIDE_UP), BlockFactory::get($this->id, $this->meta | self::BITFLAG_TOP), false, false);

			return true;
		}

		return false;
	}

	/**
	 * Returns whether this double-plant has a corresponding other half.
	 */
	public function isValidHalfPlant() : bool{
		if(($this->meta & self::BITFLAG_TOP) !== 0){
			$other = $this->getSide(Vector3::SIDE_DOWN);
		}else{
			$other = $this->getSide(Vector3::SIDE_UP);
		}

		return (
			$other->getId() === $this->getId() and
			$other->getVariant() === $this->getVariant() and
			($other->getDamage() & self::BITFLAG_TOP) !== ($this->getDamage() & self::BITFLAG_TOP)
		);
	}

	public function onNearbyBlockChange() : void{
		if(!$this->isValidHalfPlant() or (($this->meta & self::BITFLAG_TOP) === 0 and $this->getSide(Vector3::SIDE_DOWN)->isTransparent())){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function getVariantBitmask() : int{
		return 0x07;
	}

	public function getToolType() : int{
		return ($this->getVariant() === 2 or $this->getVariant() === 3) ? BlockToolType::TYPE_SHEARS : BlockToolType::TYPE_NONE;
	}

	public function getToolHarvestLevel() : int{
		return ($this->getVariant() === 2 or $this->getVariant() === 3) ? 1 : 0; //only grass or fern require shears
	}

	public function getDrops(Item $item) : array{
		if(($this->meta & self::BITFLAG_TOP) !== 0){
			if($this->isCompatibleWithTool($item)){
				return parent::getDrops($item);
			}

			if(mt_rand(0, 24) === 0){
				return [
					ItemFactory::get(Item::SEEDS)
				];
			}
		}

		return [];
	}

	public function getAffectedBlocks() : array{
		if($this->isValidHalfPlant()){
			return [$this, $this->getSide(($this->meta & self::BITFLAG_TOP) !== 0 ? Vector3::SIDE_DOWN : Vector3::SIDE_UP)];
		}

		return parent::getAffectedBlocks();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\Banner as TileBanner;
use pocketmine\tile\Tile;
use function floor;

class StandingBanner extends Transparent{

	protected $id = self::STANDING_BANNER;

	protected $itemId = Item::BANNER;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getHardness() : float{
		return 1;
	}

	public function isSolid() : bool{
		return false;
	}

	public function getName() : string{
		return "Standing Banner";
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return null;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($face !== Vector3::SIDE_DOWN){
			if($face === Vector3::SIDE_UP and $player !== null){
				$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
				$this->getLevel()->setBlock($blockReplace, $this, true);
			}else{
				$this->meta = $face;
				$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $this->meta), true);
			}

			Tile::createTile(Tile::BANNER, $this->getLevel(), TileBanner::createNBT($this, $face, $item, $player));
			return true;
		}

		return false;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
			$this->getLevel()->useBreakOn($this);
		}
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		$tile = $this->level->getTile($this);

		$drop = ItemFactory::get(Item::BANNER, ($tile instanceof TileBanner ? $tile->getBaseColor() : 0));
		if($tile instanceof TileBanner and !($patterns = $tile->getPatterns())->empty()){
			$drop->setNamedTagEntry(clone $patterns);
		}

		return [$drop];
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class WallBanner extends StandingBanner{

	protected $id = self::WALL_BANNER;

	public function getName() : string{
		return "Wall Banner";
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){
			$this->getLevel()->useBreakOn($this);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class RedSandstone extends Sandstone{
	protected $id = self::RED_SANDSTONE;

	public function getName() : string{
		static $names = [
			self::NORMAL => "Red Sandstone",
			self::CHISELED => "Chiseled Red Sandstone",
			self::SMOOTH => "Smooth Red Sandstone"
		];
		return $names[$this->getVariant()] ?? "Unknown";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class RedSandstoneStairs extends SandstoneStairs{

	protected $id = self::RED_SANDSTONE_STAIRS;

	public function getName() : string{
		return "Red " . parent::getName();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class DoubleStoneSlab2 extends DoubleStoneSlab{

	protected $id = self::DOUBLE_STONE_SLAB2;

	public function getSlabId() : int{
		return self::STONE_SLAB2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class StoneSlab2 extends StoneSlab{
	public const TYPE_RED_SANDSTONE = 0;
	public const TYPE_PURPUR = 1;
	public const TYPE_PRISMARINE = 2;
	public const TYPE_DARK_PRISMARINE = 3;
	public const TYPE_PRISMARINE_BRICKS = 4;
	public const TYPE_MOSSY_COBBLESTONE = 5;
	public const TYPE_SMOOTH_SANDSTONE = 6;
	public const TYPE_RED_NETHER_BRICK = 7;

	protected $id = self::STONE_SLAB2;

	public function getDoubleSlabId() : int{
		return self::DOUBLE_STONE_SLAB2;
	}

	public function getName() : string{
		static $names = [
			self::TYPE_RED_SANDSTONE => "Red Sandstone",
			self::TYPE_PURPUR => "Purpur",
			self::TYPE_PRISMARINE => "Prismarine",
			self::TYPE_DARK_PRISMARINE => "Dark Prismarine",
			self::TYPE_PRISMARINE_BRICKS => "Prismarine Bricks",
			self::TYPE_MOSSY_COBBLESTONE => "Mossy Cobblestone",
			self::TYPE_SMOOTH_SANDSTONE => "Smooth Sandstone",
			self::TYPE_RED_NETHER_BRICK => "Red Nether Brick"
		];

		return (($this->meta & 0x08) > 0 ? "Upper " : "") . ($names[$this->getVariant()] ?? "") . " Slab";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;

class GrassPath extends Transparent{

	protected $id = self::GRASS_PATH;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Grass Path";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		return new AxisAlignedBB(
			$this->x,
			$this->y,
			$this->z,
			$this->x + 1,
			$this->y + 1, //TODO: this should be 0.9375, but MCPE currently treats them as a full block (https://bugs.mojang.com/browse/MCPE-12109)
			$this->z + 1
		);
	}

	public function getHardness() : float{
		return 0.6;
	}

	public function onNearbyBlockChange() : void{
		if($this->getSide(Vector3::SIDE_UP)->isSolid()){
			$this->level->setBlock($this, BlockFactory::get(Block::DIRT), true);
		}
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::DIRT)
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\ItemFrame as TileItemFrame;
use pocketmine\tile\Tile;
use function lcg_value;

class ItemFrame extends Flowable{
	protected $id = Block::ITEM_FRAME_BLOCK;

	protected $itemId = Item::ITEM_FRAME;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Item Frame";
	}

	public function onActivate(Item $item, Player $player = null) : bool{
		$tile = $this->level->getTile($this);
		if(!($tile instanceof TileItemFrame)){
			$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this));
			if(!($tile instanceof TileItemFrame)){
				return true;
			}
		}

		if($tile->hasItem()){
			$tile->setItemRotation(($tile->getItemRotation() + 1) % 8);
		}elseif(!$item->isNull()){
			$tile->setItem($item->pop());
		}

		return true;
	}

	public function onNearbyBlockChange() : void{
		$sides = [
			0 => Vector3::SIDE_WEST,
			1 => Vector3::SIDE_EAST,
			2 => Vector3::SIDE_NORTH,
			3 => Vector3::SIDE_SOUTH
		];
		if(isset($sides[$this->meta]) and !$this->getSide($sides[$this->meta])->isSolid()){
			$this->level->useBreakOn($this);
		}
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($face === Vector3::SIDE_DOWN or $face === Vector3::SIDE_UP or !$blockClicked->isSolid()){
			return false;
		}

		$faces = [
			Vector3::SIDE_NORTH => 3,
			Vector3::SIDE_SOUTH => 2,
			Vector3::SIDE_WEST => 1,
			Vector3::SIDE_EAST => 0
		];

		$this->meta = $faces[$face];
		$this->level->setBlock($blockReplace, $this, true, true);

		Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player));

		return true;

	}

	public function getVariantBitmask() : int{
		return 0;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		$drops = parent::getDropsForCompatibleTool($item);

		$tile = $this->level->getTile($this);
		if($tile instanceof TileItemFrame){
			$tileItem = $tile->getItem();
			if(lcg_value() <= $tile->getItemDropChance() and !$tileItem->isNull()){
				$drops[] = $tileItem;
			}
		}

		return $drops;
	}

	public function isAffectedBySilkTouch() : bool{
		return false;
	}

	public function getHardness() : float{
		return 0.25;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class Purpur extends Quartz{

	protected $id = self::PURPUR_BLOCK;

	public function getName() : string{
		static $names = [
			self::NORMAL => "Purpur Block",
			self::CHISELED => "Chiseled Purpur", //wtf?
			self::PILLAR => "Purpur Pillar"
		];

		return $names[$this->getVariant()] ?? "Unknown";
	}

	public function getHardness() : float{
		return 1.5;
	}

	public function getBlastResistance() : float{
		return 30;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class PurpurStairs extends Stair{

	protected $id = self::PURPUR_STAIRS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Purpur Stairs";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getHardness() : float{
		return 1.5;
	}

	public function getBlastResistance() : float{
		return 30;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class EndStoneBricks extends Solid{

	protected $id = self::END_BRICKS;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "End Stone Bricks";
	}

	public function getHardness() : float{
		return 0.8;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;

class EndRod extends Flowable{

	protected $id = Block::END_ROD;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "End Rod";
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($face === Vector3::SIDE_UP or $face === Vector3::SIDE_DOWN){
			$this->meta = $face;
		}else{
			$this->meta = $face ^ 0x01;
		}
		if($blockClicked instanceof EndRod and $blockClicked->getDamage() === $this->meta){
			$this->meta ^= 0x01;
		}

		return $this->level->setBlock($blockReplace, $this, true, true);
	}

	public function isSolid() : bool{
		return true;
	}

	public function getLightLevel() : int{
		return 14;
	}

	protected function recalculateBoundingBox() : ?AxisAlignedBB{
		$m = $this->meta & ~0x01;
		$width = 0.375;

		switch($m){
			case 0x00: //up/down
				return new AxisAlignedBB(
					$this->x + $width,
					$this->y,
					$this->z + $width,
					$this->x + 1 - $width,
					$this->y + 1,
					$this->z + 1 - $width
				);
			case 0x02: //north/south
				return new AxisAlignedBB(
					$this->x,
					$this->y + $width,
					$this->z + $width,
					$this->x + 1,
					$this->y + 1 - $width,
					$this->z + 1 - $width
				);
			case 0x04: //east/west
				return new AxisAlignedBB(
					$this->x + $width,
					$this->y + $width,
					$this->z,
					$this->x + 1 - $width,
					$this->y + 1 - $width,
					$this->z + 1
				);
		}

		return null;
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\entity\Entity;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\TieredTool;

class Magma extends Solid{

	protected $id = Block::MAGMA;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Magma Block";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getLightLevel() : int{
		return 3;
	}

	public function hasEntityCollision() : bool{
		return true;
	}

	public function onEntityCollide(Entity $entity) : void{
		if(!$entity->isSneaking()){
			$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
			$entity->attack($ev);
		}
	}

	public function burnsForever() : bool{
		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class NetherWartBlock extends Solid{

	protected $id = Block::NETHER_WART_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Nether Wart Block";
	}

	public function getHardness() : float{
		return 1;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\PillarRotationHelper;
use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;

class BoneBlock extends Solid{

	protected $id = Block::BONE_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Bone Block";
	}

	public function getHardness() : float{
		return 2;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
		return $this->getLevel()->setBlock($blockReplace, $this, true, true);
	}

	public function getVariantBitmask() : int{
		return 0x03;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;

class GlazedTerracotta extends Solid{

	public function getHardness() : float{
		return 1.4;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
		if($player !== null){
			$faces = [
				0 => 4,
				1 => 3,
				2 => 5,
				3 => 2
			];
			$this->meta = $faces[(~($player->getDirection() - 1)) & 0x03];
		}

		return $this->getLevel()->setBlock($blockReplace, $this, true, true);
	}

	public function getVariantBitmask() : int{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\item\TieredTool;

class Concrete extends Solid{

	protected $id = Block::CONCRETE;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return ColorBlockMetaHelper::getColorFromMeta($this->getVariant()) . " Concrete";
	}

	public function getHardness() : float{
		return 1.8;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\ColorBlockMetaHelper;

class ConcretePowder extends Fallable{

	protected $id = self::CONCRETE_POWDER;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return ColorBlockMetaHelper::getColorFromMeta($this->getVariant()) . " Concrete Powder";
	}

	public function getHardness() : float{
		return 0.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function onNearbyBlockChange() : void{
		if(($block = $this->checkAdjacentWater()) !== null){
			$this->level->setBlock($this, $block);
		}else{
			parent::onNearbyBlockChange();
		}
	}

	public function tickFalling() : ?Block{
		return $this->checkAdjacentWater();
	}

	private function checkAdjacentWater() : ?Block{
		for($i = 1; $i < 6; ++$i){ //Do not check underneath
			if($this->getSide($i) instanceof Water){
				return BlockFactory::get(Block::CONCRETE, $this->meta);
			}
		}

		return null;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\block\utils\ColorBlockMetaHelper;

class StainedGlass extends Glass{

	protected $id = self::STAINED_GLASS;

	public function getName() : string{
		return ColorBlockMetaHelper::getColorFromMeta($this->getVariant()) . " Stained Glass";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class Podzol extends Solid{

	protected $id = self::PODZOL;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getName() : string{
		return "Podzol";
	}

	public function getHardness() : float{
		return 2.5;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use function mt_rand;

class Beetroot extends Crops{

	protected $id = self::BEETROOT_BLOCK;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Beetroot Block";
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		if($this->meta >= 0x07){
			return [
				ItemFactory::get(Item::BEETROOT),
				ItemFactory::get(Item::BEETROOT_SEEDS, 0, mt_rand(0, 3))
			];
		}

		return [
			ItemFactory::get(Item::BEETROOT_SEEDS)
		];
	}

	public function getPickedItem() : Item{
		return ItemFactory::get(Item::BEETROOT_SEEDS);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class Stonecutter extends Solid{

	protected $id = self::STONECUTTER;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Stonecutter";
	}

	public function getHardness() : float{
		return 3.5;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\TieredTool;

class GlowingObsidian extends Solid{

	protected $id = self::GLOWING_OBSIDIAN;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		return "Glowing Obsidian";
	}

	public function getLightLevel() : int{
		return 12;
	}

	public function getHardness() : float{
		return 10;
	}

	public function getBlastResistance() : float{
		return 50;
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_DIAMOND;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\TieredTool;

class NetherReactor extends Solid{
	protected $id = Block::NETHER_REACTOR;

	public function __construct(int $meta = 0){
		$this->meta = $meta;
	}

	public function getName() : string{
		static $prefixes = [
			"",
			"Active ",
			"Used "
		];
		return ($prefixes[$this->meta] ?? "") . "Nether Reactor Core";
	}

	public function getToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getToolHarvestLevel() : int{
		return TieredTool::TIER_WOODEN;
	}

	public function getHardness() : float{
		return 3;
	}

	public function getDropsForCompatibleTool(Item $item) : array{
		return [
			ItemFactory::get(Item::IRON_INGOT, 0, 6),
			ItemFactory::get(Item::DIAMOND, 0, 3)
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class InfoUpdate extends Solid{

	public function getHardness() : float{
		return 1;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

class Reserved6 extends Solid{

	public function getHardness() : float{
		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

use pocketmine\item\Item;

class UnknownBlock extends Transparent{

	public function getHardness() : float{
		return 0;
	}

	public function canBePlaced() : bool{
		return false;
	}

	public function getDrops(Item $item) : array{
		return [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item\enchantment;

use pocketmine\event\entity\EntityDamageEvent;
use function constant;
use function defined;
use function strtoupper;

/**
 * Manages enchantment type data.
 */
class Enchantment{

	public const PROTECTION = 0;
	public const FIRE_PROTECTION = 1;
	public const FEATHER_FALLING = 2;
	public const BLAST_PROTECTION = 3;
	public const PROJECTILE_PROTECTION = 4;
	public const THORNS = 5;
	public const RESPIRATION = 6;
	public const DEPTH_STRIDER = 7;
	public const AQUA_AFFINITY = 8;
	public const SHARPNESS = 9;
	public const SMITE = 10;
	public const BANE_OF_ARTHROPODS = 11;
	public const KNOCKBACK = 12;
	public const FIRE_ASPECT = 13;
	public const LOOTING = 14;
	public const EFFICIENCY = 15;
	public const SILK_TOUCH = 16;
	public const UNBREAKING = 17;
	public const FORTUNE = 18;
	public const POWER = 19;
	public const PUNCH = 20;
	public const FLAME = 21;
	public const INFINITY = 22;
	public const LUCK_OF_THE_SEA = 23;
	public const LURE = 24;
	public const FROST_WALKER = 25;
	public const MENDING = 26;
	public const BINDING = 27;
	public const VANISHING = 28;
	public const IMPALING = 29;
	public const RIPTIDE = 30;
	public const LOYALTY = 31;
	public const CHANNELING = 32;

	public const RARITY_COMMON = 10;
	public const RARITY_UNCOMMON = 5;
	public const RARITY_RARE = 2;
	public const RARITY_MYTHIC = 1;

	public const SLOT_NONE = 0x0;
	public const SLOT_ALL = 0xffff;
	public const SLOT_ARMOR = self::SLOT_HEAD | self::SLOT_TORSO | self::SLOT_LEGS | self::SLOT_FEET;
	public const SLOT_HEAD = 0x1;
	public const SLOT_TORSO = 0x2;
	public const SLOT_LEGS = 0x4;
	public const SLOT_FEET = 0x8;
	public const SLOT_SWORD = 0x10;
	public const SLOT_BOW = 0x20;
	public const SLOT_TOOL = self::SLOT_HOE | self::SLOT_SHEARS | self::SLOT_FLINT_AND_STEEL;
	public const SLOT_HOE = 0x40;
	public const SLOT_SHEARS = 0x80;
	public const SLOT_FLINT_AND_STEEL = 0x100;
	public const SLOT_DIG = self::SLOT_AXE | self::SLOT_PICKAXE | self::SLOT_SHOVEL;
	public const SLOT_AXE = 0x200;
	public const SLOT_PICKAXE = 0x400;
	public const SLOT_SHOVEL = 0x800;
	public const SLOT_FISHING_ROD = 0x1000;
	public const SLOT_CARROT_STICK = 0x2000;
	public const SLOT_ELYTRA = 0x4000;
	public const SLOT_TRIDENT = 0x8000;

	/**
	 * @var \SplFixedArray|Enchantment[]
	 * @phpstan-var \SplFixedArray<Enchantment>
	 */
	protected static $enchantments;

	public static function init() : void{
		self::$enchantments = new \SplFixedArray(256);

		self::registerEnchantment(new ProtectionEnchantment(self::PROTECTION, "%enchantment.protect.all", self::RARITY_COMMON, self::SLOT_ARMOR, self::SLOT_NONE, 4, 0.75, null));
		self::registerEnchantment(new ProtectionEnchantment(self::FIRE_PROTECTION, "%enchantment.protect.fire", self::RARITY_UNCOMMON, self::SLOT_ARMOR, self::SLOT_NONE, 4, 1.25, [
			EntityDamageEvent::CAUSE_FIRE,
			EntityDamageEvent::CAUSE_FIRE_TICK,
			EntityDamageEvent::CAUSE_LAVA
			//TODO: check fireballs
		]));
		self::registerEnchantment(new ProtectionEnchantment(self::FEATHER_FALLING, "%enchantment.protect.fall", self::RARITY_UNCOMMON, self::SLOT_FEET, self::SLOT_NONE, 4, 2.5, [
			EntityDamageEvent::CAUSE_FALL
		]));
		self::registerEnchantment(new ProtectionEnchantment(self::BLAST_PROTECTION, "%enchantment.protect.explosion", self::RARITY_RARE, self::SLOT_ARMOR, self::SLOT_NONE, 4, 1.5, [
			EntityDamageEvent::CAUSE_BLOCK_EXPLOSION,
			EntityDamageEvent::CAUSE_ENTITY_EXPLOSION
		]));
		self::registerEnchantment(new ProtectionEnchantment(self::PROJECTILE_PROTECTION, "%enchantment.protect.projectile", self::RARITY_UNCOMMON, self::SLOT_ARMOR, self::SLOT_NONE, 4, 1.5, [
			EntityDamageEvent::CAUSE_PROJECTILE
		]));
		self::registerEnchantment(new Enchantment(self::THORNS, "%enchantment.thorns", self::RARITY_MYTHIC, self::SLOT_TORSO, self::SLOT_HEAD | self::SLOT_LEGS | self::SLOT_FEET, 3));
		self::registerEnchantment(new Enchantment(self::RESPIRATION, "%enchantment.oxygen", self::RARITY_RARE, self::SLOT_HEAD, self::SLOT_NONE, 3));

		self::registerEnchantment(new SharpnessEnchantment(self::SHARPNESS, "%enchantment.damage.all", self::RARITY_COMMON, self::SLOT_SWORD, self::SLOT_AXE, 5));
		//TODO: smite, bane of arthropods (these don't make sense now because their applicable mobs don't exist yet)

		self::registerEnchantment(new KnockbackEnchantment(self::KNOCKBACK, "%enchantment.knockback", self::RARITY_UNCOMMON, self::SLOT_SWORD, self::SLOT_NONE, 2));
		self::registerEnchantment(new FireAspectEnchantment(self::FIRE_ASPECT, "%enchantment.fire", self::RARITY_RARE, self::SLOT_SWORD, self::SLOT_NONE, 2));

		self::registerEnchantment(new Enchantment(self::EFFICIENCY, "%enchantment.digging", self::RARITY_COMMON, self::SLOT_DIG, self::SLOT_SHEARS, 5));
		self::registerEnchantment(new Enchantment(self::SILK_TOUCH, "%enchantment.untouching", self::RARITY_MYTHIC, self::SLOT_DIG, self::SLOT_SHEARS, 1));
		self::registerEnchantment(new Enchantment(self::UNBREAKING, "%enchantment.durability", self::RARITY_UNCOMMON, self::SLOT_DIG | self::SLOT_ARMOR | self::SLOT_FISHING_ROD | self::SLOT_BOW, self::SLOT_TOOL | self::SLOT_CARROT_STICK | self::SLOT_ELYTRA, 3));

		self::registerEnchantment(new Enchantment(self::POWER, "%enchantment.arrowDamage", self::RARITY_COMMON, self::SLOT_BOW, self::SLOT_NONE, 5));
		self::registerEnchantment(new Enchantment(self::PUNCH, "%enchantment.arrowKnockback", self::RARITY_RARE, self::SLOT_BOW, self::SLOT_NONE, 2));
		self::registerEnchantment(new Enchantment(self::FLAME, "%enchantment.arrowFire", self::RARITY_RARE, self::SLOT_BOW, self::SLOT_NONE, 1));
		self::registerEnchantment(new Enchantment(self::INFINITY, "%enchantment.arrowInfinite", self::RARITY_MYTHIC, self::SLOT_BOW, self::SLOT_NONE, 1));

		self::registerEnchantment(new Enchantment(self::MENDING, "%enchantment.mending", self::RARITY_RARE, self::SLOT_NONE, self::SLOT_ALL, 1));

		self::registerEnchantment(new Enchantment(self::VANISHING, "%enchantment.curse.vanishing", self::RARITY_MYTHIC, self::SLOT_NONE, self::SLOT_ALL, 1));
	}

	/**
	 * Registers an enchantment type.
	 */
	public static function registerEnchantment(Enchantment $enchantment) : void{
		self::$enchantments[$enchantment->getId()] = clone $enchantment;
	}

	public static function getEnchantment(int $id) : ?Enchantment{
		if($id < 0 or $id >= self::$enchantments->getSize()){
			return null;
		}
		return self::$enchantments[$id] ?? null;
	}

	public static function getEnchantmentByName(string $name) : ?Enchantment{
		$const = Enchantment::class . "::" . strtoupper($name);
		if(defined($const)){
			return self::getEnchantment(constant($const));
		}
		return null;
	}

	/** @var int */
	private $id;
	/** @var string */
	private $name;
	/** @var int */
	private $rarity;
	/** @var int */
	private $primaryItemFlags;
	/** @var int */
	private $secondaryItemFlags;
	/** @var int */
	private $maxLevel;

	public function __construct(int $id, string $name, int $rarity, int $primaryItemFlags, int $secondaryItemFlags, int $maxLevel){
		$this->id = $id;
		$this->name = $name;
		$this->rarity = $rarity;
		$this->primaryItemFlags = $primaryItemFlags;
		$this->secondaryItemFlags = $secondaryItemFlags;
		$this->maxLevel = $maxLevel;
	}

	/**
	 * Returns the ID of this enchantment as per Minecraft PE
	 */
	public function getId() : int{
		return $this->id;
	}

	/**
	 * Returns a translation key for this enchantment's name.
	 */
	public function getName() : string{
		return $this->name;
	}

	/**
	 * Returns an int constant indicating how rare this enchantment type is.
	 */
	public function getRarity() : int{
		return $this->rarity;
	}

	/**
	 * Returns a bitset indicating what item types can have this item applied from an enchanting table.
	 */
	public function getPrimaryItemFlags() : int{
		return $this->primaryItemFlags;
	}

	/**
	 * Returns a bitset indicating what item types cannot have this item applied from an enchanting table, but can from
	 * an anvil.
	 */
	public function getSecondaryItemFlags() : int{
		return $this->secondaryItemFlags;
	}

	/**
	 * Returns whether this enchantment can apply to the item type from an enchanting table.
	 */
	public function hasPrimaryItemType(int $flag) : bool{
		return ($this->primaryItemFlags & $flag) !== 0;
	}

	/**
	 * Returns whether this enchantment can apply to the item type from an anvil, if it is not a primary item.
	 */
	public function hasSecondaryItemType(int $flag) : bool{
		return ($this->secondaryItemFlags & $flag) !== 0;
	}

	/**
	 * Returns the maximum level of this enchantment that can be found on an enchantment table.
	 */
	public function getMaxLevel() : int{
		return $this->maxLevel;
	}

	//TODO: methods for min/max XP cost bounds based on enchantment level (not needed yet - enchanting is client-side)
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item\enchantment;

use pocketmine\event\entity\EntityDamageEvent;
use function array_flip;
use function floor;

class ProtectionEnchantment extends Enchantment{
	/** @var float */
	protected $typeModifier;
	/** @var int[]|null */
	protected $applicableDamageTypes = null;

	/**
	 * ProtectionEnchantment constructor.
	 *
	 * @param int[]|null $applicableDamageTypes EntityDamageEvent::CAUSE_* constants which this enchantment type applies to, or null if it applies to all types of damage.
	 */
	public function __construct(int $id, string $name, int $rarity, int $primaryItemFlags, int $secondaryItemFlags, int $maxLevel, float $typeModifier, ?array $applicableDamageTypes){
		parent::__construct($id, $name, $rarity, $primaryItemFlags, $secondaryItemFlags, $maxLevel);

		$this->typeModifier = $typeModifier;
		if($applicableDamageTypes !== null){
			$this->applicableDamageTypes = array_flip($applicableDamageTypes);
		}
	}

	/**
	 * Returns the multiplier by which this enchantment type's EPF increases with each enchantment level.
	 */
	public function getTypeModifier() : float{
		return $this->typeModifier;
	}

	/**
	 * Returns the base EPF this enchantment type offers for the given enchantment level.
	 */
	public function getProtectionFactor(int $level) : int{
		return (int) floor((6 + $level ** 2) * $this->typeModifier / 3);
	}

	/**
	 * Returns whether this enchantment type offers protection from the specified damage source's cause.
	 */
	public function isApplicable(EntityDamageEvent $event) : bool{
		return $this->applicableDamageTypes === null or isset($this->applicableDamageTypes[$event->getCause()]);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\entity;

use pocketmine\entity\Entity;
use pocketmine\event\Cancellable;
use function array_sum;

/**
 * Called when an entity takes damage.
 */
class EntityDamageEvent extends EntityEvent implements Cancellable{
	public const MODIFIER_ARMOR = 1;
	public const MODIFIER_STRENGTH = 2;
	public const MODIFIER_WEAKNESS = 3;
	public const MODIFIER_RESISTANCE = 4;
	public const MODIFIER_ABSORPTION = 5;
	public const MODIFIER_ARMOR_ENCHANTMENTS = 6;
	public const MODIFIER_CRITICAL = 7;
	public const MODIFIER_TOTEM = 8;
	public const MODIFIER_WEAPON_ENCHANTMENTS = 9;

	public const CAUSE_CONTACT = 0;
	public const CAUSE_ENTITY_ATTACK = 1;
	public const CAUSE_PROJECTILE = 2;
	public const CAUSE_SUFFOCATION = 3;
	public const CAUSE_FALL = 4;
	public const CAUSE_FIRE = 5;
	public const CAUSE_FIRE_TICK = 6;
	public const CAUSE_LAVA = 7;
	public const CAUSE_DROWNING = 8;
	public const CAUSE_BLOCK_EXPLOSION = 9;
	public const CAUSE_ENTITY_EXPLOSION = 10;
	public const CAUSE_VOID = 11;
	public const CAUSE_SUICIDE = 12;
	public const CAUSE_MAGIC = 13;
	public const CAUSE_CUSTOM = 14;
	public const CAUSE_STARVATION = 15;

	/** @var int */
	private $cause;
	/** @var float */
	private $baseDamage;
	/** @var float */
	private $originalBase;

	/** @var float[] */
	private $modifiers;
	/** @var float[] */
	private $originals;

	/** @var int */
	private $attackCooldown = 10;

	/**
	 * @param float[] $modifiers
	 */
	public function __construct(Entity $entity, int $cause, float $damage, array $modifiers = []){
		$this->entity = $entity;
		$this->cause = $cause;
		$this->baseDamage = $this->originalBase = $damage;

		$this->modifiers = $modifiers;
		$this->originals = $this->modifiers;
	}

	public function getCause() : int{
		return $this->cause;
	}

	/**
	 * Returns the base amount of damage applied, before modifiers.
	 */
	public function getBaseDamage() : float{
		return $this->baseDamage;
	}

	/**
	 * Sets the base amount of damage applied, optionally recalculating modifiers.
	 *
	 * TODO: add ability to recalculate modifiers when this is set
	 */
	public function setBaseDamage(float $damage) : void{
		$this->baseDamage = $damage;
	}

	/**
	 * Returns the original base amount of damage applied, before alterations by plugins.
	 */
	public function getOriginalBaseDamage() : float{
		return $this->originalBase;
	}

	/**
	 * @return float[]
	 */
	public function getOriginalModifiers() : array{
		return $this->originals;
	}

	public function getOriginalModifier(int $type) : float{
		return $this->originals[$type] ?? 0.0;
	}

	/**
	 * @return float[]
	 */
	public function getModifiers() : array{
		return $this->modifiers;
	}

	public function getModifier(int $type) : float{
		return $this->modifiers[$type] ?? 0.0;
	}

	public function setModifier(float $damage, int $type) : void{
		$this->modifiers[$type] = $damage;
	}

	public function isApplicable(int $type) : bool{
		return isset($this->modifiers[$type]);
	}

	public function getFinalDamage() : float{
		return $this->baseDamage + array_sum($this->modifiers);
	}

	/**
	 * Returns whether an entity can use armour points to reduce this type of damage.
	 */
	public function canBeReducedByArmor() : bool{
		switch($this->cause){
			case self::CAUSE_FIRE_TICK:
			case self::CAUSE_SUFFOCATION:
			case self::CAUSE_DROWNING:
			case self::CAUSE_STARVATION:
			case self::CAUSE_FALL:
			case self::CAUSE_VOID:
			case self::CAUSE_MAGIC:
			case self::CAUSE_SUICIDE:
				return false;

		}

		return true;
	}

	/**
	 * Returns the cooldown in ticks before the target entity can be attacked again.
	 */
	public function getAttackCooldown() : int{
		return $this->attackCooldown;
	}

	/**
	 * Sets the cooldown in ticks before the target entity can be attacked again.
	 *
	 * NOTE: This value is not used in non-Living entities
	 */
	public function setAttackCooldown(int $attackCooldown) : void{
		$this->attackCooldown = $attackCooldown;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Entity related Events, like spawn, inventory, attack...
 */
namespace pocketmine\event\entity;

use pocketmine\entity\Entity;
use pocketmine\event\Event;

abstract class EntityEvent extends Event{
	/** @var Entity */
	protected $entity;

	/**
	 * @return Entity
	 */
	public function getEntity(){
		return $this->entity;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Event related classes
 */
namespace pocketmine\event;

use function assert;
use function get_class;

abstract class Event{
	private const MAX_EVENT_CALL_DEPTH = 50;
	/** @var int */
	private static $eventCallDepth = 1;

	/** @var string|null */
	protected $eventName = null;
	/** @var bool */
	private $isCancelled = false;

	final public function getEventName() : string{
		return $this->eventName ?? get_class($this);
	}

	/**
	 * @throws \BadMethodCallException
	 */
	public function isCancelled() : bool{
		if(!($this instanceof Cancellable)){
			throw new \BadMethodCallException(get_class($this) . " is not Cancellable");
		}

		return $this->isCancelled;
	}

	/**
	 * @throws \BadMethodCallException
	 */
	public function setCancelled(bool $value = true) : void{
		if(!($this instanceof Cancellable)){
			throw new \BadMethodCallException(get_class($this) . " is not Cancellable");
		}

		$this->isCancelled = $value;
	}

	/**
	 * Calls event handlers registered for this event.
	 *
	 * @throws \RuntimeException if event call recursion reaches the max depth limit
	 */
	public function call() : void{
		if(self::$eventCallDepth >= self::MAX_EVENT_CALL_DEPTH){
			//this exception will be caught by the parent event call if all else fails
			throw new \RuntimeException("Recursive event call detected (reached max depth of " . self::MAX_EVENT_CALL_DEPTH . " calls)");
		}

		$handlerList = HandlerList::getHandlerListFor(get_class($this));
		assert($handlerList !== null, "Called event should have a valid HandlerList");

		++self::$eventCallDepth;
		try{
			foreach(EventPriority::ALL as $priority){
				$currentList = $handlerList;
				while($currentList !== null){
					foreach($currentList->getListenersByPriority($priority) as $registration){
						$registration->callEvent($this);
					}

					$currentList = $currentList->getParent();
				}
			}
		}finally{
			--self::$eventCallDepth;
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event;

/**
 * Events that can be cancelled must use the interface Cancellable
 */
interface Cancellable{
	public function isCancelled() : bool;

	/**
	 * @return void
	 */
	public function setCancelled(bool $value = true);
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item\enchantment;

use pocketmine\entity\Entity;

class SharpnessEnchantment extends MeleeWeaponEnchantment{

	public function isApplicableTo(Entity $victim) : bool{
		return true;
	}

	public function getDamageBonus(int $enchantmentLevel) : float{
		return 0.5 * ($enchantmentLevel + 1);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item\enchantment;

use pocketmine\entity\Entity;

/**
 * Classes extending this class can be applied to weapons and activate when used by a mob to attack another mob in melee
 * combat.
 */
abstract class MeleeWeaponEnchantment extends Enchantment{

	/**
	 * Returns whether this melee enchantment has an effect on the target entity. For example, Smite only applies to
	 * undead mobs.
	 */
	abstract public function isApplicableTo(Entity $victim) : bool;

	/**
	 * Returns the amount of additional damage caused by this enchantment to applicable targets.
	 */
	abstract public function getDamageBonus(int $enchantmentLevel) : float;

	/**
	 * Called after damaging the entity to apply any post damage effects to the target.
	 */
	public function onPostAttack(Entity $attacker, Entity $victim, int $enchantmentLevel) : void{

	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item\enchantment;

use pocketmine\entity\Entity;
use pocketmine\entity\Living;

class KnockbackEnchantment extends MeleeWeaponEnchantment{

	public function isApplicableTo(Entity $victim) : bool{
		return $victim instanceof Living;
	}

	public function getDamageBonus(int $enchantmentLevel) : float{
		return 0;
	}

	public function onPostAttack(Entity $attacker, Entity $victim, int $enchantmentLevel) : void{
		if($victim instanceof Living){
			$victim->knockBack($attacker, 0, $victim->x - $attacker->x, $victim->z - $attacker->z, $enchantmentLevel * 0.5);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item\enchantment;

use pocketmine\entity\Entity;

class FireAspectEnchantment extends MeleeWeaponEnchantment{

	public function isApplicableTo(Entity $victim) : bool{
		return true;
	}

	public function getDamageBonus(int $enchantmentLevel) : float{
		return 0;
	}

	public function onPostAttack(Entity $attacker, Entity $victim, int $enchantmentLevel) : void{
		$victim->setOnFire($enchantmentLevel * 4);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\nbt\tag\CompoundTag;
use function constant;
use function defined;
use function explode;
use function get_class;
use function gettype;
use function is_numeric;
use function is_object;
use function is_string;
use function str_replace;
use function strtoupper;
use function trim;

/**
 * Manages Item instance creation and registration
 */
class ItemFactory{

	/**
	 * @var \SplFixedArray|Item[]
	 * @phpstan-var \SplFixedArray<Item>
	 */
	private static $list;

	/**
	 * @return void
	 */
	public static function init(){
		self::$list = new \SplFixedArray(65536);

		self::registerItem(new Shovel(Item::IRON_SHOVEL, 0, "Iron Shovel", TieredTool::TIER_IRON));
		self::registerItem(new Pickaxe(Item::IRON_PICKAXE, 0, "Iron Pickaxe", TieredTool::TIER_IRON));
		self::registerItem(new Axe(Item::IRON_AXE, 0, "Iron Axe", TieredTool::TIER_IRON));
		self::registerItem(new FlintSteel());
		self::registerItem(new Apple());
		self::registerItem(new Bow());
		self::registerItem(new Arrow());
		self::registerItem(new Coal());
		self::registerItem(new Item(Item::DIAMOND, 0, "Diamond"));
		self::registerItem(new Item(Item::IRON_INGOT, 0, "Iron Ingot"));
		self::registerItem(new Item(Item::GOLD_INGOT, 0, "Gold Ingot"));
		self::registerItem(new Sword(Item::IRON_SWORD, 0, "Iron Sword", TieredTool::TIER_IRON));
		self::registerItem(new Sword(Item::WOODEN_SWORD, 0, "Wooden Sword", TieredTool::TIER_WOODEN));
		self::registerItem(new Shovel(Item::WOODEN_SHOVEL, 0, "Wooden Shovel", TieredTool::TIER_WOODEN));
		self::registerItem(new Pickaxe(Item::WOODEN_PICKAXE, 0, "Wooden Pickaxe", TieredTool::TIER_WOODEN));
		self::registerItem(new Axe(Item::WOODEN_AXE, 0, "Wooden Axe", TieredTool::TIER_WOODEN));
		self::registerItem(new Sword(Item::STONE_SWORD, 0, "Stone Sword", TieredTool::TIER_STONE));
		self::registerItem(new Shovel(Item::STONE_SHOVEL, 0, "Stone Shovel", TieredTool::TIER_STONE));
		self::registerItem(new Pickaxe(Item::STONE_PICKAXE, 0, "Stone Pickaxe", TieredTool::TIER_STONE));
		self::registerItem(new Axe(Item::STONE_AXE, 0, "Stone Axe", TieredTool::TIER_STONE));
		self::registerItem(new Sword(Item::DIAMOND_SWORD, 0, "Diamond Sword", TieredTool::TIER_DIAMOND));
		self::registerItem(new Shovel(Item::DIAMOND_SHOVEL, 0, "Diamond Shovel", TieredTool::TIER_DIAMOND));
		self::registerItem(new Pickaxe(Item::DIAMOND_PICKAXE, 0, "Diamond Pickaxe", TieredTool::TIER_DIAMOND));
		self::registerItem(new Axe(Item::DIAMOND_AXE, 0, "Diamond Axe", TieredTool::TIER_DIAMOND));
		self::registerItem(new Stick());
		self::registerItem(new Bowl());
		self::registerItem(new MushroomStew());
		self::registerItem(new Sword(Item::GOLDEN_SWORD, 0, "Gold Sword", TieredTool::TIER_GOLD));
		self::registerItem(new Shovel(Item::GOLDEN_SHOVEL, 0, "Gold Shovel", TieredTool::TIER_GOLD));
		self::registerItem(new Pickaxe(Item::GOLDEN_PICKAXE, 0, "Gold Pickaxe", TieredTool::TIER_GOLD));
		self::registerItem(new Axe(Item::GOLDEN_AXE, 0, "Gold Axe", TieredTool::TIER_GOLD));
		self::registerItem(new StringItem());
		self::registerItem(new Item(Item::FEATHER, 0, "Feather"));
		self::registerItem(new Item(Item::GUNPOWDER, 0, "Gunpowder"));
		self::registerItem(new Hoe(Item::WOODEN_HOE, 0, "Wooden Hoe", TieredTool::TIER_WOODEN));
		self::registerItem(new Hoe(Item::STONE_HOE, 0, "Stone Hoe", TieredTool::TIER_STONE));
		self::registerItem(new Hoe(Item::IRON_HOE, 0, "Iron Hoe", TieredTool::TIER_IRON));
		self::registerItem(new Hoe(Item::DIAMOND_HOE, 0, "Diamond Hoe", TieredTool::TIER_DIAMOND));
		self::registerItem(new Hoe(Item::GOLDEN_HOE, 0, "Golden Hoe", TieredTool::TIER_GOLD));
		self::registerItem(new WheatSeeds());
		self::registerItem(new Item(Item::WHEAT, 0, "Wheat"));
		self::registerItem(new Bread());
		self::registerItem(new LeatherCap());
		self::registerItem(new LeatherTunic());
		self::registerItem(new LeatherPants());
		self::registerItem(new LeatherBoots());
		self::registerItem(new ChainHelmet());
		self::registerItem(new ChainChestplate());
		self::registerItem(new ChainLeggings());
		self::registerItem(new ChainBoots());
		self::registerItem(new IronHelmet());
		self::registerItem(new IronChestplate());
		self::registerItem(new IronLeggings());
		self::registerItem(new IronBoots());
		self::registerItem(new DiamondHelmet());
		self::registerItem(new DiamondChestplate());
		self::registerItem(new DiamondLeggings());
		self::registerItem(new DiamondBoots());
		self::registerItem(new GoldHelmet());
		self::registerItem(new GoldChestplate());
		self::registerItem(new GoldLeggings());
		self::registerItem(new GoldBoots());
		self::registerItem(new Item(Item::FLINT, 0, "Flint"));
		self::registerItem(new RawPorkchop());
		self::registerItem(new CookedPorkchop());
		self::registerItem(new PaintingItem());
		self::registerItem(new GoldenApple());
		self::registerItem(new Sign());
		self::registerItem(new ItemBlock(Block::OAK_DOOR_BLOCK, 0, Item::OAK_DOOR));
		self::registerItem(new Bucket());

		self::registerItem(new Minecart());
		//TODO: SADDLE
		self::registerItem(new ItemBlock(Block::IRON_DOOR_BLOCK, 0, Item::IRON_DOOR));
		self::registerItem(new Redstone());
		self::registerItem(new Snowball());
		self::registerItem(new Boat());
		self::registerItem(new Item(Item::LEATHER, 0, "Leather"));
		//TODO: KELP
		self::registerItem(new Item(Item::BRICK, 0, "Brick"));
		self::registerItem(new Item(Item::CLAY_BALL, 0, "Clay"));
		self::registerItem(new ItemBlock(Block::SUGARCANE_BLOCK, 0, Item::SUGARCANE));
		self::registerItem(new Item(Item::PAPER, 0, "Paper"));
		self::registerItem(new Book());
		self::registerItem(new Item(Item::SLIME_BALL, 0, "Slimeball"));
		//TODO: CHEST_MINECART

		self::registerItem(new Egg());
		self::registerItem(new Compass());
		self::registerItem(new FishingRod());
		self::registerItem(new Clock());
		self::registerItem(new Item(Item::GLOWSTONE_DUST, 0, "Glowstone Dust"));
		self::registerItem(new RawFish());
		self::registerItem(new CookedFish());
		self::registerItem(new Dye());
		self::registerItem(new Item(Item::BONE, 0, "Bone"));
		self::registerItem(new Item(Item::SUGAR, 0, "Sugar"));
		self::registerItem(new ItemBlock(Block::CAKE_BLOCK, 0, Item::CAKE));
		self::registerItem(new Bed());
		self::registerItem(new ItemBlock(Block::REPEATER_BLOCK, 0, Item::REPEATER));
		self::registerItem(new Cookie());
		//TODO: FILLED_MAP
		self::registerItem(new Shears());
		self::registerItem(new Melon());
		self::registerItem(new PumpkinSeeds());
		self::registerItem(new MelonSeeds());
		self::registerItem(new RawBeef());
		self::registerItem(new Steak());
		self::registerItem(new RawChicken());
		self::registerItem(new CookedChicken());
		self::registerItem(new RottenFlesh());
		self::registerItem(new EnderPearl());
		self::registerItem(new BlazeRod());
		self::registerItem(new Item(Item::GHAST_TEAR, 0, "Ghast Tear"));
		self::registerItem(new Item(Item::GOLD_NUGGET, 0, "Gold Nugget"));
		self::registerItem(new ItemBlock(Block::NETHER_WART_PLANT, 0, Item::NETHER_WART));
		self::registerItem(new Potion());
		self::registerItem(new GlassBottle());
		self::registerItem(new SpiderEye());
		self::registerItem(new Item(Item::FERMENTED_SPIDER_EYE, 0, "Fermented Spider Eye"));
		self::registerItem(new Item(Item::BLAZE_POWDER, 0, "Blaze Powder"));
		self::registerItem(new Item(Item::MAGMA_CREAM, 0, "Magma Cream"));
		self::registerItem(new ItemBlock(Block::BREWING_STAND_BLOCK, 0, Item::BREWING_STAND));
		self::registerItem(new ItemBlock(Block::CAULDRON_BLOCK, 0, Item::CAULDRON));
		//TODO: ENDER_EYE
		self::registerItem(new Item(Item::GLISTERING_MELON, 0, "Glistering Melon"));
		self::registerItem(new SpawnEgg());
		self::registerItem(new ExperienceBottle());
		//TODO: FIREBALL
		self::registerItem(new WritableBook());
		self::registerItem(new WrittenBook());
		self::registerItem(new Item(Item::EMERALD, 0, "Emerald"));
		self::registerItem(new ItemBlock(Block::ITEM_FRAME_BLOCK, 0, Item::ITEM_FRAME));
		self::registerItem(new ItemBlock(Block::FLOWER_POT_BLOCK, 0, Item::FLOWER_POT));
		self::registerItem(new Carrot());
		self::registerItem(new Potato());
		self::registerItem(new BakedPotato());
		self::registerItem(new PoisonousPotato());
		//TODO: EMPTYMAP
		self::registerItem(new GoldenCarrot());
		self::registerItem(new ItemBlock(Block::SKULL_BLOCK, 0, Item::SKULL));
		//TODO: CARROTONASTICK
		self::registerItem(new Item(Item::NETHER_STAR, 0, "Nether Star"));
		self::registerItem(new PumpkinPie());
		//TODO: FIREWORKS
		//TODO: FIREWORKSCHARGE
		//TODO: ENCHANTED_BOOK
		self::registerItem(new ItemBlock(Block::COMPARATOR_BLOCK, 0, Item::COMPARATOR));
		self::registerItem(new Item(Item::NETHER_BRICK, 0, "Nether Brick"));
		self::registerItem(new Item(Item::NETHER_QUARTZ, 0, "Nether Quartz"));
		//TODO: MINECART_WITH_TNT
		//TODO: HOPPER_MINECART
		self::registerItem(new Item(Item::PRISMARINE_SHARD, 0, "Prismarine Shard"));
		self::registerItem(new ItemBlock(Block::HOPPER_BLOCK, 0, Item::HOPPER));
		self::registerItem(new RawRabbit());
		self::registerItem(new CookedRabbit());
		self::registerItem(new RabbitStew());
		self::registerItem(new Item(Item::RABBIT_FOOT, 0, "Rabbit's Foot"));
		self::registerItem(new Item(Item::RABBIT_HIDE, 0, "Rabbit Hide"));
		//TODO: HORSEARMORLEATHER
		//TODO: HORSEARMORIRON
		//TODO: GOLD_HORSE_ARMOR
		//TODO: DIAMOND_HORSE_ARMOR
		//TODO: LEAD
		//TODO: NAMETAG
		self::registerItem(new Item(Item::PRISMARINE_CRYSTALS, 0, "Prismarine Crystals"));
		self::registerItem(new RawMutton());
		self::registerItem(new CookedMutton());
		//TODO: ARMOR_STAND
		//TODO: END_CRYSTAL
		self::registerItem(new ItemBlock(Block::SPRUCE_DOOR_BLOCK, 0, Item::SPRUCE_DOOR));
		self::registerItem(new ItemBlock(Block::BIRCH_DOOR_BLOCK, 0, Item::BIRCH_DOOR));
		self::registerItem(new ItemBlock(Block::JUNGLE_DOOR_BLOCK, 0, Item::JUNGLE_DOOR));
		self::registerItem(new ItemBlock(Block::ACACIA_DOOR_BLOCK, 0, Item::ACACIA_DOOR));
		self::registerItem(new ItemBlock(Block::DARK_OAK_DOOR_BLOCK, 0, Item::DARK_OAK_DOOR));
		self::registerItem(new ChorusFruit());
		self::registerItem(new Item(Item::CHORUS_FRUIT_POPPED, 0, "Popped Chorus Fruit"));

		self::registerItem(new Item(Item::DRAGON_BREATH, 0, "Dragon's Breath"));
		self::registerItem(new SplashPotion());

		//TODO: LINGERING_POTION
		//TODO: SPARKLER
		//TODO: COMMAND_BLOCK_MINECART
		//TODO: ELYTRA
		self::registerItem(new Item(Item::SHULKER_SHELL, 0, "Shulker Shell"));
		self::registerItem(new Banner());
		//TODO: MEDICINE
		//TODO: BALLOON
		//TODO: RAPID_FERTILIZER
		self::registerItem(new Totem());
		self::registerItem(new Item(Item::BLEACH, 0, "Bleach")); //EDU
		self::registerItem(new Item(Item::IRON_NUGGET, 0, "Iron Nugget"));
		//TODO: ICE_BOMB

		//TODO: TRIDENT

		self::registerItem(new Beetroot());
		self::registerItem(new BeetrootSeeds());
		self::registerItem(new BeetrootSoup());
		self::registerItem(new RawSalmon());
		self::registerItem(new Clownfish());
		self::registerItem(new Pufferfish());
		self::registerItem(new CookedSalmon());
		self::registerItem(new DriedKelp());
		self::registerItem(new Item(Item::NAUTILUS_SHELL, 0, "Nautilus Shell"));
		self::registerItem(new GoldenAppleEnchanted());
		self::registerItem(new Item(Item::HEART_OF_THE_SEA, 0, "Heart of the Sea"));
		self::registerItem(new Item(Item::TURTLE_SHELL_PIECE, 0, "Scute"));
		//TODO: TURTLE_HELMET

		//TODO: COMPOUND
		//TODO: RECORD_13
		//TODO: RECORD_CAT
		//TODO: RECORD_BLOCKS
		//TODO: RECORD_CHIRP
		//TODO: RECORD_FAR
		//TODO: RECORD_MALL
		//TODO: RECORD_MELLOHI
		//TODO: RECORD_STAL
		//TODO: RECORD_STRAD
		//TODO: RECORD_WARD
		//TODO: RECORD_11
		//TODO: RECORD_WAIT
	}

	/**
	 * Registers an item type into the index. Plugins may use this method to register new item types or override existing
	 * ones.
	 *
	 * NOTE: If you are registering a new item type, you will need to add it to the creative inventory yourself - it
	 * will not automatically appear there.
	 *
	 * @return void
	 * @throws \RuntimeException if something attempted to override an already-registered item without specifying the
	 * $override parameter.
	 */
	public static function registerItem(Item $item, bool $override = false){
		$id = $item->getId();
		if(!$override and self::isRegistered($id)){
			throw new \RuntimeException("Trying to overwrite an already registered item");
		}

		self::$list[self::getListOffset($id)] = clone $item;
	}

	/**
	 * Returns an instance of the Item with the specified id, meta, count and NBT.
	 *
	 * @param CompoundTag|string|null $tags
	 *
	 * @throws \TypeError
	 */
	public static function get(int $id, int $meta = 0, int $count = 1, $tags = null) : Item{
		if(!is_string($tags) and !($tags instanceof CompoundTag) and $tags !== null){
			throw new \TypeError("`tags` argument must be a string or CompoundTag instance, " . (is_object($tags) ? "instance of " . get_class($tags) : gettype($tags)) . " given");
		}

		try{
			/** @var Item|null $listed */
			$listed = self::$list[self::getListOffset($id)];
			if($listed !== null){
				$item = clone $listed;
			}elseif($id >= 0 and $id < 256){ //intentionally excludes negatives because extended blocks aren't supported yet
				/* Blocks must have a damage value 0-15, but items can have damage value -1 to indicate that they are
				 * crafting ingredients with any-damage. */
				$item = new ItemBlock($id, $meta);
			}else{
				$item = new Item($id, $meta);
			}
		}catch(\RuntimeException $e){
			throw new \InvalidArgumentException("Item ID $id is invalid or out of bounds");
		}

		$item->setDamage($meta);
		$item->setCount($count);
		$item->setCompoundTag($tags);
		return $item;
	}

	/**
	 * Tries to parse the specified string into Item ID/meta identifiers, and returns Item instances it created.
	 *
	 * Example accepted formats:
	 * - `diamond_pickaxe:5`
	 * - `minecraft:string`
	 * - `351:4 (lapis lazuli ID:meta)`
	 *
	 * If multiple item instances are to be created, their identifiers must be comma-separated, for example:
	 * `diamond_pickaxe,wooden_shovel:18,iron_ingot`
	 *
	 * @return Item[]|Item
	 *
	 * @throws \InvalidArgumentException if the given string cannot be parsed as an item identifier
	 */
	public static function fromString(string $str, bool $multiple = false){
		if($multiple){
			$blocks = [];
			foreach(explode(",", $str) as $b){
				$blocks[] = self::fromString($b, false);
			}

			return $blocks;
		}else{
			$b = explode(":", str_replace([" ", "minecraft:"], ["_", ""], trim($str)));
			if(!isset($b[1])){
				$meta = 0;
			}elseif(is_numeric($b[1])){
				$meta = (int) $b[1];
			}else{
				throw new \InvalidArgumentException("Unable to parse \"" . $b[1] . "\" from \"" . $str . "\" as a valid meta value");
			}

			if(is_numeric($b[0])){
				$item = self::get((int) $b[0], $meta);
			}elseif(defined(ItemIds::class . "::" . strtoupper($b[0]))){
				$item = self::get(constant(ItemIds::class . "::" . strtoupper($b[0])), $meta);
			}else{
				throw new \InvalidArgumentException("Unable to resolve \"" . $str . "\" to a valid item");
			}

			return $item;
		}
	}

	/**
	 * Returns whether the specified item ID is already registered in the item factory.
	 */
	public static function isRegistered(int $id) : bool{
		if($id < 256){
			return BlockFactory::isRegistered($id);
		}
		return self::$list[self::getListOffset($id)] !== null;
	}

	private static function getListOffset(int $id) : int{
		if($id < -0x8000 or $id > 0x7fff){
			throw new \InvalidArgumentException("ID must be in range " . -0x8000 . " - " . 0x7fff);
		}
		return $id & 0xffff;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockToolType;
use pocketmine\entity\Entity;

class Shovel extends TieredTool{

	public function getBlockToolType() : int{
		return BlockToolType::TYPE_SHOVEL;
	}

	public function getBlockToolHarvestLevel() : int{
		return $this->tier;
	}

	public function getAttackPoints() : int{
		return self::getBaseDamageFromTier($this->tier) - 3;
	}

	public function onDestroyBlock(Block $block) : bool{
		if($block->getHardness() > 0){
			return $this->applyDamage(1);
		}
		return false;
	}

	public function onAttackEntity(Entity $victim) : bool{
		return $this->applyDamage(2);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

abstract class TieredTool extends Tool{
	public const TIER_WOODEN = 1;
	public const TIER_GOLD = 2;
	public const TIER_STONE = 3;
	public const TIER_IRON = 4;
	public const TIER_DIAMOND = 5;

	/** @var int */
	protected $tier;

	public function __construct(int $id, int $meta, string $name, int $tier){
		parent::__construct($id, $meta, $name);
		$this->tier = $tier;
	}

	public function getMaxDurability() : int{
		return self::getDurabilityFromTier($this->tier);
	}

	public function getTier() : int{
		return $this->tier;
	}

	public static function getDurabilityFromTier(int $tier) : int{
		static $levels = [
			self::TIER_GOLD => 33,
			self::TIER_WOODEN => 60,
			self::TIER_STONE => 132,
			self::TIER_IRON => 251,
			self::TIER_DIAMOND => 1562
		];

		if(!isset($levels[$tier])){
			throw new \InvalidArgumentException("Unknown tier '$tier'");
		}

		return $levels[$tier];
	}

	protected static function getBaseDamageFromTier(int $tier) : int{
		static $levels = [
			self::TIER_WOODEN => 5,
			self::TIER_GOLD => 5,
			self::TIER_STONE => 6,
			self::TIER_IRON => 7,
			self::TIER_DIAMOND => 8
		];

		if(!isset($levels[$tier])){
			throw new \InvalidArgumentException("Unknown tier '$tier'");
		}

		return $levels[$tier];
	}

	public static function getBaseMiningEfficiencyFromTier(int $tier) : float{
		static $levels = [
			self::TIER_WOODEN => 2,
			self::TIER_STONE => 4,
			self::TIER_IRON => 6,
			self::TIER_DIAMOND => 8,
			self::TIER_GOLD => 12
		];

		if(!isset($levels[$tier])){
			throw new \InvalidArgumentException("Unknown tier '$tier'");
		}

		return $levels[$tier];
	}

	protected function getBaseMiningEfficiency() : float{
		return self::getBaseMiningEfficiencyFromTier($this->tier);
	}

	public function getFuelTime() : int{
		if($this->tier === self::TIER_WOODEN){
			return 200;
		}

		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\item\enchantment\Enchantment;

abstract class Tool extends Durable{

	public function getMaxStackSize() : int{
		return 1;
	}

	public function getMiningEfficiency(Block $block) : float{
		$efficiency = 1;
		if(($block->getToolType() & $this->getBlockToolType()) !== 0){
			$efficiency = $this->getBaseMiningEfficiency();
			if(($enchantmentLevel = $this->getEnchantmentLevel(Enchantment::EFFICIENCY)) > 0){
				$efficiency += ($enchantmentLevel ** 2 + 1);
			}
		}

		return $efficiency;
	}

	protected function getBaseMiningEfficiency() : float{
		return 1;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\item\enchantment\Enchantment;
use pocketmine\nbt\tag\ByteTag;
use function lcg_value;
use function min;

abstract class Durable extends Item{

	/**
	 * Returns whether this item will take damage when used.
	 */
	public function isUnbreakable() : bool{
		return $this->getNamedTag()->getByte("Unbreakable", 0) !== 0;
	}

	/**
	 * Sets whether the item will take damage when used.
	 *
	 * @return void
	 */
	public function setUnbreakable(bool $value = true){
		$this->setNamedTagEntry(new ByteTag("Unbreakable", $value ? 1 : 0));
	}

	/**
	 * Applies damage to the item.
	 *
	 * @return bool if any damage was applied to the item
	 */
	public function applyDamage(int $amount) : bool{
		if($this->isUnbreakable() or $this->isBroken()){
			return false;
		}

		$amount -= $this->getUnbreakingDamageReduction($amount);

		$this->meta = min($this->meta + $amount, $this->getMaxDurability());
		if($this->isBroken()){
			$this->onBroken();
		}

		return true;
	}

	protected function getUnbreakingDamageReduction(int $amount) : int{
		if(($unbreakingLevel = $this->getEnchantmentLevel(Enchantment::UNBREAKING)) > 0){
			$negated = 0;

			$chance = 1 / ($unbreakingLevel + 1);
			for($i = 0; $i < $amount; ++$i){
				if(lcg_value() > $chance){
					$negated++;
				}
			}

			return $negated;
		}

		return 0;
	}

	/**
	 * Called when the item's damage exceeds its maximum durability.
	 */
	protected function onBroken() : void{
		$this->pop();
	}

	/**
	 * Returns the maximum amount of damage this item can take before it breaks.
	 */
	abstract public function getMaxDurability() : int;

	/**
	 * Returns whether the item is broken.
	 */
	public function isBroken() : bool{
		return $this->meta >= $this->getMaxDurability();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockToolType;
use pocketmine\entity\Entity;

class Pickaxe extends TieredTool{

	public function getBlockToolType() : int{
		return BlockToolType::TYPE_PICKAXE;
	}

	public function getBlockToolHarvestLevel() : int{
		return $this->tier;
	}

	public function getAttackPoints() : int{
		return self::getBaseDamageFromTier($this->tier) - 2;
	}

	public function onDestroyBlock(Block $block) : bool{
		if($block->getHardness() > 0){
			return $this->applyDamage(1);
		}
		return false;
	}

	public function onAttackEntity(Entity $victim) : bool{
		return $this->applyDamage(2);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockToolType;
use pocketmine\entity\Entity;

class Axe extends TieredTool{

	public function getBlockToolType() : int{
		return BlockToolType::TYPE_AXE;
	}

	public function getBlockToolHarvestLevel() : int{
		return $this->tier;
	}

	public function getAttackPoints() : int{
		return self::getBaseDamageFromTier($this->tier) - 1;
	}

	public function onDestroyBlock(Block $block) : bool{
		if($block->getHardness() > 0){
			return $this->applyDamage(1);
		}
		return false;
	}

	public function onAttackEntity(Entity $victim) : bool{
		return $this->applyDamage(2);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\Player;
use function assert;

class FlintSteel extends Tool{
	public function __construct(int $meta = 0){
		parent::__construct(self::FLINT_STEEL, $meta, "Flint and Steel");
	}

	public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{
		if($blockReplace->getId() === self::AIR){
			$level = $player->getLevel();
			assert($level !== null);
			$level->setBlock($blockReplace, BlockFactory::get(Block::FIRE), true);
			$level->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), LevelSoundEventPacket::SOUND_IGNITE);

			$this->applyDamage(1);

			return true;
		}

		return false;
	}

	public function getMaxDurability() : int{
		return 65;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Apple extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::APPLE, $meta, "Apple");
	}

	public function getFoodRestore() : int{
		return 4;
	}

	public function getSaturationRestore() : float{
		return 2.4;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Living;

abstract class Food extends Item implements FoodSource{
	public function requiresHunger() : bool{
		return true;
	}

	/**
	 * @return Item
	 */
	public function getResidue(){
		return ItemFactory::get(Item::AIR, 0, 0);
	}

	public function getAdditionalEffects() : array{
		return [];
	}

	public function onConsume(Living $consumer){

	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Entity;
use pocketmine\entity\projectile\Arrow as ArrowEntity;
use pocketmine\entity\projectile\Projectile;
use pocketmine\event\entity\EntityShootBowEvent;
use pocketmine\event\entity\ProjectileLaunchEvent;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\Player;
use function intdiv;
use function min;

class Bow extends Tool{
	public function __construct(int $meta = 0){
		parent::__construct(self::BOW, $meta, "Bow");
	}

	public function getFuelTime() : int{
		return 200;
	}

	public function getMaxDurability() : int{
		return 385;
	}

	public function onReleaseUsing(Player $player) : bool{
		if($player->isSurvival() and !$player->getInventory()->contains(ItemFactory::get(Item::ARROW, 0, 1))){
			$player->getInventory()->sendContents($player);
			return false;
		}

		$nbt = Entity::createBaseNBT(
			$player->add(0, $player->getEyeHeight(), 0),
			$player->getDirectionVector(),
			($player->yaw > 180 ? 360 : 0) - $player->yaw,
			-$player->pitch
		);
		$nbt->setShort("Fire", $player->isOnFire() ? 45 * 60 : 0);

		$diff = $player->getItemUseDuration();
		$p = $diff / 20;
		$baseForce = min((($p ** 2) + $p * 2) / 3, 1);

		$entity = Entity::createEntity("Arrow", $player->getLevel(), $nbt, $player, $baseForce >= 1);
		if($entity instanceof Projectile){
			$infinity = $this->hasEnchantment(Enchantment::INFINITY);
			if($entity instanceof ArrowEntity){
				if($infinity){
					$entity->setPickupMode(ArrowEntity::PICKUP_CREATIVE);
				}
				if(($punchLevel = $this->getEnchantmentLevel(Enchantment::PUNCH)) > 0){
					$entity->setPunchKnockback($punchLevel);
				}
			}
			if(($powerLevel = $this->getEnchantmentLevel(Enchantment::POWER)) > 0){
				$entity->setBaseDamage($entity->getBaseDamage() + (($powerLevel + 1) / 2));
			}
			if($this->hasEnchantment(Enchantment::FLAME)){
				$entity->setOnFire(intdiv($entity->getFireTicks(), 20) + 100);
			}
			$ev = new EntityShootBowEvent($player, $this, $entity, $baseForce * 3);

			if($baseForce < 0.1 or $diff < 5){
				$ev->setCancelled();
			}

			$ev->call();

			$entity = $ev->getProjectile(); //This might have been changed by plugins

			if($ev->isCancelled()){
				$entity->flagForDespawn();
				$player->getInventory()->sendContents($player);
			}else{
				$entity->setMotion($entity->getMotion()->multiply($ev->getForce()));
				if($player->isSurvival()){
					if(!$infinity){ //TODO: tipped arrows are still consumed when Infinity is applied
						$player->getInventory()->removeItem(ItemFactory::get(Item::ARROW, 0, 1));
					}
					$this->applyDamage(1);
				}

				if($entity instanceof Projectile){
					$projectileEv = new ProjectileLaunchEvent($entity);
					$projectileEv->call();
					if($projectileEv->isCancelled()){
						$ev->getProjectile()->flagForDespawn();
					}else{
						$ev->getProjectile()->spawnToAll();
						$player->getLevel()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_BOW);
					}
				}else{
					$entity->spawnToAll();
				}
			}
		}else{
			$entity->spawnToAll();
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Arrow extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::ARROW, $meta, "Arrow");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Coal extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::COAL, $meta, "Coal");
		if($this->meta === 1){
			$this->name = "Charcoal";
		}
	}

	public function getFuelTime() : int{
		return 1600;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockToolType;
use pocketmine\entity\Entity;

class Sword extends TieredTool{

	public function getBlockToolType() : int{
		return BlockToolType::TYPE_SWORD;
	}

	public function getAttackPoints() : int{
		return self::getBaseDamageFromTier($this->tier);
	}

	public function getBlockToolHarvestLevel() : int{
		return 1;
	}

	public function getMiningEfficiency(Block $block) : float{
		return parent::getMiningEfficiency($block) * 1.5; //swords break any block 1.5x faster than hand
	}

	protected function getBaseMiningEfficiency() : float{
		return 10;
	}

	public function onDestroyBlock(Block $block) : bool{
		if($block->getHardness() > 0){
			return $this->applyDamage(2);
		}
		return false;
	}

	public function onAttackEntity(Entity $victim) : bool{
		return $this->applyDamage(1);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Stick extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::STICK, $meta, "Stick");
	}

	public function getFuelTime() : int{
		return 100;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Bowl extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::BOWL, $meta, "Bowl");
	}

	//TODO: check fuel
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class MushroomStew extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::MUSHROOM_STEW, $meta, "Mushroom Stew");
	}

	public function getMaxStackSize() : int{
		return 1;
	}

	public function getFoodRestore() : int{
		return 6;
	}

	public function getSaturationRestore() : float{
		return 7.2;
	}

	public function getResidue(){
		return ItemFactory::get(Item::BOWL);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class StringItem extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::STRING, $meta, "String");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::TRIPWIRE);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Entity;

class Hoe extends TieredTool{

	public function onAttackEntity(Entity $victim) : bool{
		return $this->applyDamage(1);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class WheatSeeds extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::WHEAT_SEEDS, $meta, "Wheat Seeds");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::WHEAT_BLOCK);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Bread extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::BREAD, $meta, "Bread");
	}

	public function getFoodRestore() : int{
		return 5;
	}

	public function getSaturationRestore() : float{
		return 6;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class LeatherCap extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::LEATHER_CAP, $meta, "Leather Cap");
	}

	public function getDefensePoints() : int{
		return 1;
	}

	public function getMaxDurability() : int{
		return 56;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\enchantment\ProtectionEnchantment;
use pocketmine\nbt\tag\IntTag;
use pocketmine\utils\Binary;
use pocketmine\utils\Color;
use function lcg_value;
use function mt_rand;

abstract class Armor extends Durable{

	public const TAG_CUSTOM_COLOR = "customColor"; //TAG_Int

	public function getMaxStackSize() : int{
		return 1;
	}

	/**
	 * Returns the dyed colour of this armour piece. This generally only applies to leather armour.
	 */
	public function getCustomColor() : ?Color{
		if($this->getNamedTag()->hasTag(self::TAG_CUSTOM_COLOR, IntTag::class)){
			return Color::fromARGB(Binary::unsignInt($this->getNamedTag()->getInt(self::TAG_CUSTOM_COLOR)));
		}

		return null;
	}

	/**
	 * Sets the dyed colour of this armour piece. This generally only applies to leather armour.
	 */
	public function setCustomColor(Color $color) : void{
		$this->setNamedTagEntry(new IntTag(self::TAG_CUSTOM_COLOR, Binary::signInt($color->toARGB())));
	}

	/**
	 * Returns the total enchantment protection factor this armour piece offers from all applicable protection
	 * enchantments on the item.
	 */
	public function getEnchantmentProtectionFactor(EntityDamageEvent $event) : int{
		$epf = 0;

		foreach($this->getEnchantments() as $enchantment){
			$type = $enchantment->getType();
			if($type instanceof ProtectionEnchantment and $type->isApplicable($event)){
				$epf += $type->getProtectionFactor($enchantment->getLevel());
			}
		}

		return $epf;
	}

	protected function getUnbreakingDamageReduction(int $amount) : int{
		if(($unbreakingLevel = $this->getEnchantmentLevel(Enchantment::UNBREAKING)) > 0){
			$negated = 0;

			$chance = 1 / ($unbreakingLevel + 1);
			for($i = 0; $i < $amount; ++$i){
				if(mt_rand(1, 100) > 60 and lcg_value() > $chance){ //unbreaking only applies to armor 40% of the time at best
					$negated++;
				}
			}

			return $negated;
		}

		return 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class LeatherTunic extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::LEATHER_TUNIC, $meta, "Leather Tunic");
	}

	public function getDefensePoints() : int{
		return 3;
	}

	public function getMaxDurability() : int{
		return 81;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class LeatherPants extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::LEATHER_PANTS, $meta, "Leather Pants");
	}

	public function getDefensePoints() : int{
		return 2;
	}

	public function getMaxDurability() : int{
		return 76;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class LeatherBoots extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::LEATHER_BOOTS, $meta, "Leather Boots");
	}

	public function getDefensePoints() : int{
		return 1;
	}

	public function getMaxDurability() : int{
		return 66;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class ChainHelmet extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::CHAIN_HELMET, $meta, "Chainmail Helmet");
	}

	public function getDefensePoints() : int{
		return 2;
	}

	public function getMaxDurability() : int{
		return 166;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class ChainChestplate extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::CHAIN_CHESTPLATE, $meta, "Chain Chestplate");
	}

	public function getDefensePoints() : int{
		return 5;
	}

	public function getMaxDurability() : int{
		return 241;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class ChainLeggings extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::CHAIN_LEGGINGS, $meta, "Chain Leggings");
	}

	public function getDefensePoints() : int{
		return 4;
	}

	public function getMaxDurability() : int{
		return 226;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class ChainBoots extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::CHAIN_BOOTS, $meta, "Chainmail Boots");
	}

	public function getDefensePoints() : int{
		return 1;
	}

	public function getMaxDurability() : int{
		return 196;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class IronHelmet extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::IRON_HELMET, $meta, "Iron Helmet");
	}

	public function getDefensePoints() : int{
		return 2;
	}

	public function getMaxDurability() : int{
		return 166;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class IronChestplate extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::IRON_CHESTPLATE, $meta, "Iron Chestplate");
	}

	public function getDefensePoints() : int{
		return 6;
	}

	public function getMaxDurability() : int{
		return 241;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class IronLeggings extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::IRON_LEGGINGS, $meta, "Iron Leggings");
	}

	public function getDefensePoints() : int{
		return 5;
	}

	public function getMaxDurability() : int{
		return 226;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class IronBoots extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::IRON_BOOTS, $meta, "Iron Boots");
	}

	public function getDefensePoints() : int{
		return 2;
	}

	public function getMaxDurability() : int{
		return 196;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class DiamondHelmet extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::DIAMOND_HELMET, $meta, "Diamond Helmet");
	}

	public function getDefensePoints() : int{
		return 3;
	}

	public function getMaxDurability() : int{
		return 364;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class DiamondChestplate extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::DIAMOND_CHESTPLATE, $meta, "Diamond Chestplate");
	}

	public function getDefensePoints() : int{
		return 8;
	}

	public function getMaxDurability() : int{
		return 529;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class DiamondLeggings extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::DIAMOND_LEGGINGS, $meta, "Diamond Leggings");
	}

	public function getDefensePoints() : int{
		return 6;
	}

	public function getMaxDurability() : int{
		return 496;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class DiamondBoots extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::DIAMOND_BOOTS, $meta, "Diamond Boots");
	}

	public function getDefensePoints() : int{
		return 3;
	}

	public function getMaxDurability() : int{
		return 430;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class GoldHelmet extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::GOLD_HELMET, $meta, "Gold Helmet");
	}

	public function getDefensePoints() : int{
		return 2;
	}

	public function getMaxDurability() : int{
		return 78;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class GoldChestplate extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::GOLD_CHESTPLATE, $meta, "Gold Chestplate");
	}

	public function getDefensePoints() : int{
		return 5;
	}

	public function getMaxDurability() : int{
		return 113;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class GoldLeggings extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::GOLD_LEGGINGS, $meta, "Gold Leggings");
	}

	public function getDefensePoints() : int{
		return 3;
	}

	public function getMaxDurability() : int{
		return 106;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class GoldBoots extends Armor{
	public function __construct(int $meta = 0){
		parent::__construct(self::GOLD_BOOTS, $meta, "Gold Boots");
	}

	public function getDefensePoints() : int{
		return 1;
	}

	public function getMaxDurability() : int{
		return 92;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class RawPorkchop extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::RAW_PORKCHOP, $meta, "Raw Porkchop");
	}

	public function getFoodRestore() : int{
		return 3;
	}

	public function getSaturationRestore() : float{
		return 0.6;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class CookedPorkchop extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::COOKED_PORKCHOP, $meta, "Cooked Porkchop");
	}

	public function getFoodRestore() : int{
		return 8;
	}

	public function getSaturationRestore() : float{
		return 12.8;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\entity\Entity;
use pocketmine\entity\object\Painting;
use pocketmine\entity\object\PaintingMotive;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\Player;
use function array_rand;
use function count;

class PaintingItem extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::PAINTING, $meta, "Painting");
	}

	public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{
		if($face === Vector3::SIDE_DOWN or $face === Vector3::SIDE_UP){
			return false;
		}

		$motives = [];

		$totalDimension = 0;
		foreach(PaintingMotive::getAll() as $motive){
			$currentTotalDimension = $motive->getHeight() + $motive->getWidth();
			if($currentTotalDimension < $totalDimension){
				continue;
			}

			if(Painting::canFit($player->level, $blockReplace, $face, true, $motive)){
				if($currentTotalDimension > $totalDimension){
					$totalDimension = $currentTotalDimension;
					/*
					 * This drops all motive possibilities smaller than this
					 * We use the total of height + width to allow equal chance of horizontal/vertical paintings
					 * when there is an L-shape of space available.
					 */
					$motives = [];
				}

				$motives[] = $motive;
			}
		}

		if(count($motives) === 0){ //No space available
			return false;
		}

		/** @var PaintingMotive $motive */
		$motive = $motives[array_rand($motives)];

		static $directions = [
			Vector3::SIDE_SOUTH => 0,
			Vector3::SIDE_WEST => 1,
			Vector3::SIDE_NORTH => 2,
			Vector3::SIDE_EAST => 3
		];

		$direction = $directions[$face] ?? -1;
		if($direction === -1){
			return false;
		}

		$nbt = Entity::createBaseNBT($blockReplace, null, $direction * 90, 0);
		$nbt->setByte("Direction", $direction);
		$nbt->setString("Motive", $motive->getName());
		$nbt->setInt("TileX", $blockClicked->getFloorX());
		$nbt->setInt("TileY", $blockClicked->getFloorY());
		$nbt->setInt("TileZ", $blockClicked->getFloorZ());

		$entity = Entity::createEntity("Painting", $blockReplace->getLevel(), $nbt);

		if($entity instanceof Entity){
			--$this->count;
			$entity->spawnToAll();

			$player->getLevel()->broadcastLevelEvent($blockReplace->add(0.5, 0.5, 0.5), LevelEventPacket::EVENT_SOUND_ITEMFRAME_PLACE); //item frame and painting have the same sound
			return true;
		}

		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;

class GoldenApple extends Food{

	public function __construct(int $meta = 0){
		parent::__construct(self::GOLDEN_APPLE, $meta, "Golden Apple");
	}

	public function requiresHunger() : bool{
		return false;
	}

	public function getFoodRestore() : int{
		return 4;
	}

	public function getSaturationRestore() : float{
		return 9.6;
	}

	public function getAdditionalEffects() : array{
		return [
			new EffectInstance(Effect::getEffect(Effect::REGENERATION), 100, 1),
			new EffectInstance(Effect::getEffect(Effect::ABSORPTION), 2400)
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class Sign extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::SIGN, $meta, "Sign");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::SIGN_POST);
	}

	public function getMaxStackSize() : int{
		return 16;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

/**
 * Class used for Items that can be Blocks
 */
class ItemBlock extends Item{
	/** @var int */
	protected $blockId;

	/**
	 * @param int      $meta usually 0-15 (placed blocks may only have meta values 0-15)
	 */
	public function __construct(int $blockId, int $meta = 0, int $itemId = null){
		$this->blockId = $blockId;
		parent::__construct($itemId ?? $blockId, $meta, $this->getBlock()->getName());
	}

	public function getBlock() : Block{
		return BlockFactory::get($this->blockId, $this->meta === -1 ? 0 : $this->meta & 0xf);
	}

	public function getVanillaName() : string{
		return $this->getBlock()->getName();
	}

	public function getFuelTime() : int{
		return $this->getBlock()->getFuelTime();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Air;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\block\Liquid;
use pocketmine\entity\Living;
use pocketmine\event\player\PlayerBucketEmptyEvent;
use pocketmine\event\player\PlayerBucketFillEvent;
use pocketmine\math\Vector3;
use pocketmine\Player;

class Bucket extends Item implements MaybeConsumable{
	public function __construct(int $meta = 0){
		parent::__construct(self::BUCKET, $meta, "Bucket");
	}

	public function getMaxStackSize() : int{
		return $this->meta === Block::AIR ? 16 : 1; //empty buckets stack to 16
	}

	public function getFuelTime() : int{
		if($this->meta === Block::LAVA or $this->meta === Block::FLOWING_LAVA){
			return 20000;
		}

		return 0;
	}

	public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{
		$resultBlock = BlockFactory::get($this->meta);

		if($resultBlock instanceof Air){
			if($blockClicked instanceof Liquid and $blockClicked->getDamage() === 0){
				$stack = clone $this;

				$stack->pop();
				$resultItem = ItemFactory::get(Item::BUCKET, $blockClicked->getFlowingForm()->getId());
				$ev = new PlayerBucketFillEvent($player, $blockReplace, $face, $this, $resultItem);
				$ev->call();
				if(!$ev->isCancelled()){
					$player->getLevel()->setBlock($blockClicked, BlockFactory::get(Block::AIR), true, true);
					$player->getLevel()->broadcastLevelSoundEvent($blockClicked->add(0.5, 0.5, 0.5), $blockClicked->getBucketFillSound());
					if($player->isSurvival()){
						if($stack->getCount() === 0){
							$player->getInventory()->setItemInHand($ev->getItem());
						}else{
							$player->getInventory()->setItemInHand($stack);
							$player->getInventory()->addItem($ev->getItem());
						}
					}else{
						$player->getInventory()->addItem($ev->getItem());
					}

					return true;
				}else{
					$player->getInventory()->sendContents($player);
				}
			}
		}elseif($resultBlock instanceof Liquid and $blockReplace->canBeReplaced()){
			$ev = new PlayerBucketEmptyEvent($player, $blockReplace, $face, $this, ItemFactory::get(Item::BUCKET));
			$ev->call();
			if(!$ev->isCancelled()){
				$player->getLevel()->setBlock($blockReplace, $resultBlock->getFlowingForm(), true, true);
				$player->getLevel()->broadcastLevelSoundEvent($blockReplace->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());

				if($player->isSurvival()){
					$player->getInventory()->setItemInHand($ev->getItem());
				}
				return true;
			}else{
				$player->getInventory()->sendContents($player);
			}
		}

		return false;
	}

	public function getResidue(){
		return ItemFactory::get(Item::BUCKET, 0, 1);
	}

	public function getAdditionalEffects() : array{
		return [];
	}

	public function canBeConsumed() : bool{
		return $this->meta === 1; //Milk
	}

	public function onConsume(Living $consumer){
		$consumer->removeAllEffects();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

/**
 * Items which are sometimes (but not always) consumable should implement this interface.
 *
 * Note: If implementing custom items, consider making separate items instead of using this.
 * This interface serves as a workaround for the consumability of buckets and shouldn't
 * really be used for anything else.
 */
interface MaybeConsumable extends Consumable{

	public function canBeConsumed() : bool;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Minecart extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::MINECART, $meta, "Minecart");
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class Redstone extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::REDSTONE, $meta, "Redstone");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::REDSTONE_WIRE);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Snowball extends ProjectileItem{
	public function __construct(int $meta = 0){
		parent::__construct(self::SNOWBALL, $meta, "Snowball");
	}

	public function getMaxStackSize() : int{
		return 16;
	}

	public function getProjectileEntityType() : string{
		return "Snowball";
	}

	public function getThrowForce() : float{
		return 1.5;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Entity;
use pocketmine\entity\EntityIds;
use pocketmine\entity\projectile\Projectile;
use pocketmine\event\entity\ProjectileLaunchEvent;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\Player;

abstract class ProjectileItem extends Item{

	abstract public function getProjectileEntityType() : string;

	abstract public function getThrowForce() : float;

	/**
	 * Helper function to apply extra NBT tags to pass to the created projectile.
	 */
	protected function addExtraTags(CompoundTag $tag) : void{

	}

	public function onClickAir(Player $player, Vector3 $directionVector) : bool{
		$nbt = Entity::createBaseNBT($player->add(0, $player->getEyeHeight(), 0), $directionVector, $player->yaw, $player->pitch);
		$this->addExtraTags($nbt);

		$projectile = Entity::createEntity($this->getProjectileEntityType(), $player->getLevel(), $nbt, $player);
		if($projectile !== null){
			$projectile->setMotion($projectile->getMotion()->multiply($this->getThrowForce()));
		}

		$this->count--;

		if($projectile instanceof Projectile){
			$projectileEv = new ProjectileLaunchEvent($projectile);
			$projectileEv->call();
			if($projectileEv->isCancelled()){
				$projectile->flagForDespawn();
			}else{
				$projectile->spawnToAll();

				$player->getLevel()->broadcastLevelSoundEvent($player, LevelSoundEventPacket::SOUND_THROW, 0, EntityIds::PLAYER);
			}
		}elseif($projectile !== null){
			$projectile->spawnToAll();
		}else{
			return false;
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Boat extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::BOAT, $meta, "Boat");
	}

	public function getFuelTime() : int{
		return 1200; //400 in PC
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Book extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::BOOK, $meta, "Book");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Egg extends ProjectileItem{
	public function __construct(int $meta = 0){
		parent::__construct(self::EGG, $meta, "Egg");
	}

	public function getMaxStackSize() : int{
		return 16;
	}

	public function getProjectileEntityType() : string{
		return "Egg";
	}

	public function getThrowForce() : float{
		return 1.5;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Compass extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::COMPASS, $meta, "Compass");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class FishingRod extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::FISHING_ROD, $meta, "Fishing Rod");
	}

	//TODO
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Clock extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::CLOCK, $meta, "Clock");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class RawFish extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::RAW_FISH, $meta, "Raw Fish");
	}

	public function getFoodRestore() : int{
		return 2;
	}

	public function getSaturationRestore() : float{
		return 0.4;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class CookedFish extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::COOKED_FISH, $meta, "Cooked Fish");
	}

	public function getFoodRestore() : int{
		return 5;
	}

	public function getSaturationRestore() : float{
		return 6;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Dye extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::DYE, $meta, "Dye");
	}

	//TODO: names
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class Bed extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::BED, $meta, "Bed");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::BED_BLOCK);
	}

	public function getMaxStackSize() : int{
		return 1;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Cookie extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::COOKIE, $meta, "Cookie");
	}

	public function getFoodRestore() : int{
		return 2;
	}

	public function getSaturationRestore() : float{
		return 0.4;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockToolType;

class Shears extends Tool{
	public function __construct(int $meta = 0){
		parent::__construct(self::SHEARS, $meta, "Shears");
	}

	public function getMaxDurability() : int{
		return 239;
	}

	public function getBlockToolType() : int{
		return BlockToolType::TYPE_SHEARS;
	}

	public function getBlockToolHarvestLevel() : int{
		return 1;
	}

	protected function getBaseMiningEfficiency() : float{
		return 15;
	}

	public function onDestroyBlock(Block $block) : bool{
		if($block->getHardness() === 0.0 or $block->isCompatibleWithTool($this)){
			return $this->applyDamage(1);
		}
		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Melon extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::MELON, $meta, "Melon");
	}

	public function getFoodRestore() : int{
		return 2;
	}

	public function getSaturationRestore() : float{
		return 1.2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class PumpkinSeeds extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::PUMPKIN_SEEDS, $meta, "Pumpkin Seeds");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::PUMPKIN_STEM);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class MelonSeeds extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::MELON_SEEDS, $meta, "Melon Seeds");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::MELON_STEM);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class RawBeef extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::RAW_BEEF, $meta, "Raw Beef");
	}

	public function getFoodRestore() : int{
		return 3;
	}

	public function getSaturationRestore() : float{
		return 1.8;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Steak extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::STEAK, $meta, "Steak");
	}

	public function getFoodRestore() : int{
		return 8;
	}

	public function getSaturationRestore() : float{
		return 12.8;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;
use function mt_rand;

class RawChicken extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::RAW_CHICKEN, $meta, "Raw Chicken");
	}

	public function getFoodRestore() : int{
		return 2;
	}

	public function getSaturationRestore() : float{
		return 1.2;
	}

	public function getAdditionalEffects() : array{
		return mt_rand(0, 9) < 3 ? [new EffectInstance(Effect::getEffect(Effect::HUNGER), 600)] : [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class CookedChicken extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::COOKED_CHICKEN, $meta, "Cooked Chicken");
	}

	public function getFoodRestore() : int{
		return 6;
	}

	public function getSaturationRestore() : float{
		return 7.2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;
use function lcg_value;

class RottenFlesh extends Food{

	public function __construct(int $meta = 0){
		parent::__construct(self::ROTTEN_FLESH, $meta, "Rotten Flesh");
	}

	public function getFoodRestore() : int{
		return 4;
	}

	public function getSaturationRestore() : float{
		return 0.8;
	}

	public function getAdditionalEffects() : array{
		if(lcg_value() <= 0.8){
			return [
				new EffectInstance(Effect::getEffect(Effect::HUNGER), 600)
			];
		}

		return [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class EnderPearl extends ProjectileItem{
	public function __construct(int $meta = 0){
		parent::__construct(self::ENDER_PEARL, $meta, "Ender Pearl");
	}

	public function getMaxStackSize() : int{
		return 16;
	}

	public function getProjectileEntityType() : string{
		return "ThrownEnderpearl";
	}

	public function getThrowForce() : float{
		return 1.5;
	}

	public function getCooldownTicks() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class BlazeRod extends Item{

	public function __construct(int $meta = 0){
		parent::__construct(self::BLAZE_ROD, $meta, "Blaze Rod");
	}

	public function getFuelTime() : int{
		return 2400;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;
use pocketmine\entity\Living;

class Potion extends Item implements Consumable{

	public const WATER = 0;
	public const MUNDANE = 1;
	public const LONG_MUNDANE = 2;
	public const THICK = 3;
	public const AWKWARD = 4;
	public const NIGHT_VISION = 5;
	public const LONG_NIGHT_VISION = 6;
	public const INVISIBILITY = 7;
	public const LONG_INVISIBILITY = 8;
	public const LEAPING = 9;
	public const LONG_LEAPING = 10;
	public const STRONG_LEAPING = 11;
	public const FIRE_RESISTANCE = 12;
	public const LONG_FIRE_RESISTANCE = 13;
	public const SWIFTNESS = 14;
	public const LONG_SWIFTNESS = 15;
	public const STRONG_SWIFTNESS = 16;
	public const SLOWNESS = 17;
	public const LONG_SLOWNESS = 18;
	public const WATER_BREATHING = 19;
	public const LONG_WATER_BREATHING = 20;
	public const HEALING = 21;
	public const STRONG_HEALING = 22;
	public const HARMING = 23;
	public const STRONG_HARMING = 24;
	public const POISON = 25;
	public const LONG_POISON = 26;
	public const STRONG_POISON = 27;
	public const REGENERATION = 28;
	public const LONG_REGENERATION = 29;
	public const STRONG_REGENERATION = 30;
	public const STRENGTH = 31;
	public const LONG_STRENGTH = 32;
	public const STRONG_STRENGTH = 33;
	public const WEAKNESS = 34;
	public const LONG_WEAKNESS = 35;
	public const WITHER = 36;

	/**
	 * Returns a list of effects applied by potions with the specified ID.
	 *
	 * @return EffectInstance[]
	 */
	public static function getPotionEffectsById(int $id) : array{
		switch($id){
			case self::WATER:
			case self::MUNDANE:
			case self::LONG_MUNDANE:
			case self::THICK:
			case self::AWKWARD:
				return [];
			case self::NIGHT_VISION:
				return [
					new EffectInstance(Effect::getEffect(Effect::NIGHT_VISION), 3600)
				];
			case self::LONG_NIGHT_VISION:
				return [
					new EffectInstance(Effect::getEffect(Effect::NIGHT_VISION), 9600)
				];
			case self::INVISIBILITY:
				return [
					new EffectInstance(Effect::getEffect(Effect::INVISIBILITY), 3600)
				];
			case self::LONG_INVISIBILITY:
				return [
					new EffectInstance(Effect::getEffect(Effect::INVISIBILITY), 9600)
				];
			case self::LEAPING:
				return [
					new EffectInstance(Effect::getEffect(Effect::JUMP_BOOST), 3600)
				];
			case self::LONG_LEAPING:
				return [
					new EffectInstance(Effect::getEffect(Effect::JUMP_BOOST), 9600)
				];
			case self::STRONG_LEAPING:
				return [
					new EffectInstance(Effect::getEffect(Effect::JUMP_BOOST), 1800, 1)
				];
			case self::FIRE_RESISTANCE:
				return [
					new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 3600)
				];
			case self::LONG_FIRE_RESISTANCE:
				return [
					new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 9600)
				];
			case self::SWIFTNESS:
				return [
					new EffectInstance(Effect::getEffect(Effect::SPEED), 3600)
				];
			case self::LONG_SWIFTNESS:
				return [
					new EffectInstance(Effect::getEffect(Effect::SPEED), 9600)
				];
			case self::STRONG_SWIFTNESS:
				return [
					new EffectInstance(Effect::getEffect(Effect::SPEED), 1800, 1)
				];
			case self::SLOWNESS:
				return [
					new EffectInstance(Effect::getEffect(Effect::SLOWNESS), 1800)
				];
			case self::LONG_SLOWNESS:
				return [
					new EffectInstance(Effect::getEffect(Effect::SLOWNESS), 4800)
				];
			case self::WATER_BREATHING:
				return [
					new EffectInstance(Effect::getEffect(Effect::WATER_BREATHING), 3600)
				];
			case self::LONG_WATER_BREATHING:
				return [
					new EffectInstance(Effect::getEffect(Effect::WATER_BREATHING), 9600)
				];
			case self::HEALING:
				return [
					new EffectInstance(Effect::getEffect(Effect::INSTANT_HEALTH))
				];
			case self::STRONG_HEALING:
				return [
					new EffectInstance(Effect::getEffect(Effect::INSTANT_HEALTH), null, 1)
				];
			case self::HARMING:
				return [
					new EffectInstance(Effect::getEffect(Effect::INSTANT_DAMAGE))
				];
			case self::STRONG_HARMING:
				return [
					new EffectInstance(Effect::getEffect(Effect::INSTANT_DAMAGE), null, 1)
				];
			case self::POISON:
				return [
					new EffectInstance(Effect::getEffect(Effect::POISON), 900)
				];
			case self::LONG_POISON:
				return [
					new EffectInstance(Effect::getEffect(Effect::POISON), 2400)
				];
			case self::STRONG_POISON:
				return [
					new EffectInstance(Effect::getEffect(Effect::POISON), 440, 1)
				];
			case self::REGENERATION:
				return [
					new EffectInstance(Effect::getEffect(Effect::REGENERATION), 900)
				];
			case self::LONG_REGENERATION:
				return [
					new EffectInstance(Effect::getEffect(Effect::REGENERATION), 2400)
				];
			case self::STRONG_REGENERATION:
				return [
					new EffectInstance(Effect::getEffect(Effect::REGENERATION), 440, 1)
				];
			case self::STRENGTH:
				return [
					new EffectInstance(Effect::getEffect(Effect::STRENGTH), 3600)
				];
			case self::LONG_STRENGTH:
				return [
					new EffectInstance(Effect::getEffect(Effect::STRENGTH), 9600)
				];
			case self::STRONG_STRENGTH:
				return [
					new EffectInstance(Effect::getEffect(Effect::STRENGTH), 1800, 1)
				];
			case self::WEAKNESS:
				return [
					new EffectInstance(Effect::getEffect(Effect::WEAKNESS), 1800)
				];
			case self::LONG_WEAKNESS:
				return [
					new EffectInstance(Effect::getEffect(Effect::WEAKNESS), 4800)
				];
			case self::WITHER:
				return [
					new EffectInstance(Effect::getEffect(Effect::WITHER), 800, 1)
				];
		}

		return [];
	}

	public function __construct(int $meta = 0){
		parent::__construct(self::POTION, $meta, "Potion");
	}

	public function getMaxStackSize() : int{
		return 1;
	}

	public function onConsume(Living $consumer){

	}

	public function getAdditionalEffects() : array{
		//TODO: check CustomPotionEffects NBT
		return self::getPotionEffectsById($this->meta);
	}

	public function getResidue(){
		return ItemFactory::get(Item::GLASS_BOTTLE);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class GlassBottle extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::GLASS_BOTTLE, $meta, "Glass Bottle");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;

class SpiderEye extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::SPIDER_EYE, $meta, "Spider Eye");
	}

	public function getFoodRestore() : int{
		return 2;
	}

	public function getSaturationRestore() : float{
		return 3.2;
	}

	public function getAdditionalEffects() : array{
		return [new EffectInstance(Effect::getEffect(Effect::POISON), 80)];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\entity\Entity;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function lcg_value;

class SpawnEgg extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::SPAWN_EGG, $meta, "Spawn Egg");
	}

	public function onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : bool{
		$nbt = Entity::createBaseNBT($blockReplace->add(0.5, 0, 0.5), null, lcg_value() * 360, 0);

		if($this->hasCustomName()){
			$nbt->setString("CustomName", $this->getCustomName());
		}

		$entity = Entity::createEntity($this->meta, $player->getLevel(), $nbt);

		if($entity instanceof Entity){
			--$this->count;
			$entity->spawnToAll();
			return true;
		}

		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class ExperienceBottle extends ProjectileItem{
	public function __construct(int $meta = 0){
		parent::__construct(self::EXPERIENCE_BOTTLE, $meta, "Bottle o' Enchanting");
	}

	public function getProjectileEntityType() : string{
		return "ThrownExpBottle";
	}

	public function getThrowForce() : float{
		return 0.7;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;

class WritableBook extends Item{

	public const TAG_PAGES = "pages"; //TAG_List<TAG_Compound>
	public const TAG_PAGE_TEXT = "text"; //TAG_String
	public const TAG_PAGE_PHOTONAME = "photoname"; //TAG_String - TODO

	public function __construct(int $meta = 0){
		parent::__construct(self::WRITABLE_BOOK, $meta, "Book & Quill");
	}

	/**
	 * Returns whether the given page exists in this book.
	 */
	public function pageExists(int $pageId) : bool{
		return $this->getPagesTag()->isset($pageId);
	}

	/**
	 * Returns a string containing the content of a page (which could be empty), or null if the page doesn't exist.
	 */
	public function getPageText(int $pageId) : ?string{
		$pages = $this->getNamedTag()->getListTag(self::TAG_PAGES);
		if($pages === null){
			return null;
		}

		$page = $pages->get($pageId);
		if($page instanceof CompoundTag){
			return $page->getString(self::TAG_PAGE_TEXT, "");
		}

		return null;
	}

	/**
	 * Sets the text of a page in the book. Adds the page if the page does not yet exist.
	 *
	 * @return bool indicating whether the page was created or not.
	 */
	public function setPageText(int $pageId, string $pageText) : bool{
		$created = false;
		if(!$this->pageExists($pageId)){
			$this->addPage($pageId);
			$created = true;
		}

		/** @var CompoundTag[]|ListTag $pagesTag */
		$pagesTag = $this->getPagesTag();
		/** @var CompoundTag $page */
		$page = $pagesTag->get($pageId);
		$page->setString(self::TAG_PAGE_TEXT, $pageText);

		$this->setNamedTagEntry($pagesTag);

		return $created;
	}

	/**
	 * Adds a new page with the given page ID.
	 * Creates a new page for every page between the given ID and existing pages that doesn't yet exist.
	 */
	public function addPage(int $pageId) : void{
		if($pageId < 0){
			throw new \InvalidArgumentException("Page number \"$pageId\" is out of range");
		}

		$pagesTag = $this->getPagesTag();

		for($current = $pagesTag->count(); $current <= $pageId; $current++){
			$pagesTag->push(new CompoundTag("", [
				new StringTag(self::TAG_PAGE_TEXT, ""),
				new StringTag(self::TAG_PAGE_PHOTONAME, "")
			]));
		}

		$this->setNamedTagEntry($pagesTag);
	}

	/**
	 * Deletes an existing page with the given page ID.
	 *
	 * @return bool indicating success
	 */
	public function deletePage(int $pageId) : bool{
		$pagesTag = $this->getPagesTag();
		$pagesTag->remove($pageId);
		$this->setNamedTagEntry($pagesTag);

		return true;
	}

	/**
	 * Inserts a new page with the given text and moves other pages upwards.
	 *
	 * @return bool indicating success
	 */
	public function insertPage(int $pageId, string $pageText = "") : bool{
		$pagesTag = $this->getPagesTag();

		$pagesTag->insert($pageId, new CompoundTag("", [
			new StringTag(self::TAG_PAGE_TEXT, $pageText),
			new StringTag(self::TAG_PAGE_PHOTONAME, "")
		]));

		$this->setNamedTagEntry($pagesTag);

		return true;
	}

	/**
	 * Switches the text of two pages with each other.
	 *
	 * @return bool indicating success
	 */
	public function swapPages(int $pageId1, int $pageId2) : bool{
		if(!$this->pageExists($pageId1) or !$this->pageExists($pageId2)){
			return false;
		}

		$pageContents1 = $this->getPageText($pageId1);
		$pageContents2 = $this->getPageText($pageId2);
		$this->setPageText($pageId1, $pageContents2);
		$this->setPageText($pageId2, $pageContents1);

		return true;
	}

	public function getMaxStackSize() : int{
		return 1;
	}

	/**
	 * Returns an array containing all pages of this book.
	 *
	 * @return CompoundTag[]
	 */
	public function getPages() : array{
		/** @var CompoundTag[] $pages */
		$pages = $this->getPagesTag()->getValue();

		return $pages;
	}

	protected function getPagesTag() : ListTag{
		$pagesTag = $this->getNamedTag()->getListTag(self::TAG_PAGES);
		if($pagesTag !== null and $pagesTag->getTagType() === NBT::TAG_Compound){
			return $pagesTag;
		}
		return new ListTag(self::TAG_PAGES, [], NBT::TAG_Compound);
	}

	/**
	 * @param CompoundTag[] $pages
	 */
	public function setPages(array $pages) : void{
		$nbt = $this->getNamedTag();
		$nbt->setTag(new ListTag(self::TAG_PAGES, $pages, NBT::TAG_Compound));
		$this->setNamedTag($nbt);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class WrittenBook extends WritableBook{

	public const GENERATION_ORIGINAL = 0;
	public const GENERATION_COPY = 1;
	public const GENERATION_COPY_OF_COPY = 2;
	public const GENERATION_TATTERED = 3;

	public const TAG_GENERATION = "generation"; //TAG_Int
	public const TAG_AUTHOR = "author"; //TAG_String
	public const TAG_TITLE = "title"; //TAG_String

	public function __construct(int $meta = 0){
		Item::__construct(self::WRITTEN_BOOK, $meta, "Written Book");
	}

	public function getMaxStackSize() : int{
		return 16;
	}

	/**
	 * Returns the generation of the book.
	 * Generations higher than 1 can not be copied.
	 */
	public function getGeneration() : int{
		return $this->getNamedTag()->getInt(self::TAG_GENERATION, -1);
	}

	/**
	 * Sets the generation of a book.
	 */
	public function setGeneration(int $generation) : void{
		if($generation < 0 or $generation > 3){
			throw new \InvalidArgumentException("Generation \"$generation\" is out of range");
		}
		$namedTag = $this->getNamedTag();
		$namedTag->setInt(self::TAG_GENERATION, $generation);
		$this->setNamedTag($namedTag);
	}

	/**
	 * Returns the author of this book.
	 * This is not a reliable way to get the name of the player who signed this book.
	 * The author can be set to anything when signing a book.
	 */
	public function getAuthor() : string{
		return $this->getNamedTag()->getString(self::TAG_AUTHOR, "");
	}

	/**
	 * Sets the author of this book.
	 */
	public function setAuthor(string $authorName) : void{
		$namedTag = $this->getNamedTag();
		$namedTag->setString(self::TAG_AUTHOR, $authorName);
		$this->setNamedTag($namedTag);
	}

	/**
	 * Returns the title of this book.
	 */
	public function getTitle() : string{
		return $this->getNamedTag()->getString(self::TAG_TITLE, "");
	}

	/**
	 * Sets the author of this book.
	 */
	public function setTitle(string $title) : void{
		$namedTag = $this->getNamedTag();
		$namedTag->setString(self::TAG_TITLE, $title);
		$this->setNamedTag($namedTag);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class Carrot extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::CARROT, $meta, "Carrot");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::CARROT_BLOCK);
	}

	public function getFoodRestore() : int{
		return 3;
	}

	public function getSaturationRestore() : float{
		return 4.8;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class Potato extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::POTATO, $meta, "Potato");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::POTATO_BLOCK);
	}

	public function getFoodRestore() : int{
		return 1;
	}

	public function getSaturationRestore() : float{
		return 0.6;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class BakedPotato extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::BAKED_POTATO, $meta, "Baked Potato");
	}

	public function getFoodRestore() : int{
		return 5;
	}

	public function getSaturationRestore() : float{
		return 7.2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;
use function mt_rand;

class PoisonousPotato extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::POISONOUS_POTATO, $meta, "Poisonous Potato");
	}

	public function getFoodRestore() : int{
		return 2;
	}

	public function getSaturationRestore() : float{
		return 1.2;
	}

	public function getAdditionalEffects() : array{
		if(mt_rand(0, 100) > 40){
			return [
				new EffectInstance(Effect::getEffect(Effect::POISON), 100)
			];
		}
		return [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class GoldenCarrot extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::GOLDEN_CARROT, $meta, "Golden Carrot");
	}

	public function getFoodRestore() : int{
		return 6;
	}

	public function getSaturationRestore() : float{
		return 14.4;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class PumpkinPie extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::PUMPKIN_PIE, $meta, "Pumpkin Pie");
	}

	public function getFoodRestore() : int{
		return 8;
	}

	public function getSaturationRestore() : float{
		return 4.8;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class RawRabbit extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::RAW_RABBIT, $meta, "Raw Rabbit");
	}

	public function getFoodRestore() : int{
		return 3;
	}

	public function getSaturationRestore() : float{
		return 1.8;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class CookedRabbit extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::COOKED_RABBIT, $meta, "Cooked Rabbit");
	}

	public function getFoodRestore() : int{
		return 5;
	}

	public function getSaturationRestore() : float{
		return 6;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class RabbitStew extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::RABBIT_STEW, $meta, "Rabbit Stew");
	}

	public function getMaxStackSize() : int{
		return 1;
	}

	public function getFoodRestore() : int{
		return 10;
	}

	public function getSaturationRestore() : float{
		return 12;
	}

	public function getResidue(){
		return ItemFactory::get(Item::BOWL);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class RawMutton extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::RAW_MUTTON, $meta, "Raw Mutton");
	}

	public function getFoodRestore() : int{
		return 2;
	}

	public function getSaturationRestore() : float{
		return 1.2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class CookedMutton extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::COOKED_MUTTON, $meta, "Cooked Mutton");
	}

	public function getFoodRestore() : int{
		return 6;
	}

	public function getSaturationRestore() : float{
		return 9.6;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Liquid;
use pocketmine\entity\Living;
use pocketmine\level\sound\EndermanTeleportSound;
use pocketmine\math\Vector3;
use function assert;
use function min;
use function mt_rand;

class ChorusFruit extends Food{

	public function __construct(int $meta = 0){
		parent::__construct(self::CHORUS_FRUIT, $meta, "Chorus Fruit");
	}

	public function getFoodRestore() : int{
		return 4;
	}

	public function getSaturationRestore() : float{
		return 2.4;
	}

	public function requiresHunger() : bool{
		return false;
	}

	public function onConsume(Living $consumer){
		$level = $consumer->getLevel();
		assert($level !== null);

		$minX = $consumer->getFloorX() - 8;
		$minY = min($consumer->getFloorY(), $consumer->getLevel()->getWorldHeight()) - 8;
		$minZ = $consumer->getFloorZ() - 8;

		$maxX = $minX + 16;
		$maxY = $minY + 16;
		$maxZ = $minZ + 16;

		for($attempts = 0; $attempts < 16; ++$attempts){
			$x = mt_rand($minX, $maxX);
			$y = mt_rand($minY, $maxY);
			$z = mt_rand($minZ, $maxZ);

			while($y >= 0 and !$level->getBlockAt($x, $y, $z)->isSolid()){
				$y--;
			}
			if($y < 0){
				continue;
			}

			$blockUp = $level->getBlockAt($x, $y + 1, $z);
			$blockUp2 = $level->getBlockAt($x, $y + 2, $z);
			if($blockUp->isSolid() or $blockUp instanceof Liquid or $blockUp2->isSolid() or $blockUp2 instanceof Liquid){
				continue;
			}

			//Sounds are broadcasted at both source and destination
			$level->addSound(new EndermanTeleportSound($consumer->asVector3()));
			$consumer->teleport(new Vector3($x + 0.5, $y + 1, $z + 0.5));
			$level->addSound(new EndermanTeleportSound($consumer->asVector3()));

			break;
		}
	}

	public function getCooldownTicks() : int{
		return 20;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\nbt\tag\CompoundTag;

class SplashPotion extends ProjectileItem{

	public function __construct(int $meta = 0){
		parent::__construct(self::SPLASH_POTION, $meta, "Splash Potion");
	}

	public function getMaxStackSize() : int{
		return 1;
	}

	public function getProjectileEntityType() : string{
		return "ThrownPotion";
	}

	public function getThrowForce() : float{
		return 0.5;
	}

	protected function addExtraTags(CompoundTag $tag) : void{
		$tag->setShort("PotionId", $this->meta);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\tile\Banner as TileBanner;
use function assert;

class Banner extends Item{
	public const TAG_BASE = TileBanner::TAG_BASE;
	public const TAG_PATTERNS = TileBanner::TAG_PATTERNS;
	public const TAG_PATTERN_COLOR = TileBanner::TAG_PATTERN_COLOR;
	public const TAG_PATTERN_NAME = TileBanner::TAG_PATTERN_NAME;

	public function __construct(int $meta = 0){
		parent::__construct(self::BANNER, $meta, "Banner");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::STANDING_BANNER);
	}

	public function getMaxStackSize() : int{
		return 16;
	}

	/**
	 * Returns the color of the banner base.
	 */
	public function getBaseColor() : int{
		return $this->getNamedTag()->getInt(self::TAG_BASE, 0);
	}

	/**
	 * Sets the color of the banner base.
	 * Banner items have to be resent to see the changes in the inventory.
	 */
	public function setBaseColor(int $color) : void{
		$namedTag = $this->getNamedTag();
		$namedTag->setInt(self::TAG_BASE, $color & 0x0f);
		$this->setNamedTag($namedTag);
	}

	/**
	 * Applies a new pattern on the banner with the given color.
	 * Banner items have to be resent to see the changes in the inventory.
	 *
	 * @return int ID of pattern.
	 */
	public function addPattern(string $pattern, int $color) : int{
		$patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS);
		assert($patternsTag !== null);

		$patternsTag->push(new CompoundTag("", [
			new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f),
			new StringTag(self::TAG_PATTERN_NAME, $pattern)
		]));

		$this->setNamedTagEntry($patternsTag);

		return $patternsTag->count() - 1;
	}

	/**
	 * Returns whether a pattern with the given ID exists on the banner or not.
	 */
	public function patternExists(int $patternId) : bool{
		$this->correctNBT();
		return $this->getNamedTag()->getListTag(self::TAG_PATTERNS)->isset($patternId);
	}

	/**
	 * Returns the data of a pattern with the given ID.
	 *
	 * @return mixed[]
	 * @phpstan-return array{Color?: int, Pattern?: string}
	 */
	public function getPatternData(int $patternId) : array{
		if(!$this->patternExists($patternId)){
			return [];
		}

		$patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS);
		assert($patternsTag !== null);
		$pattern = $patternsTag->get($patternId);
		assert($pattern instanceof CompoundTag);

		return [
			self::TAG_PATTERN_COLOR => $pattern->getInt(self::TAG_PATTERN_COLOR),
			self::TAG_PATTERN_NAME => $pattern->getString(self::TAG_PATTERN_NAME)
		];
	}

	/**
	 * Changes the pattern of a previously existing pattern.
	 * Banner items have to be resent to see the changes in the inventory.
	 *
	 * @return bool indicating success.
	 */
	public function changePattern(int $patternId, string $pattern, int $color) : bool{
		if(!$this->patternExists($patternId)){
			return false;
		}

		$patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS);
		assert($patternsTag !== null);

		$patternsTag->set($patternId, new CompoundTag("", [
			new IntTag(self::TAG_PATTERN_COLOR, $color & 0x0f),
			new StringTag(self::TAG_PATTERN_NAME, $pattern)
		]));

		$this->setNamedTagEntry($patternsTag);
		return true;
	}

	/**
	 * Deletes a pattern from the banner with the given ID.
	 * Banner items have to be resent to see the changes in the inventory.
	 *
	 * @return bool indicating whether the pattern existed or not.
	 */
	public function deletePattern(int $patternId) : bool{
		if(!$this->patternExists($patternId)){
			return false;
		}

		$patternsTag = $this->getNamedTag()->getListTag(self::TAG_PATTERNS);
		if($patternsTag instanceof ListTag){
			$patternsTag->remove($patternId);
			$this->setNamedTagEntry($patternsTag);
		}

		return true;
	}

	/**
	 * Deletes the top most pattern of the banner.
	 * Banner items have to be resent to see the changes in the inventory.
	 *
	 * @return bool indicating whether the banner was empty or not.
	 */
	public function deleteTopPattern() : bool{
		return $this->deletePattern($this->getPatternCount() - 1);
	}

	/**
	 * Deletes the bottom pattern of the banner.
	 * Banner items have to be resent to see the changes in the inventory.
	 *
	 * @return bool indicating whether the banner was empty or not.
	 */
	public function deleteBottomPattern() : bool{
		return $this->deletePattern(0);
	}

	/**
	 * Returns the total count of patterns on this banner.
	 */
	public function getPatternCount() : int{
		return $this->getNamedTag()->getListTag(self::TAG_PATTERNS)->count();
	}

	public function correctNBT() : void{
		$tag = $this->getNamedTag();
		if(!$tag->hasTag(self::TAG_BASE, IntTag::class)){
			$tag->setInt(self::TAG_BASE, 0);
		}

		if(!$tag->hasTag(self::TAG_PATTERNS, ListTag::class)){
			$tag->setTag(new ListTag(self::TAG_PATTERNS));
		}
		$this->setNamedTag($tag);
	}

	public function getFuelTime() : int{
		return 300;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Totem extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::TOTEM, $meta, "Totem of Undying");
	}

	public function getMaxStackSize() : int{
		return 1;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Beetroot extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::BEETROOT, $meta, "Beetroot");
	}

	public function getFoodRestore() : int{
		return 1;
	}

	public function getSaturationRestore() : float{
		return 1.2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

class BeetrootSeeds extends Item{
	public function __construct(int $meta = 0){
		parent::__construct(self::BEETROOT_SEEDS, $meta, "Beetroot Seeds");
	}

	public function getBlock() : Block{
		return BlockFactory::get(Block::BEETROOT_BLOCK);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class BeetrootSoup extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::BEETROOT_SOUP, $meta, "Beetroot Soup");
	}

	public function getMaxStackSize() : int{
		return 1;
	}

	public function getFoodRestore() : int{
		return 6;
	}

	public function getSaturationRestore() : float{
		return 7.2;
	}

	public function getResidue(){
		return ItemFactory::get(Item::BOWL);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class RawSalmon extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::RAW_SALMON, $meta, "Raw Salmon");
	}

	public function getFoodRestore() : int{
		return 2;
	}

	public function getSaturationRestore() : float{
		return 0.2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class Clownfish extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::CLOWNFISH, $meta, "Clownfish");
	}

	public function getFoodRestore() : int{
		return 1;
	}

	public function getSaturationRestore() : float{
		return 0.2;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;

class Pufferfish extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::PUFFERFISH, $meta, "Pufferfish");
	}

	public function getFoodRestore() : int{
		return 1;
	}

	public function getSaturationRestore() : float{
		return 0.2;
	}

	public function getAdditionalEffects() : array{
		return [
			new EffectInstance(Effect::getEffect(Effect::HUNGER), 300, 2),
			new EffectInstance(Effect::getEffect(Effect::POISON), 1200, 3),
			new EffectInstance(Effect::getEffect(Effect::NAUSEA), 300, 1)
		];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class CookedSalmon extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::COOKED_SALMON, $meta, "Cooked Salmon");
	}

	public function getFoodRestore() : int{
		return 6;
	}

	public function getSaturationRestore() : float{
		return 9.6;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

class DriedKelp extends Food{
	public function __construct(int $meta = 0){
		parent::__construct(self::DRIED_KELP, $meta, "Dried Kelp");
	}

	public function getFoodRestore() : int{
		return 1;
	}

	public function getSaturationRestore() : float{
		return 0.6;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\item;

use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;

class GoldenAppleEnchanted extends GoldenApple{

	public function __construct(int $meta = 0){
		Food::__construct(self::ENCHANTED_GOLDEN_APPLE, $meta, "Enchanted Golden Apple"); //skip parent constructor
	}

	public function getAdditionalEffects() : array{
		return [
			new EffectInstance(Effect::getEffect(Effect::REGENERATION), 600, 4),
			new EffectInstance(Effect::getEffect(Effect::ABSORPTION), 2400, 3),
			new EffectInstance(Effect::getEffect(Effect::RESISTANCE), 6000),
			new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 6000)
		];
	}
}
[{"id":5},{"id":5,"damage":1},{"id":5,"damage":2},{"id":5,"damage":3},{"id":5,"damage":4},{"id":5,"damage":5},{"id":139},{"id":139,"damage":1},{"id":139,"damage":2},{"id":139,"damage":3},{"id":139,"damage":4},{"id":139,"damage":5},{"id":139,"damage":12},{"id":139,"damage":7},{"id":139,"damage":8},{"id":139,"damage":6},{"id":139,"damage":9},{"id":139,"damage":13},{"id":139,"damage":10},{"id":139,"damage":11},{"id":85},{"id":85,"damage":1},{"id":85,"damage":2},{"id":85,"damage":3},{"id":85,"damage":4},{"id":85,"damage":5},{"id":113},{"id":107},{"id":183},{"id":184},{"id":185},{"id":187},{"id":186},{"id":-180},{"id":67},{"id":-179},{"id":53},{"id":134},{"id":135},{"id":136},{"id":163},{"id":164},{"id":109},{"id":-175},{"id":128},{"id":-177},{"id":180},{"id":-176},{"id":-169},{"id":-172},{"id":-170},{"id":-173},{"id":-171},{"id":-174},{"id":108},{"id":114},{"id":-184},{"id":-178},{"id":156},{"id":-185},{"id":203},{"id":-2},{"id":-3},{"id":-4},{"id":324},{"id":427},{"id":428},{"id":429},{"id":430},{"id":431},{"id":330},{"id":96},{"id":-149},{"id":-146},{"id":-148},{"id":-145},{"id":-147},{"id":167},{"id":101},{"id":20},{"id":241},{"id":241,"damage":8},{"id":241,"damage":7},{"id":241,"damage":15},{"id":241,"damage":12},{"id":241,"damage":14},{"id":241,"damage":1},{"id":241,"damage":4},{"id":241,"damage":5},{"id":241,"damage":13},{"id":241,"damage":9},{"id":241,"damage":3},{"id":241,"damage":11},{"id":241,"damage":10},{"id":241,"damage":2},{"id":241,"damage":6},{"id":102},{"id":160},{"id":160,"damage":8},{"id":160,"damage":7},{"id":160,"damage":15},{"id":160,"damage":12},{"id":160,"damage":14},{"id":160,"damage":1},{"id":160,"damage":4},{"id":160,"damage":5},{"id":160,"damage":13},{"id":160,"damage":9},{"id":160,"damage":3},{"id":160,"damage":11},{"id":160,"damage":10},{"id":160,"damage":2},{"id":160,"damage":6},{"id":65},{"id":-165},{"id":44},{"id":-166,"damage":2},{"id":44,"damage":3},{"id":182,"damage":5},{"id":158},{"id":158,"damage":1},{"id":158,"damage":2},{"id":158,"damage":3},{"id":158,"damage":4},{"id":158,"damage":5},{"id":44,"damage":5},{"id":-166},{"id":44,"damage":1},{"id":-166,"damage":3},{"id":182,"damage":6},{"id":182},{"id":-166,"damage":4},{"id":-162,"damage":1},{"id":-162,"damage":6},{"id":-162,"damage":7},{"id":-162,"damage":4},{"id":-162,"damage":5},{"id":-162,"damage":3},{"id":-162,"damage":2},{"id":44,"damage":4},{"id":44,"damage":7},{"id":182,"damage":7},{"id":-162},{"id":44,"damage":6},{"id":-166,"damage":1},{"id":182,"damage":1},{"id":182,"damage":2},{"id":182,"damage":3},{"id":182,"damage":4},{"id":45},{"id":98},{"id":98,"damage":1},{"id":98,"damage":2},{"id":98,"damage":3},{"id":206},{"id":168,"damage":2},{"id":4},{"id":48},{"id":-183},{"id":24},{"id":24,"damage":1},{"id":24,"damage":2},{"id":24,"damage":3},{"id":179},{"id":179,"damage":1},{"id":179,"damage":2},{"id":179,"damage":3},{"id":173},{"id":-139},{"id":41},{"id":42},{"id":133},{"id":57},{"id":22},{"id":155},{"id":155,"damage":2},{"id":155,"damage":1},{"id":155,"damage":3},{"id":168},{"id":168,"damage":1},{"id":165},{"id":-220},{"id":-221},{"id":170},{"id":216},{"id":214},{"id":112},{"id":215},{"id":35},{"id":35,"damage":8},{"id":35,"damage":7},{"id":35,"damage":15},{"id":35,"damage":12},{"id":35,"damage":14},{"id":35,"damage":1},{"id":35,"damage":4},{"id":35,"damage":5},{"id":35,"damage":13},{"id":35,"damage":9},{"id":35,"damage":3},{"id":35,"damage":11},{"id":35,"damage":10},{"id":35,"damage":2},{"id":35,"damage":6},{"id":171},{"id":171,"damage":8},{"id":171,"damage":7},{"id":171,"damage":15},{"id":171,"damage":12},{"id":171,"damage":14},{"id":171,"damage":1},{"id":171,"damage":4},{"id":171,"damage":5},{"id":171,"damage":13},{"id":171,"damage":9},{"id":171,"damage":3},{"id":171,"damage":11},{"id":171,"damage":10},{"id":171,"damage":2},{"id":171,"damage":6},{"id":237},{"id":237,"damage":8},{"id":237,"damage":7},{"id":237,"damage":15},{"id":237,"damage":12},{"id":237,"damage":14},{"id":237,"damage":1},{"id":237,"damage":4},{"id":237,"damage":5},{"id":237,"damage":13},{"id":237,"damage":9},{"id":237,"damage":3},{"id":237,"damage":11},{"id":237,"damage":10},{"id":237,"damage":2},{"id":237,"damage":6},{"id":236},{"id":236,"damage":8},{"id":236,"damage":7},{"id":236,"damage":15},{"id":236,"damage":12},{"id":236,"damage":14},{"id":236,"damage":1},{"id":236,"damage":4},{"id":236,"damage":5},{"id":236,"damage":13},{"id":236,"damage":9},{"id":236,"damage":3},{"id":236,"damage":11},{"id":236,"damage":10},{"id":236,"damage":2},{"id":236,"damage":6},{"id":82},{"id":172},{"id":159},{"id":159,"damage":8},{"id":159,"damage":7},{"id":159,"damage":15},{"id":159,"damage":12},{"id":159,"damage":14},{"id":159,"damage":1},{"id":159,"damage":4},{"id":159,"damage":5},{"id":159,"damage":13},{"id":159,"damage":9},{"id":159,"damage":3},{"id":159,"damage":11},{"id":159,"damage":10},{"id":159,"damage":2},{"id":159,"damage":6},{"id":220},{"id":228},{"id":227},{"id":235},{"id":232},{"id":234},{"id":221},{"id":224},{"id":225},{"id":233},{"id":229},{"id":223},{"id":231},{"id":219},{"id":222},{"id":226},{"id":201},{"id":201,"damage":2},{"id":3},{"id":3,"damage":1},{"id":2},{"id":198},{"id":243},{"id":110},{"id":1},{"id":15},{"id":14},{"id":56},{"id":21},{"id":73},{"id":16},{"id":129},{"id":153},{"id":13},{"id":1,"damage":1},{"id":1,"damage":3},{"id":1,"damage":5},{"id":1,"damage":2},{"id":1,"damage":4},{"id":1,"damage":6},{"id":12},{"id":12,"damage":1},{"id":81},{"id":17},{"id":-10},{"id":17,"damage":1},{"id":-5},{"id":17,"damage":2},{"id":-6},{"id":17,"damage":3},{"id":-7},{"id":162},{"id":-8},{"id":162,"damage":1},{"id":-9},{"id":-212},{"id":-212,"damage":8},{"id":-212,"damage":1},{"id":-212,"damage":9},{"id":-212,"damage":2},{"id":-212,"damage":10},{"id":-212,"damage":3},{"id":-212,"damage":11},{"id":-212,"damage":4},{"id":-212,"damage":12},{"id":-212,"damage":5},{"id":-212,"damage":13},{"id":18},{"id":18,"damage":1},{"id":18,"damage":2},{"id":18,"damage":3},{"id":161},{"id":161,"damage":1},{"id":6},{"id":6,"damage":1},{"id":6,"damage":2},{"id":6,"damage":3},{"id":6,"damage":4},{"id":6,"damage":5},{"id":-218},{"id":295},{"id":361},{"id":362},{"id":458},{"id":296},{"id":457},{"id":392},{"id":394},{"id":391},{"id":396},{"id":260},{"id":322},{"id":466},{"id":103},{"id":360},{"id":382},{"id":477},{"id":86},{"id":-155},{"id":91},{"id":736},{"id":31,"damage":2},{"id":175,"damage":3},{"id":31,"damage":1},{"id":175,"damage":2},{"id":-131,"damage":3},{"id":-131,"damage":1},{"id":-131,"damage":2},{"id":-131},{"id":-131,"damage":4},{"id":-131,"damage":11},{"id":-131,"damage":9},{"id":-131,"damage":10},{"id":-131,"damage":8},{"id":-131,"damage":12},{"id":-133,"damage":3},{"id":-133,"damage":1},{"id":-133,"damage":2},{"id":-133},{"id":-133,"damage":4},{"id":-134,"damage":3},{"id":-134,"damage":1},{"id":-134,"damage":2},{"id":-134},{"id":-134,"damage":4},{"id":335},{"id":-130},{"id":37},{"id":38},{"id":38,"damage":1},{"id":38,"damage":2},{"id":38,"damage":3},{"id":38,"damage":4},{"id":38,"damage":5},{"id":38,"damage":6},{"id":38,"damage":7},{"id":38,"damage":8},{"id":38,"damage":9},{"id":38,"damage":10},{"id":175},{"id":175,"damage":1},{"id":175,"damage":4},{"id":175,"damage":5},{"id":-216},{"id":351,"damage":19},{"id":351,"damage":7},{"id":351,"damage":8},{"id":351,"damage":16},{"id":351,"damage":17},{"id":351,"damage":1},{"id":351,"damage":14},{"id":351,"damage":11},{"id":351,"damage":10},{"id":351,"damage":2},{"id":351,"damage":6},{"id":351,"damage":12},{"id":351,"damage":18},{"id":351,"damage":5},{"id":351,"damage":13},{"id":351,"damage":9},{"id":351},{"id":351,"damage":3},{"id":351,"damage":4},{"id":351,"damage":15},{"id":106},{"id":111},{"id":32},{"id":-163},{"id":80},{"id":79},{"id":174},{"id":-11},{"id":78},{"id":365},{"id":319},{"id":363},{"id":423},{"id":411},{"id":349},{"id":460},{"id":461},{"id":462},{"id":39},{"id":40},{"id":99,"damage":14},{"id":100,"damage":14},{"id":99,"damage":15},{"id":99},{"id":344},{"id":338},{"id":353},{"id":367},{"id":352},{"id":30},{"id":375},{"id":52},{"id":97},{"id":97,"damage":1},{"id":97,"damage":2},{"id":97,"damage":3},{"id":97,"damage":4},{"id":97,"damage":5},{"id":122},{"id":-159},{"id":383,"damage":10},{"id":383,"damage":122},{"id":383,"damage":11},{"id":383,"damage":12},{"id":383,"damage":13},{"id":383,"damage":14},{"id":383,"damage":28},{"id":383,"damage":22},{"id":383,"damage":75},{"id":383,"damage":16},{"id":383,"damage":19},{"id":383,"damage":30},{"id":383,"damage":18},{"id":383,"damage":29},{"id":383,"damage":23},{"id":383,"damage":24},{"id":383,"damage":25},{"id":383,"damage":26},{"id":383,"damage":27},{"id":383,"damage":111},{"id":383,"damage":112},{"id":383,"damage":108},{"id":383,"damage":109},{"id":383,"damage":31},{"id":383,"damage":74},{"id":383,"damage":113},{"id":383,"damage":121},{"id":383,"damage":33},{"id":383,"damage":38},{"id":383,"damage":39},{"id":383,"damage":34},{"id":383,"damage":48},{"id":383,"damage":46},{"id":383,"damage":37},{"id":383,"damage":35},{"id":383,"damage":32},{"id":383,"damage":36},{"id":383,"damage":47},{"id":383,"damage":110},{"id":383,"damage":17},{"id":383,"damage":40},{"id":383,"damage":45},{"id":383,"damage":49},{"id":383,"damage":50},{"id":383,"damage":55},{"id":383,"damage":42},{"id":383,"damage":41},{"id":383,"damage":43},{"id":383,"damage":54},{"id":383,"damage":57},{"id":383,"damage":104},{"id":383,"damage":105},{"id":383,"damage":115},{"id":383,"damage":118},{"id":383,"damage":116},{"id":383,"damage":58},{"id":383,"damage":114},{"id":383,"damage":59},{"id":49},{"id":7},{"id":88},{"id":87},{"id":213},{"id":372},{"id":121},{"id":200},{"id":240},{"id":432},{"id":433},{"id":19},{"id":19,"damage":1},{"id":-132},{"id":-132,"damage":1},{"id":-132,"damage":2},{"id":-132,"damage":3},{"id":-132,"damage":4},{"id":-132,"damage":8},{"id":-132,"damage":9},{"id":-132,"damage":10},{"id":-132,"damage":11},{"id":-132,"damage":12},{"id":298},{"id":302},{"id":306},{"id":314},{"id":310},{"id":299},{"id":303},{"id":307},{"id":315},{"id":311},{"id":300},{"id":304},{"id":308},{"id":316},{"id":312},{"id":301},{"id":305},{"id":309},{"id":317},{"id":313},{"id":268},{"id":272},{"id":267},{"id":283},{"id":276},{"id":271},{"id":275},{"id":258},{"id":286},{"id":279},{"id":270},{"id":274},{"id":257},{"id":285},{"id":278},{"id":269},{"id":273},{"id":256},{"id":284},{"id":277},{"id":290},{"id":291},{"id":292},{"id":294},{"id":293},{"id":261},{"id":471},{"id":262},{"id":262,"damage":6},{"id":262,"damage":7},{"id":262,"damage":8},{"id":262,"damage":9},{"id":262,"damage":10},{"id":262,"damage":11},{"id":262,"damage":12},{"id":262,"damage":13},{"id":262,"damage":14},{"id":262,"damage":15},{"id":262,"damage":16},{"id":262,"damage":17},{"id":262,"damage":18},{"id":262,"damage":19},{"id":262,"damage":20},{"id":262,"damage":21},{"id":262,"damage":22},{"id":262,"damage":23},{"id":262,"damage":24},{"id":262,"damage":25},{"id":262,"damage":26},{"id":262,"damage":27},{"id":262,"damage":28},{"id":262,"damage":29},{"id":262,"damage":30},{"id":262,"damage":31},{"id":262,"damage":32},{"id":262,"damage":33},{"id":262,"damage":34},{"id":262,"damage":35},{"id":262,"damage":36},{"id":262,"damage":37},{"id":262,"damage":38},{"id":262,"damage":39},{"id":262,"damage":40},{"id":262,"damage":41},{"id":262,"damage":42},{"id":513},{"id":366},{"id":320},{"id":364},{"id":424},{"id":412},{"id":350},{"id":463},{"id":297},{"id":282},{"id":459},{"id":413},{"id":393},{"id":357},{"id":400},{"id":354},{"id":464},{"id":346},{"id":398},{"id":332},{"id":359},{"id":259},{"id":420},{"id":347},{"id":345},{"id":395},{"id":395,"damage":2},{"id":329},{"id":416},{"id":417},{"id":418},{"id":419},{"id":455},{"id":469},{"id":444},{"id":450},{"id":374},{"id":384},{"id":373},{"id":373,"damage":1},{"id":373,"damage":2},{"id":373,"damage":3},{"id":373,"damage":4},{"id":373,"damage":5},{"id":373,"damage":6},{"id":373,"damage":7},{"id":373,"damage":8},{"id":373,"damage":9},{"id":373,"damage":10},{"id":373,"damage":11},{"id":373,"damage":12},{"id":373,"damage":13},{"id":373,"damage":14},{"id":373,"damage":15},{"id":373,"damage":16},{"id":373,"damage":17},{"id":373,"damage":18},{"id":373,"damage":19},{"id":373,"damage":20},{"id":373,"damage":21},{"id":373,"damage":22},{"id":373,"damage":23},{"id":373,"damage":24},{"id":373,"damage":25},{"id":373,"damage":26},{"id":373,"damage":27},{"id":373,"damage":28},{"id":373,"damage":29},{"id":373,"damage":30},{"id":373,"damage":31},{"id":373,"damage":32},{"id":373,"damage":33},{"id":373,"damage":34},{"id":373,"damage":35},{"id":373,"damage":36},{"id":373,"damage":37},{"id":373,"damage":38},{"id":373,"damage":39},{"id":373,"damage":40},{"id":373,"damage":41},{"id":438},{"id":438,"damage":1},{"id":438,"damage":2},{"id":438,"damage":3},{"id":438,"damage":4},{"id":438,"damage":5},{"id":438,"damage":6},{"id":438,"damage":7},{"id":438,"damage":8},{"id":438,"damage":9},{"id":438,"damage":10},{"id":438,"damage":11},{"id":438,"damage":12},{"id":438,"damage":13},{"id":438,"damage":14},{"id":438,"damage":15},{"id":438,"damage":16},{"id":438,"damage":17},{"id":438,"damage":18},{"id":438,"damage":19},{"id":438,"damage":20},{"id":438,"damage":21},{"id":438,"damage":22},{"id":438,"damage":23},{"id":438,"damage":24},{"id":438,"damage":25},{"id":438,"damage":26},{"id":438,"damage":27},{"id":438,"damage":28},{"id":438,"damage":29},{"id":438,"damage":30},{"id":438,"damage":31},{"id":438,"damage":32},{"id":438,"damage":33},{"id":438,"damage":34},{"id":438,"damage":35},{"id":438,"damage":36},{"id":438,"damage":37},{"id":438,"damage":38},{"id":438,"damage":39},{"id":438,"damage":40},{"id":438,"damage":41},{"id":441},{"id":441,"damage":1},{"id":441,"damage":2},{"id":441,"damage":3},{"id":441,"damage":4},{"id":441,"damage":5},{"id":441,"damage":6},{"id":441,"damage":7},{"id":441,"damage":8},{"id":441,"damage":9},{"id":441,"damage":10},{"id":441,"damage":11},{"id":441,"damage":12},{"id":441,"damage":13},{"id":441,"damage":14},{"id":441,"damage":15},{"id":441,"damage":16},{"id":441,"damage":17},{"id":441,"damage":18},{"id":441,"damage":19},{"id":441,"damage":20},{"id":441,"damage":21},{"id":441,"damage":22},{"id":441,"damage":23},{"id":441,"damage":24},{"id":441,"damage":25},{"id":441,"damage":26},{"id":441,"damage":27},{"id":441,"damage":28},{"id":441,"damage":29},{"id":441,"damage":30},{"id":441,"damage":31},{"id":441,"damage":32},{"id":441,"damage":33},{"id":441,"damage":34},{"id":441,"damage":35},{"id":441,"damage":36},{"id":441,"damage":37},{"id":441,"damage":38},{"id":441,"damage":39},{"id":441,"damage":40},{"id":441,"damage":41},{"id":280},{"id":355},{"id":355,"damage":8},{"id":355,"damage":7},{"id":355,"damage":15},{"id":355,"damage":12},{"id":355,"damage":14},{"id":355,"damage":1},{"id":355,"damage":4},{"id":355,"damage":5},{"id":355,"damage":13},{"id":355,"damage":9},{"id":355,"damage":3},{"id":355,"damage":11},{"id":355,"damage":10},{"id":355,"damage":2},{"id":355,"damage":6},{"id":50},{"id":-156},{"id":-208},{"id":58},{"id":-200},{"id":-201},{"id":-202},{"id":-219},{"id":720},{"id":61},{"id":-196},{"id":-198},{"id":238,"damage":8},{"id":238},{"id":238,"damage":12},{"id":238,"damage":4},{"id":379},{"id":145},{"id":145,"damage":4},{"id":145,"damage":8},{"id":-195},{"id":116},{"id":47},{"id":-194},{"id":380},{"id":-213},{"id":54},{"id":146},{"id":130},{"id":-203},{"id":205},{"id":218},{"id":218,"damage":8},{"id":218,"damage":7},{"id":218,"damage":15},{"id":218,"damage":12},{"id":218,"damage":14},{"id":218,"damage":1},{"id":218,"damage":4},{"id":218,"damage":5},{"id":218,"damage":13},{"id":218,"damage":9},{"id":218,"damage":3},{"id":218,"damage":11},{"id":218,"damage":10},{"id":218,"damage":2},{"id":218,"damage":6},{"id":425},{"id":25},{"id":84},{"id":500},{"id":501},{"id":502},{"id":503},{"id":504},{"id":505},{"id":506},{"id":507},{"id":508},{"id":509},{"id":510},{"id":511},{"id":348},{"id":89},{"id":123},{"id":169},{"id":323},{"id":472},{"id":473},{"id":474},{"id":475},{"id":476},{"id":321},{"id":389},{"id":737},{"id":390},{"id":281},{"id":325},{"id":325,"damage":1},{"id":325,"damage":8},{"id":325,"damage":10},{"id":325,"damage":2},{"id":325,"damage":3},{"id":325,"damage":4},{"id":325,"damage":5},{"id":397,"damage":3},{"id":397,"damage":2},{"id":397,"damage":4},{"id":397,"damage":5},{"id":397},{"id":397,"damage":1},{"id":138},{"id":-206},{"id":-157},{"id":-197},{"id":120},{"id":263},{"id":263,"damage":1},{"id":264},{"id":452},{"id":265},{"id":371},{"id":266},{"id":388},{"id":406},{"id":337},{"id":336},{"id":405},{"id":409},{"id":422},{"id":465},{"id":467},{"id":468},{"id":470},{"id":287},{"id":288},{"id":318},{"id":289},{"id":334},{"id":415},{"id":414},{"id":385},{"id":369},{"id":377},{"id":378},{"id":376},{"id":437},{"id":445},{"id":370},{"id":341},{"id":368},{"id":381},{"id":399},{"id":208},{"id":426},{"id":339},{"id":340},{"id":386},{"id":36},{"id":-12},{"id":-13},{"id":-14},{"id":-15},{"id":-16},{"id":-17},{"id":-18},{"id":-19},{"id":-20},{"id":-21},{"id":-22},{"id":-23},{"id":-24},{"id":-25},{"id":-26},{"id":-27},{"id":-28},{"id":-29},{"id":-30},{"id":-31},{"id":-32},{"id":-33},{"id":-34},{"id":-35},{"id":-36},{"id":-37},{"id":-38},{"id":-39},{"id":-40},{"id":-41},{"id":-42},{"id":-43},{"id":-44},{"id":-45},{"id":-46},{"id":-47},{"id":-48},{"id":-49},{"id":-50},{"id":-51},{"id":-52},{"id":-53},{"id":-54},{"id":-55},{"id":-56},{"id":-57},{"id":-58},{"id":-59},{"id":-60},{"id":-61},{"id":-62},{"id":-63},{"id":-64},{"id":-65},{"id":-66},{"id":-67},{"id":-68},{"id":-69},{"id":-70},{"id":-71},{"id":-72},{"id":-73},{"id":-74},{"id":-75},{"id":-76},{"id":-77},{"id":-78},{"id":-79},{"id":-80},{"id":-81},{"id":-82},{"id":-83},{"id":-84},{"id":-85},{"id":-86},{"id":-87},{"id":-88},{"id":-89},{"id":-90},{"id":-91},{"id":-92},{"id":-93},{"id":-94},{"id":-95},{"id":-96},{"id":-97},{"id":-98},{"id":-99},{"id":-100},{"id":-101},{"id":-102},{"id":-103},{"id":-104},{"id":-105},{"id":-106},{"id":-107},{"id":-108},{"id":-109},{"id":-110},{"id":-111},{"id":-112},{"id":-113},{"id":-114},{"id":-115},{"id":-116},{"id":-117},{"id":-118},{"id":-119},{"id":-120},{"id":-121},{"id":-122},{"id":-123},{"id":-124},{"id":-125},{"id":-126},{"id":-127},{"id":-128},{"id":-129},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA="},{"id":403,"nbt_b64":"CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA="},{"id":333},{"id":333,"damage":1},{"id":333,"damage":2},{"id":333,"damage":3},{"id":333,"damage":4},{"id":333,"damage":5},{"id":66},{"id":27},{"id":28},{"id":126},{"id":328},{"id":342},{"id":408},{"id":407},{"id":331},{"id":152},{"id":76},{"id":69},{"id":143},{"id":-144},{"id":-141},{"id":-143},{"id":-140},{"id":-142},{"id":77},{"id":131},{"id":72},{"id":-154},{"id":-151},{"id":-153},{"id":-150},{"id":-152},{"id":70},{"id":147},{"id":148},{"id":251},{"id":151},{"id":356},{"id":404},{"id":410},{"id":125,"damage":3},{"id":23,"damage":3},{"id":33,"damage":1},{"id":29,"damage":1},{"id":46},{"id":421},{"id":-204},{"id":446},{"id":446,"damage":8},{"id":446,"damage":7},{"id":446,"damage":15},{"id":446,"damage":12},{"id":446,"damage":14},{"id":446,"damage":1},{"id":446,"damage":4},{"id":446,"damage":5},{"id":446,"damage":13},{"id":446,"damage":9},{"id":446,"damage":3},{"id":446,"damage":11},{"id":446,"damage":10},{"id":446,"damage":2},{"id":446,"damage":6},{"id":446,"damage":15,"nbt_b64":"CgAAAwQAVHlwZQEAAAAA"},{"id":434},{"id":434,"damage":1},{"id":434,"damage":2},{"id":434,"damage":3},{"id":434,"damage":4},{"id":434,"damage":5},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":401,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"},{"id":402,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d\/wA="},{"id":402,"damage":8,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H\/wA="},{"id":402,"damage":7,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d\/wA="},{"id":402,"damage":15,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw\/wA="},{"id":402,"damage":12,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6\/wA="},{"id":402,"damage":14,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5\/wA="},{"id":402,"damage":1,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w\/wA="},{"id":402,"damage":4,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8\/wA="},{"id":402,"damage":5,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ\/wA="},{"id":402,"damage":13,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H\/wA="},{"id":402,"damage":9,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz\/wA="},{"id":402,"damage":3,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD\/wA="},{"id":402,"damage":11,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+\/wA="},{"id":402,"damage":10,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA\/wA="},{"id":402,"damage":2,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe\/wA="},{"id":402,"damage":6,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW\/wA="}]<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;
use function assert;
use function count;
use function current;
use function get_class;
use function gettype;
use function is_a;
use function is_int;
use function is_object;
use function key;
use function next;
use function reset;
use function str_repeat;

use pocketmine\utils\Binary;

class CompoundTag extends NamedTag implements \ArrayAccess, \Iterator, \Countable{
	use NoDynamicFieldsTrait;

	/** @var NamedTag[] */
	private $value = [];

	/**
	 * @param string     $name
	 * @param NamedTag[] $value
	 */
	public function __construct(string $name = "", array $value = []){
		parent::__construct($name);

		foreach($value as $tag){
			$this->setTag($tag);
		}
	}

	/**
	 * @return int
	 */
	public function count() : int{
		return count($this->value);
	}

	/**
	 * @return int
	 */
	public function getCount(){
		return count($this->value);
	}

	/**
	 * @return NamedTag[]
	 */
	public function getValue(){
		return $this->value;
	}

	/*
	 * Here follows many functions of misery for the sake of type safety. We really needs generics in PHP :(
	 */

	/**
	 * Returns the tag with the specified name, or null if it does not exist.
	 *
	 * @phpstan-template T of NamedTag
	 *
	 * @param string $name
	 * @param string $expectedClass Class that extends NamedTag
	 * @phpstan-param class-string<T> $expectedClass
	 *
	 * @return NamedTag|null
	 * @phpstan-return T|null
	 * @throws \RuntimeException if the tag exists and is not of the expected type (if specified)
	 */
	public function getTag(string $name, string $expectedClass = NamedTag::class) : ?NamedTag{
		assert(is_a($expectedClass, NamedTag::class, true));
		$tag = $this->value[$name] ?? null;
		if($tag !== null and !($tag instanceof $expectedClass)){
			throw new \RuntimeException("Expected a tag of type $expectedClass, got " . get_class($tag));
		}

		return $tag;
	}

	/**
	 * Returns the ListTag with the specified name, or null if it does not exist. Triggers an exception if a tag exists
	 * with that name and the tag is not a ListTag.
	 *
	 * @param string $name
	 * @return ListTag|null
	 */
	public function getListTag(string $name) : ?ListTag{
		return $this->getTag($name, ListTag::class);
	}

	/**
	 * Returns the CompoundTag with the specified name, or null if it does not exist. Triggers an exception if a tag
	 * exists with that name and the tag is not a CompoundTag.
	 *
	 * @param string $name
	 * @return CompoundTag|null
	 */
	public function getCompoundTag(string $name) : ?CompoundTag{
		return $this->getTag($name, CompoundTag::class);
	}

	/**
	 * Sets the specified NamedTag as a child tag of the CompoundTag at the offset specified by the tag's name. If a tag
	 * already exists at the offset and the types do not match, an exception will be thrown unless $force is true.
	 *
	 * @param NamedTag $tag
	 * @param bool     $force
	 */
	public function setTag(NamedTag $tag, bool $force = false) : void{
		if(!$force){
			$existing = $this->value[$tag->__name] ?? null;
			if($existing !== null and !($tag instanceof $existing)){
				throw new \RuntimeException("Cannot set tag at \"$tag->__name\": tried to overwrite " . get_class($existing) . " with " . get_class($tag));
			}
		}
		$this->value[$tag->__name] = $tag;
	}

	/**
	 * Removes the child tags with the specified names from the CompoundTag. This function accepts a variadic list of
	 * strings.
	 *
	 * @param string[] ...$names
	 */
	public function removeTag(string ...$names) : void{
		foreach($names as $name){
			unset($this->value[$name]);
		}
	}

	/**
	 * Returns whether the CompoundTag contains a child tag with the specified name.
	 *
	 * @param string $name
	 * @param string $expectedClass
	 *
	 * @return bool
	 */
	public function hasTag(string $name, string $expectedClass = NamedTag::class) : bool{
		assert(is_a($expectedClass, NamedTag::class, true));
		return ($this->value[$name] ?? null) instanceof $expectedClass;
	}

	/**
	 * Returns the value of the child tag with the specified name, or $default if the tag doesn't exist. If the child
	 * tag is not of type $expectedType, an exception will be thrown, unless a default is given and $badTagDefault is
	 * true.
	 *
	 * @param string $name
	 * @param string $expectedClass
	 * @param mixed  $default
	 * @param bool   $badTagDefault Return the specified default if the tag is not of the expected type.
	 *
	 * @return mixed
	 */
	public function getTagValue(string $name, string $expectedClass, $default = null, bool $badTagDefault = false){
		$tag = $this->getTag($name, $badTagDefault ? NamedTag::class : $expectedClass);
		if($tag instanceof $expectedClass){
			return $tag->getValue();
		}

		if($default === null){
			throw new \RuntimeException("Tag with name \"$name\" " . ($tag !== null ? "not of expected type" : "not found") . " and no valid default value given");
		}

		return $default;
	}

	/*
	 * The following methods are wrappers around getTagValue() with type safety.
	 */

	/**
	 * @param string   $name
	 * @param int|null $default
	 * @param bool     $badTagDefault
	 *
	 * @return int
	 */
	public function getByte(string $name, ?int $default = null, bool $badTagDefault = false) : int{
		return $this->getTagValue($name, ByteTag::class, $default, $badTagDefault);
	}

	/**
	 * @param string   $name
	 * @param int|null $default
	 * @param bool     $badTagDefault
	 *
	 * @return int
	 */
	public function getShort(string $name, ?int $default = null, bool $badTagDefault = false) : int{
		return $this->getTagValue($name, ShortTag::class, $default, $badTagDefault);
	}

	/**
	 * @param string   $name
	 * @param int|null $default
	 * @param bool     $badTagDefault
	 *
	 * @return int
	 */
	public function getInt(string $name, ?int $default = null, bool $badTagDefault = false) : int{
		return $this->getTagValue($name, IntTag::class, $default, $badTagDefault);
	}

	/**
	 * @param string   $name
	 * @param int|null $default
	 * @param bool     $badTagDefault
	 *
	 * @return int
	 */
	public function getLong(string $name, ?int $default = null, bool $badTagDefault = false) : int{
		return $this->getTagValue($name, LongTag::class, $default, $badTagDefault);
	}

	/**
	 * @param string     $name
	 * @param float|null $default
	 * @param bool       $badTagDefault
	 *
	 * @return float
	 */
	public function getFloat(string $name, ?float $default = null, bool $badTagDefault = false) : float{
		return $this->getTagValue($name, FloatTag::class, $default, $badTagDefault);
	}

	/**
	 * @param string     $name
	 * @param float|null $default
	 * @param bool       $badTagDefault
	 *
	 * @return float
	 */
	public function getDouble(string $name, ?float $default = null, bool $badTagDefault = false) : float{
		return $this->getTagValue($name, DoubleTag::class, $default, $badTagDefault);
	}

	/**
	 * @param string      $name
	 * @param string|null $default
	 * @param bool        $badTagDefault
	 *
	 * @return string
	 */
	public function getByteArray(string $name, ?string $default = null, bool $badTagDefault = false) : string{
		return $this->getTagValue($name, ByteArrayTag::class, $default, $badTagDefault);
	}

	/**
	 * @param string      $name
	 * @param string|null $default
	 * @param bool        $badTagDefault
	 *
	 * @return string
	 */
	public function getString(string $name, ?string $default = null, bool $badTagDefault = false) : string{
		return $this->getTagValue($name, StringTag::class, $default, $badTagDefault);
	}

	/**
	 * @param string     $name
	 * @param int[]|null $default
	 * @param bool       $badTagDefault
	 *
	 * @return int[]
	 */
	public function getIntArray(string $name, ?array $default = null, bool $badTagDefault = false) : array{
		return $this->getTagValue($name, IntArrayTag::class, $default, $badTagDefault);
	}

	/*
	 * The following methods are wrappers around setTag() which create appropriate tag objects on the fly.
	 */

	/**
	 * @param string $name
	 * @param int    $value
	 * @param bool   $force
	 */
	public function setByte(string $name, int $value, bool $force = false) : void{
		$this->setTag(new ByteTag($name, $value), $force);
	}

	/**
	 * @param string $name
	 * @param int    $value
	 * @param bool   $force
	 */
	public function setShort(string $name, int $value, bool $force = false) : void{
		$this->setTag(new ShortTag($name, $value), $force);
	}

	/**
	 * @param string $name
	 * @param int    $value
	 * @param bool   $force
	 */
	public function setInt(string $name, int $value, bool $force = false) : void{
		$this->setTag(new IntTag($name, $value), $force);
	}

	/**
	 * @param string $name
	 * @param int    $value
	 * @param bool   $force
	 */
	public function setLong(string $name, int $value, bool $force = false) : void{
		$this->setTag(new LongTag($name, $value), $force);
	}

	/**
	 * @param string $name
	 * @param float  $value
	 * @param bool   $force
	 */
	public function setFloat(string $name, float $value, bool $force = false) : void{
		$this->setTag(new FloatTag($name, $value), $force);
	}

	/**
	 * @param string $name
	 * @param float  $value
	 * @param bool   $force
	 */
	public function setDouble(string $name, float $value, bool $force = false) : void{
		$this->setTag(new DoubleTag($name, $value), $force);
	}

	/**
	 * @param string $name
	 * @param string $value
	 * @param bool   $force
	 */
	public function setByteArray(string $name, string $value, bool $force = false) : void{
		$this->setTag(new ByteArrayTag($name, $value), $force);
	}

	/**
	 * @param string $name
	 * @param string $value
	 * @param bool   $force
	 */
	public function setString(string $name, string $value, bool $force = false) : void{
		$this->setTag(new StringTag($name, $value), $force);
	}

	/**
	 * @param string $name
	 * @param int[]  $value
	 * @param bool   $force
	 */
	public function setIntArray(string $name, array $value, bool $force = false) : void{
		$this->setTag(new IntArrayTag($name, $value), $force);
	}


	/**
	 * @param string $offset
	 *
	 * @return bool
	 */
	public function offsetExists($offset){
		return isset($this->value[$offset]);
	}

	/**
	 * @param string $offset
	 *
	 * @return mixed|null|\ArrayAccess
	 */
	public function offsetGet($offset){
		if(isset($this->value[$offset])){
			if($this->value[$offset] instanceof \ArrayAccess){
				return $this->value[$offset];
			}else{
				return $this->value[$offset]->getValue();
			}
		}

		assert(false, "Offset $offset not found");

		return null;
	}

	/**
	 * @param string   $offset
	 * @param NamedTag $value
	 *
	 * @throws \InvalidArgumentException if offset is null
	 * @throws \TypeError if $value is not a NamedTag object
	 */
	public function offsetSet($offset, $value){
		if($offset === null){
			throw new \InvalidArgumentException("Array access push syntax is not supported");
		}
		if($value instanceof NamedTag){
			if($offset !== $value->getName()){
				throw new \UnexpectedValueException("Given tag has a name which does not match the offset given (offset: \"$offset\", tag name: \"" . $value->getName() . "\")");
			}
			$this->value[$offset] = $value;
		}else{
			throw new \TypeError("Value set by ArrayAccess must be an instance of " . NamedTag::class . ", got " . (is_object($value) ? " instance of " . get_class($value) : gettype($value)));
		}
	}

	public function offsetUnset($offset){
		unset($this->value[$offset]);
	}

	public function getType() : int{
		return NBT::TAG_Compound;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = [];
		$tracker->protectDepth(function() use($nbt, $tracker){
			do{
				$tag = $nbt->readTag($tracker);
				if($tag !== null){
					if(isset($this->value[$tag->__name])){
						throw new \UnexpectedValueException("Duplicate key \"$tag->__name\"");
					}
					$this->value[$tag->__name] = $tag;
				}
			}while($tag !== null);
		});
	}

	public function write(NBTStream $nbt) : void{
		foreach($this->value as $tag){
			$nbt->writeTag($tag);
		}
		$nbt->writeEnd();
	}

	public function toString(int $indentation = 0) : string{
		$str = str_repeat("  ", $indentation) . get_class($this) . ": " . ($this->__name !== "" ? "name='$this->__name', " : "") . "value={\n";
		foreach($this->value as $tag){
			$str .= $tag->toString($indentation + 1) . "\n";
		}
		return $str . str_repeat("  ", $indentation) . "}";
	}

	public function __clone(){
		foreach($this->value as $key => $tag){
			$this->value[$key] = $tag->safeClone();
		}
	}

	public function next() : void{
		next($this->value);
	}

	/**
	 * @return bool
	 */
	public function valid() : bool{
		return key($this->value) !== null;
	}

	/**
	 * @return string|null
	 */
	public function key() : ?string{
		$k = key($this->value);
		if(is_int($k)){
			/* PHP arrays are idiotic and cast keys like "1" to int(1)
			 * TODO: perhaps we should consider using a \Ds\Map for this?
			 */
			$k = (string) $k;
		}

		return $k;
	}

	/**
	 * @return NamedTag|null
	 */
	public function current() : ?NamedTag{
		return current($this->value) ?: null;
	}

	public function rewind() : void{
		reset($this->value);
	}

	protected function equalsValue(NamedTag $that) : bool{
		if(!($that instanceof $this) or $this->count() !== $that->count()){
			return false;
		}

		foreach($this as $k => $v){
			$other = $that->getTag($k);
			if($other === null or !$v->equals($other)){
				return false;
			}
		}

		return true;
	}

	/**
	 * Returns a copy of this CompoundTag with values from the given CompoundTag merged into it. Tags that exist both in
	 * this tag and the other will be overwritten by the tag in the other.
	 *
	 * This deep-clones all tags.
	 *
	 * @param CompoundTag $other
	 *
	 * @return CompoundTag
	 */
	public function merge(CompoundTag $other) : CompoundTag{
		$new = clone $this;

		foreach($other as $namedTag){
			$new->setTag(clone $namedTag);
		}

		return $new;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;


use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;
use function get_class;
use function str_repeat;
use function strlen;

abstract class NamedTag{
	/** @var string */
	protected $__name;

	/**
	 * Used for recursive cloning protection when cloning tags with child tags.
	 * @var bool
	 */
	protected $cloning = false;

	/**
	 * @param string $name
	 * @throws \InvalidArgumentException if the name is too long
	 */
	public function __construct(string $name = ""){
		if(strlen($name) > 32767){
			throw new \InvalidArgumentException("Tag name cannot be more than 32767 bytes, got length " . strlen($name));
		}
		$this->__name = $name;
	}

	/**
	 * @return string
	 */
	public function getName() : string{
		return $this->__name;
	}

	/**
	 * @param string $name
	 */
	public function setName(string $name) : void{
		$this->__name = $name;
	}

	abstract public function getValue();

	abstract public function getType() : int;

	abstract public function write(NBTStream $nbt) : void;

	abstract public function read(NBTStream $nbt, ReaderTracker $tracker) : void;

	public function __toString(){
		return $this->toString();
	}

	public function toString(int $indentation = 0) : string{
		return str_repeat("  ", $indentation) . get_class($this) . ": " . ($this->__name !== "" ? "name='$this->__name', " : "") . "value='" . (string) $this->getValue() . "'";
	}

	/**
	 * Clones this tag safely, detecting recursive dependencies which would otherwise cause an infinite cloning loop.
	 * Used for cloning tags in tags that have children.
	 *
	 * @return NamedTag
	 * @throws \RuntimeException if a recursive dependency was detected
	 */
	public function safeClone() : NamedTag{
		if($this->cloning){
			throw new \RuntimeException("Recursive NBT tag dependency detected");
		}
		$this->cloning = true;

		$retval = clone $this;

		$this->cloning = false;
		$retval->cloning = false;

		return $retval;
	}

	/**
	 * Compares this NamedTag to the given NamedTag and determines whether or not they are equal, based on name, type
	 * and value.
	 *
	 * @param NamedTag $that
	 *
	 * @return bool
	 */
	public function equals(NamedTag $that) : bool{
		return $this->__name === $that->__name and $this->equalsValue($that);
	}

	/**
	 * Compares this NamedTag to the given NamedTag and determines whether they are equal, based on type and value only.
	 * Complex tag types should override this to provide proper value comparison.
	 *
	 * @param NamedTag $that
	 *
	 * @return bool
	 */
	protected function equalsValue(NamedTag $that) : bool{
		return $that instanceof $this and $this->getValue() === $that->getValue();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use function get_class;

trait NoDynamicFieldsTrait{

	private function throw(string $field) : \RuntimeException{
		return new \RuntimeException("Cannot access dynamic field \"$field\": Dynamic field access on " . get_class($this) . " is no longer supported");
	}

	public function __get($name){
		throw $this->throw($name);
	}

	public function __set($name, $value){
		throw $this->throw($name);
	}

	public function __isset($name){
		throw $this->throw($name);
	}

	public function __unset($name){
		throw $this->throw($name);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block\utils;

class ColorBlockMetaHelper{

	public static function getColorFromMeta(int $meta) : string{
		static $names = [
			0 => "White",
			1 => "Orange",
			2 => "Magenta",
			3 => "Light Blue",
			4 => "Yellow",
			5 => "Lime",
			6 => "Pink",
			7 => "Gray",
			8 => "Light Gray",
			9 => "Cyan",
			10 => "Purple",
			11 => "Blue",
			12 => "Brown",
			13 => "Green",
			14 => "Red",
			15 => "Black"
		];

		return $names[$meta] ?? "Unknown";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt;

use function array_values;
use function count;
use function pack;
use function unpack;

use pocketmine\utils\Binary;

class LittleEndianNBTStream extends NBTStream{

	public function getShort() : int{
		return (\unpack("v", $this->get(2))[1]);
	}

	public function getSignedShort() : int{
		return (\unpack("v", $this->get(2))[1] << 48 >> 48);
	}

	public function putShort(int $v) : void{
		($this->buffer .= (\pack("v", $v)));
	}

	public function getInt() : int{
		return (\unpack("V", $this->get(4))[1] << 32 >> 32);
	}

	public function putInt(int $v) : void{
		($this->buffer .= (\pack("V", $v)));
	}

	public function getLong() : int{
		return Binary::readLLong($this->get(8));
	}

	public function putLong(int $v) : void{
		($this->buffer .= (\pack("VV", $v & 0xFFFFFFFF, $v >> 32)));
	}

	public function getFloat() : float{
		return (\unpack("g", $this->get(4))[1]);
	}

	public function putFloat(float $v) : void{
		($this->buffer .= (\pack("g", $v)));
	}

	public function getDouble() : float{
		return (\unpack("e", $this->get(8))[1]);
	}

	public function putDouble(float $v) : void{
		($this->buffer .= (\pack("e", $v)));
	}

	public function getIntArray() : array{
		$len = $this->getInt();
		return array_values(unpack("V*", $this->get($len * 4)));
	}

	public function putIntArray(array $array) : void{
		$this->putInt(count($array));
		($this->buffer .= pack("V*", ...$array));
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt;

use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntArrayTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\NamedTag;
use pocketmine\nbt\tag\StringTag;
use function call_user_func;
use function is_array;
use function is_bool;
use function is_float;
use function is_int;
use function is_numeric;
use function is_string;
use function strlen;
use function substr;
use function zlib_decode;
use function zlib_encode;
use pocketmine\utils\BinaryDataException;

use pocketmine\utils\Binary;

/**
 * Base Named Binary Tag encoder/decoder
 */
abstract class NBTStream{

	public $buffer = "";
	public $offset = 0;

	/**
	 * @param int|bool $len
	 *
	 * @return string
	 *
	 * @throws BinaryDataException if there are not enough bytes left in the buffer
	 */
	public function get($len) : string{
		if($len === 0){
			return "";
		}

		$buflen = strlen($this->buffer);
		if($len === true){
			$str = substr($this->buffer, $this->offset);
			$this->offset = $buflen;
			return $str;
		}
		if($len < 0){
			$this->offset = $buflen - 1;
			return "";
		}
		$remaining = $buflen - $this->offset;
		if($remaining < $len){
			throw new BinaryDataException("Not enough bytes left in buffer: need $len, have $remaining");
		}

		return $len === 1 ? $this->buffer[$this->offset++] : substr($this->buffer, ($this->offset += $len) - $len, $len);
	}

	public function put(string $v) : void{
		$this->buffer .= $v;
	}

	public function feof() : bool{
		return !isset($this->buffer[$this->offset]);
	}

	/**
	 * Decodes NBT from the given binary string and returns it.
	 *
	 * @param string $buffer
	 * @param bool   $doMultiple Whether to keep reading after the first tag if there are more bytes in the buffer
	 * @param int    $offset reference parameter
	 * @param int    $maxDepth
	 *
	 * @return NamedTag|NamedTag[]
	 */
	public function read(string $buffer, bool $doMultiple = false, int &$offset = 0, int $maxDepth = 0){
		$this->offset = &$offset;
		$this->buffer = $buffer;
		$data = $this->readTag(new ReaderTracker($maxDepth));

		if($data === null){
			throw new \InvalidArgumentException("Found TAG_End at the start of buffer");
		}

		if($doMultiple and !$this->feof()){
			$data = [$data];
			do{
				$tag = $this->readTag(new ReaderTracker($maxDepth));
				if($tag !== null){
					$data[] = $tag;
				}
			}while(!$this->feof());
		}
		$this->buffer = "";

		return $data;
	}

	/**
	 * Decodes NBT from the given compressed binary string and returns it. Anything decodable by zlib_decode() can be
	 * processed.
	 *
	 * @param string $buffer
	 *
	 * @return NamedTag|NamedTag[]
	 */
	public function readCompressed(string $buffer){
		return $this->read(zlib_decode($buffer));
	}

	/**
	 * @param NamedTag|NamedTag[] $data
	 *
	 * @return bool|string
	 */
	public function write($data){
		$this->offset = 0;
		$this->buffer = "";

		if($data instanceof NamedTag){
			$this->writeTag($data);

			return $this->buffer;
		}elseif(is_array($data)){
			foreach($data as $tag){
				$this->writeTag($tag);
			}
			return $this->buffer;
		}

		return false;
	}

	/**
	 * @param NamedTag|NamedTag[] $data
	 * @param int                 $compression
	 * @param int                 $level
	 *
	 * @return bool|string
	 */
	public function writeCompressed($data, int $compression = ZLIB_ENCODING_GZIP, int $level = 7){
		if(($write = $this->write($data)) !== false){
			return zlib_encode($write, $compression, $level);
		}

		return false;
	}

	public function readTag(ReaderTracker $tracker) : ?NamedTag{
		$tagType = (\ord($this->get(1)));
		if($tagType === NBT::TAG_End){
			return null;
		}

		$tag = NBT::createTag($tagType);
		$tag->setName($this->getString());
		$tag->read($this, $tracker);

		return $tag;
	}

	public function writeTag(NamedTag $tag) : void{
		($this->buffer .= \chr($tag->getType()));
		$this->putString($tag->getName());
		$tag->write($this);
	}

	public function writeEnd() : void{
		($this->buffer .= \chr(NBT::TAG_End));
	}

	public function getByte() : int{
		return (\ord($this->get(1)));
	}

	public function getSignedByte() : int{
		return (\ord($this->get(1)) << 56 >> 56);
	}

	public function putByte(int $v) : void{
		$this->buffer .= (\chr($v));
	}

	abstract public function getShort() : int;

	abstract public function getSignedShort() : int;

	abstract public function putShort(int $v) : void;


	abstract public function getInt() : int;

	abstract public function putInt(int $v) : void;

	abstract public function getLong() : int;

	abstract public function putLong(int $v) : void;


	abstract public function getFloat() : float;

	abstract public function putFloat(float $v) : void;


	abstract public function getDouble() : float;

	abstract public function putDouble(float $v) : void;

	/**
	 * @return string
	 * @throws \UnexpectedValueException if a too-large string is found (length may be invalid)
	 */
	public function getString() : string{
		return $this->get(self::checkReadStringLength($this->getShort()));
	}

	/**
	 * @param string $v
	 * @throws \InvalidArgumentException if the string is too long
	 */
	public function putString(string $v) : void{
		$this->putShort(self::checkWriteStringLength(strlen($v)));
		($this->buffer .= $v);
	}

	/**
	 * @param int $len
	 * @return int
	 * @throws \UnexpectedValueException
	 */
	protected static function checkReadStringLength(int $len) : int{
		if($len > 32767){
			throw new \UnexpectedValueException("NBT string length too large ($len > 32767)");
		}
		return $len;
	}

	/**
	 * @param int $len
	 * @return int
	 * @throws \InvalidArgumentException
	 */
	protected static function checkWriteStringLength(int $len) : int{
		if($len > 32767){
			throw new \InvalidArgumentException("NBT string length too large ($len > 32767)");
		}
		return $len;
	}

	/**
	 * @return int[]
	 */
	abstract public function getIntArray() : array;

	/**
	 * @param int[] $array
	 */
	abstract public function putIntArray(array $array) : void;


	/**
	 * @param CompoundTag $data
	 *
	 * @return array
	 */
	public static function toArray(CompoundTag $data) : array{
		$array = [];
		self::tagToArray($array, $data);
		return $array;
	}

	/**
	 * @param mixed[]                         $data
	 * @param CompoundTag|ListTag|IntArrayTag $tag
	 */
	private static function tagToArray(array &$data, NamedTag $tag) : void{
		foreach($tag as $key => $value){
			if($value instanceof CompoundTag or $value instanceof ListTag or $value instanceof IntArrayTag){
				$data[$key] = [];
				self::tagToArray($data[$key], $value);
			}else{
				$data[$key] = $value->getValue();
			}
		}
	}

	public static function fromArrayGuesser(string $key, $value) : ?NamedTag{
		if(is_int($value)){
			return new IntTag($key, $value);
		}elseif(is_float($value)){
			return new FloatTag($key, $value);
		}elseif(is_string($value)){
			return new StringTag($key, $value);
		}elseif(is_bool($value)){
			return new ByteTag($key, $value ? 1 : 0);
		}

		return null;
	}

	private static function tagFromArray(NamedTag $tag, array $data, callable $guesser) : void{
		foreach($data as $key => $value){
			if(is_array($value)){
				$isNumeric = true;
				$isIntArray = true;
				foreach($value as $k => $v){
					if(!is_numeric($k)){
						$isNumeric = false;
						break;
					}elseif(!is_int($v)){
						$isIntArray = false;
					}
				}
				$tag[$key] = $isNumeric ? ($isIntArray ? new IntArrayTag($key, []) : new ListTag($key, [])) : new CompoundTag($key, []);
				self::tagFromArray($tag->{$key}, $value, $guesser);
			}else{
				$v = call_user_func($guesser, $key, $value);
				if($v instanceof NamedTag){
					$tag[$key] = $v;
				}
			}
		}
	}

	/**
	 * @param array         $data
	 * @param callable|null $guesser
	 *
	 * @return CompoundTag
	 */
	public static function fromArray(array $data, callable $guesser = null) : CompoundTag{
		$tag = new CompoundTag("", []);
		self::tagFromArray($tag, $data, $guesser ?? [self::class, "fromArrayGuesser"]);
		return $tag;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt;

class ReaderTracker{

	/** @var int */
	private $maxDepth;
	/** @var int */
	private $currentDepth = 0;

	public function __construct(int $maxDepth){
		$this->maxDepth = $maxDepth;
	}

	/**
	 * @param \Closure $execute
	 *
	 * @throws \UnexpectedValueException if the recursion depth is too deep
	 */
	public function protectDepth(\Closure $execute) : void{
		if($this->maxDepth > 0 and ++$this->currentDepth > $this->maxDepth){
			throw new \UnexpectedValueException("Nesting level too deep: reached max depth of $this->maxDepth tags");
		}
		try{
			$execute();
		}finally{
			--$this->currentDepth;
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Named Binary Tag handling classes
 */
namespace pocketmine\nbt;

use pocketmine\nbt\tag\ByteArrayTag;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntArrayTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\LongTag;
use pocketmine\nbt\tag\NamedTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\nbt\tag\StringTag;

abstract class NBT{

	public const TAG_End = 0;
	public const TAG_Byte = 1;
	public const TAG_Short = 2;
	public const TAG_Int = 3;
	public const TAG_Long = 4;
	public const TAG_Float = 5;
	public const TAG_Double = 6;
	public const TAG_ByteArray = 7;
	public const TAG_String = 8;
	public const TAG_List = 9;
	public const TAG_Compound = 10;
	public const TAG_IntArray = 11;

	/**
	 * @param int $type
	 *
	 * @return NamedTag
	 */
	public static function createTag(int $type) : NamedTag{
		switch($type){
			case self::TAG_Byte:
				return new ByteTag();
			case self::TAG_Short:
				return new ShortTag();
			case self::TAG_Int:
				return new IntTag();
			case self::TAG_Long:
				return new LongTag();
			case self::TAG_Float:
				return new FloatTag();
			case self::TAG_Double:
				return new DoubleTag();
			case self::TAG_ByteArray:
				return new ByteArrayTag();
			case self::TAG_String:
				return new StringTag();
			case self::TAG_List:
				return new ListTag();
			case self::TAG_Compound:
				return new CompoundTag();
			case self::TAG_IntArray:
				return new IntArrayTag();
			default:
				throw new \InvalidArgumentException("Unknown NBT tag type $type");
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;
use function get_class;
use function gettype;
use function is_object;
use function str_repeat;

use pocketmine\utils\Binary;

class ListTag extends NamedTag implements \ArrayAccess, \Countable, \Iterator{
	use NoDynamicFieldsTrait;

	/** @var int */
	private $tagType;
	/** @var \SplDoublyLinkedList|NamedTag[] */
	private $value;

	/**
	 * @param string     $name
	 * @param NamedTag[] $value
	 * @param int        $tagType
	 */
	public function __construct(string $name = "", array $value = [], int $tagType = NBT::TAG_End){
		parent::__construct($name);

		$this->tagType = $tagType;
		$this->value = new \SplDoublyLinkedList();
		foreach($value as $tag){
			$this->push($tag);
		}
	}

	/**
	 * @return NamedTag[]
	 */
	public function getValue() : array{
		$value = [];
		foreach($this->value as $k => $v){
			$value[$k] = $v;
		}

		return $value;
	}

	/**
	 * Returns an array of tag values inserted into this list. ArrayAccess-implementing tags are returned as themselves
	 * (such as ListTag and CompoundTag) and others are returned as primitive values or arrays.
	 *
	 * @return array
	 */
	public function getAllValues() : array{
		$result = [];
		foreach($this->value as $tag){
			if($tag instanceof \ArrayAccess){
				$result[] = $tag;
			}else{
				$result[] = $tag->getValue();
			}
		}

		return $result;
	}

	/**
	 * @param int $offset
	 *
	 * @return bool
	 */
	public function offsetExists($offset) : bool{
		return isset($this->value[$offset]);
	}

	/**
	 * @param int $offset
	 *
	 * @return CompoundTag|ListTag|mixed
	 */
	public function offsetGet($offset){
		/** @var NamedTag|null $value */
		$value = $this->value[$offset] ?? null;

		if($value instanceof \ArrayAccess){
			return $value;
		}elseif($value !== null){
			return $value->getValue();
		}

		return null;
	}

	/**
	 * @param int|null $offset
	 * @param NamedTag $value
	 *
	 * @throws \TypeError if an incompatible tag type is given
	 * @throws \TypeError if $value is not a NamedTag object
	 */
	public function offsetSet($offset, $value) : void{
		if($value instanceof NamedTag){
			$this->checkTagType($value);
			$this->value[$offset] = $value;
		}else{
			throw new \TypeError("Value set by ArrayAccess must be an instance of " . NamedTag::class . ", got " . (is_object($value) ? " instance of " . get_class($value) : gettype($value)));
		}
	}

	/**
	 * @param int $offset
	 */
	public function offsetUnset($offset) : void{
		unset($this->value[$offset]);
	}

	/**
	 * @return int
	 */
	public function count() : int{
		return $this->value->count();
	}

	/**
	 * @return int
	 */
	public function getCount() : int{
		return $this->value->count();
	}

	/**
	 * Appends the specified tag to the end of the list.
	 *
	 * @param NamedTag $tag
	 */
	public function push(NamedTag $tag) : void{
		$this->checkTagType($tag);
		$this->value->push($tag);
	}

	/**
	 * Removes the last tag from the list and returns it.
	 *
	 * @return NamedTag
	 */
	public function pop() : NamedTag{
		return $this->value->pop();
	}

	/**
	 * Adds the specified tag to the start of the list.
	 *
	 * @param NamedTag $tag
	 */
	public function unshift(NamedTag $tag) : void{
		$this->checkTagType($tag);
		$this->value->unshift($tag);
	}

	/**
	 * Removes the first tag from the list and returns it.
	 *
	 * @return NamedTag
	 */
	public function shift() : NamedTag{
		return $this->value->shift();
	}

	/**
	 * Inserts a tag into the list between existing tags, at the specified offset. Later values in the list are moved up
	 * by 1 position.
	 *
	 * @param int      $offset
	 * @param NamedTag $tag
	 *
	 * @throws \OutOfRangeException if the offset is not within the bounds of the list
	 */
	public function insert(int $offset, NamedTag $tag){
		$this->checkTagType($tag);
		$this->value->add($offset, $tag);
	}

	/**
	 * Removes a value from the list. All later tags in the list are moved down by 1 position.
	 *
	 * @param int $offset
	 */
	public function remove(int $offset) : void{
		unset($this->value[$offset]);
	}

	/**
	 * Returns the tag at the specified offset.
	 *
	 * @param int $offset
	 *
	 * @return NamedTag
	 * @throws \OutOfRangeException if the offset is not within the bounds of the list
	 */
	public function get(int $offset) : NamedTag{
		return $this->value[$offset];
	}

	/**
	 * Returns the element in the first position of the list, without removing it.
	 *
	 * @return NamedTag
	 */
	public function first() : NamedTag{
		return $this->value->bottom();
	}

	/**
	 * Returns the element in the last position in the list (the end), without removing it.
	 *
	 * @return NamedTag
	 */
	public function last() : NamedTag{
		return $this->value->top();
	}

	/**
	 * Overwrites the tag at the specified offset.
	 *
	 * @param int      $offset
	 * @param NamedTag $tag
	 *
	 * @throws \OutOfRangeException if the offset is not within the bounds of the list
	 */
	public function set(int $offset, NamedTag $tag) : void{
		$this->checkTagType($tag);
		$this->value[$offset] = $tag;
	}

	/**
	 * Returns whether a tag exists at the specified offset.
	 *
	 * @param int $offset
	 *
	 * @return bool
	 */
	public function isset(int $offset) : bool{
		return isset($this->value[$offset]);
	}

	/**
	 * Returns whether there are any tags in the list.
	 *
	 * @return bool
	 */
	public function empty() : bool{
		return $this->value->isEmpty();
	}

	public function getType() : int{
		return NBT::TAG_List;
	}

	/**
	 * Returns the type of tag contained in this list.
	 *
	 * @return int
	 */
	public function getTagType() : int{
		return $this->tagType;
	}

	/**
	 * Sets the type of tag that can be added to this list. If TAG_End is used, the type will be auto-detected from the
	 * first tag added to the list.
	 *
	 * @param int $type
	 * @throws \LogicException if the list is not empty
	 */
	public function setTagType(int $type){
		if(!$this->value->isEmpty()){
			throw new \LogicException("Cannot change tag type of non-empty ListTag");
		}
		$this->tagType = $type;
	}

	/**
	 * Type-checks the given NamedTag for addition to the list, updating the list tag type as appropriate.
	 * @param NamedTag $tag
	 *
	 * @throws \TypeError if the tag type is not compatible.
	 */
	private function checkTagType(NamedTag $tag) : void{
		$type = $tag->getType();
		if($type !== $this->tagType){
			if($this->tagType === NBT::TAG_End){
				$this->tagType = $type;
			}else{
				throw new \TypeError("Invalid tag of type " . get_class($tag) . " assigned to ListTag, expected " . get_class(NBT::createTag($this->tagType)));
			}
		}
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = new \SplDoublyLinkedList();
		$this->tagType = (\ord($nbt->get(1)));
		$size = $nbt->getInt();

		if($size > 0){
			if($this->tagType === NBT::TAG_End){
				throw new \UnexpectedValueException("Unexpected non-empty list of TAG_End");
			}

			$tracker->protectDepth(function() use($nbt, $tracker, $size){
				$tagBase = NBT::createTag($this->tagType);
				for($i = 0; $i < $size; ++$i){
					$tag = clone $tagBase;
					$tag->read($nbt, $tracker);
					$this->value->push($tag);
				}
			});
		}else{
			$this->tagType = NBT::TAG_End; //Some older NBT implementations used TAG_Byte for empty lists.
		}
	}

	public function write(NBTStream $nbt) : void{
		($nbt->buffer .= \chr($this->tagType));
		$nbt->putInt($this->value->count());
		/** @var NamedTag $tag */
		foreach($this->value as $tag){
			$tag->write($nbt);
		}
	}

	public function toString(int $indentation = 0) : string{
		$str = str_repeat("  ", $indentation) . get_class($this) . ": " . ($this->__name !== "" ? "name='$this->__name', " : "") . "value={\n";
		/** @var NamedTag $tag */
		foreach($this->value as $tag){
			$str .= $tag->toString($indentation + 1) . "\n";
		}
		return $str . str_repeat("  ", $indentation) . "}";
	}

	public function __clone(){
		$new = new \SplDoublyLinkedList();

		foreach($this->value as $tag){
			$new->push($tag->safeClone());
		}

		$this->value = $new;
	}

	public function next() : void{
		$this->value->next();
	}

	/**
	 * @return bool
	 */
	public function valid() : bool{
		return $this->value->valid();
	}

	/**
	 * @return NamedTag|null
	 */
	public function current() : ?NamedTag{
		return $this->value->current();
	}

	/**
	 * @return int
	 */
	public function key() : int{
		return (int) $this->value->key();
	}

	public function rewind() : void{
		$this->value->rewind();
	}

	protected function equalsValue(NamedTag $that) : bool{
		if(!($that instanceof $this) or $this->count() !== $that->count()){
			return false;
		}

		foreach($this as $k => $v){
			if(!$v->equalsValue($that->get($k))){ //ListTag members don't have names, don't bother checking it
				return false;
			}
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;

use pocketmine\utils\Binary;

class ShortTag extends NamedTag{
	/** @var int */
	private $value;

	/**
	 * @param string $name
	 * @param int    $value
	 */
	public function __construct(string $name = "", int $value = 0){
		parent::__construct($name);
		if($value < -0x8000 or $value > 0x7fff){
			throw new \InvalidArgumentException("Value $value is too large!");
		}
		$this->value = $value;
	}

	public function getType() : int{
		return NBT::TAG_Short;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = $nbt->getSignedShort();
	}

	public function write(NBTStream $nbt) : void{
		$nbt->putShort($this->value);
	}

	/**
	 * @return int
	 */
	public function getValue() : int{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;

use pocketmine\utils\Binary;

class IntTag extends NamedTag{
	/** @var int */
	private $value;

	/**
	 * @param string $name
	 * @param int    $value
	 */
	public function __construct(string $name = "", int $value = 0){
		parent::__construct($name);
		if($value < -0x80000000 or $value > 0x7fffffff){
			throw new \InvalidArgumentException("Value $value is too large!");
		}
		$this->value = $value;
	}

	public function getType() : int{
		return NBT::TAG_Int;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = $nbt->getInt();
	}

	public function write(NBTStream $nbt) : void{
		$nbt->putInt($this->value);
	}

	/**
	 * @return int
	 */
	public function getValue() : int{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;

use pocketmine\utils\Binary;

class ByteTag extends NamedTag{
	/** @var int */
	private $value;

	/**
	 * @param string $name
	 * @param int    $value
	 */
	public function __construct(string $name = "", int $value = 0){
		parent::__construct($name);
		if($value < -128 or $value > 127){
			throw new \InvalidArgumentException("Value $value is too large!");
		}
		$this->value = $value;
	}

	public function getType() : int{
		return NBT::TAG_Byte;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = $nbt->getSignedByte();
	}

	public function write(NBTStream $nbt) : void{
		($nbt->buffer .= \chr($this->value));
	}

	/**
	 * @return int
	 */
	public function getValue() : int{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;
use function strlen;

use pocketmine\utils\Binary;

class ByteArrayTag extends NamedTag{
	/** @var string */
	private $value;

	/**
	 * @param string $name
	 * @param string $value
	 */
	public function __construct(string $name = "", string $value = ""){
		parent::__construct($name);
		$this->value = $value;
	}

	public function getType() : int{
		return NBT::TAG_ByteArray;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = $nbt->get($nbt->getInt());
	}

	public function write(NBTStream $nbt) : void{
		$nbt->putInt(strlen($this->value));
		($nbt->buffer .= $this->value);
	}

	/**
	 * @return string
	 */
	public function getValue() : string{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\block\Block;
use pocketmine\level\ChunkManager;
use pocketmine\level\generator\populator\Populator;
use pocketmine\utils\Random;

abstract class Biome{

	public const OCEAN = 0;
	public const PLAINS = 1;
	public const DESERT = 2;
	public const MOUNTAINS = 3;
	public const FOREST = 4;
	public const TAIGA = 5;
	public const SWAMP = 6;
	public const RIVER = 7;

	public const HELL = 8;

	public const ICE_PLAINS = 12;

	public const SMALL_MOUNTAINS = 20;

	public const BIRCH_FOREST = 27;

	public const MAX_BIOMES = 256;

	/**
	 * @var Biome[]|\SplFixedArray
	 * @phpstan-var \SplFixedArray<Biome>
	 */
	private static $biomes;

	/** @var int */
	private $id;
	/** @var bool */
	private $registered = false;

	/** @var Populator[] */
	private $populators = [];

	/** @var int */
	private $minElevation;
	/** @var int */
	private $maxElevation;

	/** @var Block[] */
	private $groundCover = [];

	/** @var float */
	protected $rainfall = 0.5;
	/** @var float */
	protected $temperature = 0.5;

	/**
	 * @return void
	 */
	protected static function register(int $id, Biome $biome){
		self::$biomes[$id] = $biome;
		$biome->setId($id);
	}

	/**
	 * @return void
	 */
	public static function init(){
		self::$biomes = new \SplFixedArray(self::MAX_BIOMES);

		self::register(self::OCEAN, new OceanBiome());
		self::register(self::PLAINS, new PlainBiome());
		self::register(self::DESERT, new DesertBiome());
		self::register(self::MOUNTAINS, new MountainsBiome());
		self::register(self::FOREST, new ForestBiome());
		self::register(self::TAIGA, new TaigaBiome());
		self::register(self::SWAMP, new SwampBiome());
		self::register(self::RIVER, new RiverBiome());

		self::register(self::ICE_PLAINS, new IcePlainsBiome());

		self::register(self::SMALL_MOUNTAINS, new SmallMountainsBiome());

		self::register(self::BIRCH_FOREST, new ForestBiome(ForestBiome::TYPE_BIRCH));
	}

	public static function getBiome(int $id) : Biome{
		if(self::$biomes[$id] === null){
			self::register($id, new UnknownBiome());
		}
		return self::$biomes[$id];
	}

	/**
	 * @return void
	 */
	public function clearPopulators(){
		$this->populators = [];
	}

	/**
	 * @return void
	 */
	public function addPopulator(Populator $populator){
		$this->populators[] = $populator;
	}

	/**
	 * @return void
	 */
	public function populateChunk(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){
		foreach($this->populators as $populator){
			$populator->populate($level, $chunkX, $chunkZ, $random);
		}
	}

	/**
	 * @return Populator[]
	 */
	public function getPopulators() : array{
		return $this->populators;
	}

	/**
	 * @return void
	 */
	public function setId(int $id){
		if(!$this->registered){
			$this->registered = true;
			$this->id = $id;
		}
	}

	public function getId() : int{
		return $this->id;
	}

	abstract public function getName() : string;

	public function getMinElevation() : int{
		return $this->minElevation;
	}

	public function getMaxElevation() : int{
		return $this->maxElevation;
	}

	/**
	 * @return void
	 */
	public function setElevation(int $min, int $max){
		$this->minElevation = $min;
		$this->maxElevation = $max;
	}

	/**
	 * @return Block[]
	 */
	public function getGroundCover() : array{
		return $this->groundCover;
	}

	/**
	 * @param Block[] $covers
	 *
	 * @return void
	 */
	public function setGroundCover(array $covers){
		$this->groundCover = $covers;
	}

	public function getTemperature() : float{
		return $this->temperature;
	}

	public function getRainfall() : float{
		return $this->rainfall;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\level\generator\populator\TallGrass;

class OceanBiome extends Biome{

	public function __construct(){
		$this->setGroundCover([
			BlockFactory::get(Block::GRAVEL),
			BlockFactory::get(Block::GRAVEL),
			BlockFactory::get(Block::GRAVEL),
			BlockFactory::get(Block::GRAVEL),
			BlockFactory::get(Block::GRAVEL)
		]);

		$tallGrass = new TallGrass();
		$tallGrass->setBaseAmount(5);

		$this->addPopulator($tallGrass);

		$this->setElevation(46, 58);

		$this->temperature = 0.5;
		$this->rainfall = 0.5;
	}

	public function getName() : string{
		return "Ocean";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\generator\populator;

use pocketmine\block\Block;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;

class TallGrass extends Populator{
	/** @var ChunkManager */
	private $level;
	/** @var int */
	private $randomAmount = 1;
	/** @var int */
	private $baseAmount = 0;

	/**
	 * @param int $amount
	 *
	 * @return void
	 */
	public function setRandomAmount($amount){
		$this->randomAmount = $amount;
	}

	/**
	 * @param int $amount
	 *
	 * @return void
	 */
	public function setBaseAmount($amount){
		$this->baseAmount = $amount;
	}

	public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){
		$this->level = $level;
		$amount = $random->nextRange(0, $this->randomAmount) + $this->baseAmount;
		for($i = 0; $i < $amount; ++$i){
			$x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15);
			$z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15);
			$y = $this->getHighestWorkableBlock($x, $z);

			if($y !== -1 and $this->canTallGrassStay($x, $y, $z)){
				$this->level->setBlockIdAt($x, $y, $z, Block::TALL_GRASS);
				$this->level->setBlockDataAt($x, $y, $z, 1);
			}
		}
	}

	private function canTallGrassStay(int $x, int $y, int $z) : bool{
		$b = $this->level->getBlockIdAt($x, $y, $z);
		return ($b === Block::AIR or $b === Block::SNOW_LAYER) and $this->level->getBlockIdAt($x, $y - 1, $z) === Block::GRASS;
	}

	private function getHighestWorkableBlock(int $x, int $z) : int{
		for($y = 127; $y >= 0; --$y){
			$b = $this->level->getBlockIdAt($x, $y, $z);
			if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::LEAVES2 and $b !== Block::SNOW_LAYER){
				return $y + 1;
			}
		}

		return -1;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * All the Object populator classes
 */
namespace pocketmine\level\generator\populator;

use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;

abstract class Populator{

	/**
	 * @return mixed
	 */
	abstract public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random);
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\level\generator\populator\TallGrass;

class PlainBiome extends GrassyBiome{

	public function __construct(){
		parent::__construct();

		$tallGrass = new TallGrass();
		$tallGrass->setBaseAmount(12);

		$this->addPopulator($tallGrass);

		$this->setElevation(63, 68);

		$this->temperature = 0.8;
		$this->rainfall = 0.4;
	}

	public function getName() : string{
		return "Plains";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

abstract class GrassyBiome extends Biome{

	public function __construct(){
		$this->setGroundCover([
			BlockFactory::get(Block::GRASS),
			BlockFactory::get(Block::DIRT),
			BlockFactory::get(Block::DIRT),
			BlockFactory::get(Block::DIRT),
			BlockFactory::get(Block::DIRT)
		]);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

class DesertBiome extends SandyBiome{

	public function __construct(){
		parent::__construct();
		$this->setElevation(63, 74);

		$this->temperature = 2;
		$this->rainfall = 0;
	}

	public function getName() : string{
		return "Desert";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

abstract class SandyBiome extends Biome{

	public function __construct(){
		$this->setGroundCover([
			BlockFactory::get(Block::SAND),
			BlockFactory::get(Block::SAND),
			BlockFactory::get(Block::SANDSTONE),
			BlockFactory::get(Block::SANDSTONE),
			BlockFactory::get(Block::SANDSTONE)
		]);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\level\generator\populator\TallGrass;
use pocketmine\level\generator\populator\Tree;

class MountainsBiome extends GrassyBiome{

	public function __construct(){
		parent::__construct();

		$trees = new Tree();
		$trees->setBaseAmount(1);
		$this->addPopulator($trees);

		$tallGrass = new TallGrass();
		$tallGrass->setBaseAmount(1);

		$this->addPopulator($tallGrass);

		//TODO: add emerald

		$this->setElevation(63, 127);

		$this->temperature = 0.4;
		$this->rainfall = 0.5;
	}

	public function getName() : string{
		return "Mountains";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\generator\populator;

use pocketmine\block\Block;
use pocketmine\block\Sapling;
use pocketmine\level\ChunkManager;
use pocketmine\level\generator\object\Tree as ObjectTree;
use pocketmine\utils\Random;

class Tree extends Populator{
	/** @var ChunkManager */
	private $level;
	/** @var int */
	private $randomAmount = 1;
	/** @var int */
	private $baseAmount = 0;

	/** @var int */
	private $type;

	/**
	 * @param int $type
	 */
	public function __construct($type = Sapling::OAK){
		$this->type = $type;
	}

	/**
	 * @param int $amount
	 *
	 * @return void
	 */
	public function setRandomAmount($amount){
		$this->randomAmount = $amount;
	}

	/**
	 * @param int $amount
	 *
	 * @return void
	 */
	public function setBaseAmount($amount){
		$this->baseAmount = $amount;
	}

	public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){
		$this->level = $level;
		$amount = $random->nextRange(0, $this->randomAmount) + $this->baseAmount;
		for($i = 0; $i < $amount; ++$i){
			$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
			$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
			$y = $this->getHighestWorkableBlock($x, $z);
			if($y === -1){
				continue;
			}
			ObjectTree::growTree($this->level, $x, $y, $z, $random, $this->type);
		}
	}

	private function getHighestWorkableBlock(int $x, int $z) : int{
		for($y = 127; $y >= 0; --$y){
			$b = $this->level->getBlockIdAt($x, $y, $z);
			if($b === Block::DIRT or $b === Block::GRASS){
				return $y + 1;
			}elseif($b !== Block::AIR and $b !== Block::SNOW_LAYER){
				return -1;
			}
		}

		return -1;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\block\Sapling;
use pocketmine\level\generator\populator\TallGrass;
use pocketmine\level\generator\populator\Tree;

class ForestBiome extends GrassyBiome{

	public const TYPE_NORMAL = 0;
	public const TYPE_BIRCH = 1;

	/** @var int */
	public $type;

	public function __construct(int $type = self::TYPE_NORMAL){
		parent::__construct();

		$this->type = $type;

		$trees = new Tree($type === self::TYPE_BIRCH ? Sapling::BIRCH : Sapling::OAK);
		$trees->setBaseAmount(5);
		$this->addPopulator($trees);

		$tallGrass = new TallGrass();
		$tallGrass->setBaseAmount(3);

		$this->addPopulator($tallGrass);

		$this->setElevation(63, 81);

		if($type === self::TYPE_BIRCH){
			$this->temperature = 0.6;
			$this->rainfall = 0.5;
		}else{
			$this->temperature = 0.7;
			$this->rainfall = 0.8;
		}
	}

	public function getName() : string{
		return $this->type === self::TYPE_BIRCH ? "Birch Forest" : "Forest";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\block\Sapling;
use pocketmine\level\generator\populator\TallGrass;
use pocketmine\level\generator\populator\Tree;

class TaigaBiome extends SnowyBiome{

	public function __construct(){
		parent::__construct();

		$trees = new Tree(Sapling::SPRUCE);
		$trees->setBaseAmount(10);
		$this->addPopulator($trees);

		$tallGrass = new TallGrass();
		$tallGrass->setBaseAmount(1);

		$this->addPopulator($tallGrass);

		$this->setElevation(63, 81);

		$this->temperature = 0.05;
		$this->rainfall = 0.8;
	}

	public function getName() : string{
		return "Taiga";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;

abstract class SnowyBiome extends Biome{

	public function __construct(){
		$this->setGroundCover([
			BlockFactory::get(Block::SNOW_LAYER),
			BlockFactory::get(Block::GRASS),
			BlockFactory::get(Block::DIRT),
			BlockFactory::get(Block::DIRT),
			BlockFactory::get(Block::DIRT)
		]);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

class SwampBiome extends GrassyBiome{

	public function __construct(){
		parent::__construct();

		$this->setElevation(62, 63);

		$this->temperature = 0.8;
		$this->rainfall = 0.9;
	}

	public function getName() : string{
		return "Swamp";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\level\generator\populator\TallGrass;

class RiverBiome extends Biome{

	public function __construct(){
		$this->setGroundCover([
			BlockFactory::get(Block::DIRT),
			BlockFactory::get(Block::DIRT),
			BlockFactory::get(Block::DIRT),
			BlockFactory::get(Block::DIRT),
			BlockFactory::get(Block::DIRT)
		]);

		$tallGrass = new TallGrass();
		$tallGrass->setBaseAmount(5);

		$this->addPopulator($tallGrass);

		$this->setElevation(58, 62);

		$this->temperature = 0.5;
		$this->rainfall = 0.7;
	}

	public function getName() : string{
		return "River";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

use pocketmine\level\generator\populator\TallGrass;

class IcePlainsBiome extends SnowyBiome{

	public function __construct(){
		parent::__construct();

		$tallGrass = new TallGrass();
		$tallGrass->setBaseAmount(5);

		$this->addPopulator($tallGrass);

		$this->setElevation(63, 74);

		$this->temperature = 0.05;
		$this->rainfall = 0.8;
	}

	public function getName() : string{
		return "Ice Plains";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\biome;

class SmallMountainsBiome extends MountainsBiome{

	public function __construct(){
		parent::__construct();

		$this->setElevation(63, 97);
	}

	public function getName() : string{
		return "Small Mountains";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io;

use pocketmine\level\format\io\leveldb\LevelDB;
use pocketmine\level\format\io\region\Anvil;
use pocketmine\level\format\io\region\McRegion;
use pocketmine\level\format\io\region\PMAnvil;
use function strtolower;
use function trim;

abstract class LevelProviderManager{
	/**
	 * @var string[]
	 * @phpstan-var array<string, class-string<LevelProvider>>
	 */
	protected static $providers = [];

	public static function init() : void{
		self::addProvider(Anvil::class);
		self::addProvider(McRegion::class);
		self::addProvider(PMAnvil::class);
		self::addProvider(LevelDB::class);
	}

	/**
	 * @phpstan-param class-string<LevelProvider> $class
	 *
	 * @return void
	 * @throws \InvalidArgumentException
	 */
	public static function addProvider(string $class){
		try{
			$reflection = new \ReflectionClass($class);
		}catch(\ReflectionException $e){
			throw new \InvalidArgumentException("Class $class does not exist");
		}
		if(!$reflection->implementsInterface(LevelProvider::class)){
			throw new \InvalidArgumentException("Class $class does not implement " . LevelProvider::class);
		}
		if(!$reflection->isInstantiable()){
			throw new \InvalidArgumentException("Class $class cannot be constructed");
		}

		/** @var LevelProvider $class */
		self::$providers[strtolower($class::getProviderName())] = $class;
	}

	/**
	 * Returns a LevelProvider class for this path, or null
	 *
	 * @return string|null
	 * @phpstan-return class-string<LevelProvider>|null
	 */
	public static function getProvider(string $path){
		foreach(self::$providers as $provider){
			/** @phpstan-var class-string<LevelProvider> $provider */
			if($provider::isValid($path)){
				return $provider;
			}
		}

		return null;
	}

	/**
	 * Returns a LevelProvider by name, or null if not found
	 *
	 * @return string|null
	 * @phpstan-return class-string<LevelProvider>|null
	 */
	public static function getProviderByName(string $name){
		return self::$providers[trim(strtolower($name))] ?? null;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io\region;

use pocketmine\level\format\Chunk;
use pocketmine\level\format\io\ChunkUtils;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\level\format\SubChunk;
use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteArrayTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntArrayTag;
use pocketmine\nbt\tag\ListTag;

class Anvil extends McRegion{

	public const REGION_FILE_EXTENSION = "mca";

	protected function nbtSerialize(Chunk $chunk) : string{
		$nbt = new CompoundTag("Level", []);
		$nbt->setInt("xPos", $chunk->getX());
		$nbt->setInt("zPos", $chunk->getZ());

		$nbt->setByte("V", 1);
		$nbt->setLong("LastUpdate", 0); //TODO
		$nbt->setLong("InhabitedTime", 0); //TODO
		$nbt->setByte("TerrainPopulated", $chunk->isPopulated() ? 1 : 0);
		$nbt->setByte("LightPopulated", $chunk->isLightPopulated() ? 1 : 0);

		$subChunks = [];
		foreach($chunk->getSubChunks() as $y => $subChunk){
			if(!($subChunk instanceof SubChunk) or $subChunk->isEmpty()){
				continue;
			}

			$tag = $this->serializeSubChunk($subChunk);
			$tag->setByte("Y", $y);
			$subChunks[] = $tag;
		}
		$nbt->setTag(new ListTag("Sections", $subChunks, NBT::TAG_Compound));

		$nbt->setByteArray("Biomes", $chunk->getBiomeIdArray());
		$nbt->setIntArray("HeightMap", $chunk->getHeightMapArray());

		$entities = [];

		foreach($chunk->getSavableEntities() as $entity){
			$entity->saveNBT();
			$entities[] = $entity->namedtag;
		}

		$nbt->setTag(new ListTag("Entities", $entities, NBT::TAG_Compound));

		$tiles = [];
		foreach($chunk->getTiles() as $tile){
			$tiles[] = $tile->saveNBT();
		}

		$nbt->setTag(new ListTag("TileEntities", $tiles, NBT::TAG_Compound));

		//TODO: TileTicks

		$writer = new BigEndianNBTStream();
		return $writer->writeCompressed(new CompoundTag("", [$nbt]), ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
	}

	protected function serializeSubChunk(SubChunk $subChunk) : CompoundTag{
		return new CompoundTag("", [
			new ByteArrayTag("Blocks", ChunkUtils::reorderByteArray($subChunk->getBlockIdArray())), //Generic in-memory chunks are currently always XZY
			new ByteArrayTag("Data", ChunkUtils::reorderNibbleArray($subChunk->getBlockDataArray())),
			new ByteArrayTag("SkyLight", ChunkUtils::reorderNibbleArray($subChunk->getBlockSkyLightArray(), "\xff")),
			new ByteArrayTag("BlockLight", ChunkUtils::reorderNibbleArray($subChunk->getBlockLightArray()))
		]);
	}

	protected function nbtDeserialize(string $data) : Chunk{
		$nbt = new BigEndianNBTStream();
		$chunk = $nbt->readCompressed($data);
		if(!($chunk instanceof CompoundTag) or !$chunk->hasTag("Level")){
			throw new CorruptedChunkException("'Level' key is missing from chunk NBT");
		}

		$chunk = $chunk->getCompoundTag("Level");

		$subChunks = [];
		$subChunksTag = $chunk->getListTag("Sections") ?? [];
		foreach($subChunksTag as $subChunk){
			if($subChunk instanceof CompoundTag){
				$subChunks[$subChunk->getByte("Y")] = $this->deserializeSubChunk($subChunk);
			}
		}

		if($chunk->hasTag("BiomeColors", IntArrayTag::class)){
			$biomeIds = ChunkUtils::convertBiomeColors($chunk->getIntArray("BiomeColors")); //Convert back to original format
		}else{
			$biomeIds = $chunk->getByteArray("Biomes", "", true);
		}

		$result = new Chunk(
			$chunk->getInt("xPos"),
			$chunk->getInt("zPos"),
			$subChunks,
			$chunk->hasTag("Entities", ListTag::class) ? self::getCompoundList("Entities", $chunk->getListTag("Entities")) : [],
			$chunk->hasTag("TileEntities", ListTag::class) ? self::getCompoundList("TileEntities", $chunk->getListTag("TileEntities")) : [],
			$biomeIds,
			$chunk->getIntArray("HeightMap", [])
		);
		$result->setLightPopulated($chunk->getByte("LightPopulated", 0) !== 0);
		$result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0);
		$result->setGenerated();
		return $result;
	}

	protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
		return new SubChunk(
			ChunkUtils::reorderByteArray($subChunk->getByteArray("Blocks")),
			ChunkUtils::reorderNibbleArray($subChunk->getByteArray("Data")),
			ChunkUtils::reorderNibbleArray($subChunk->getByteArray("SkyLight"), "\xff"),
			ChunkUtils::reorderNibbleArray($subChunk->getByteArray("BlockLight"))
		);
	}

	public static function getProviderName() : string{
		return "anvil";
	}

	public static function getPcWorldFormatVersion() : int{
		return 19133; //anvil
	}

	public function getWorldHeight() : int{
		//TODO: add world height options
		return 256;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io\region;

use pocketmine\level\format\Chunk;
use pocketmine\level\format\io\BaseLevelProvider;
use pocketmine\level\format\io\ChunkUtils;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\level\format\SubChunk;
use pocketmine\level\generator\GeneratorManager;
use pocketmine\level\Level;
use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteArrayTag;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntArrayTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\LongTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\utils\MainLogger;
use function array_filter;
use function array_values;
use function assert;
use function file_exists;
use function file_put_contents;
use function is_dir;
use function is_int;
use function microtime;
use function mkdir;
use function pack;
use function rename;
use function scandir;
use function str_repeat;
use function strrpos;
use function substr;
use function time;
use function unpack;
use const SCANDIR_SORT_NONE;

class McRegion extends BaseLevelProvider{

	public const REGION_FILE_EXTENSION = "mcr";

	/** @var RegionLoader[] */
	protected $regions = [];

	protected function nbtSerialize(Chunk $chunk) : string{
		$nbt = new CompoundTag("Level", []);
		$nbt->setInt("xPos", $chunk->getX());
		$nbt->setInt("zPos", $chunk->getZ());

		$nbt->setLong("LastUpdate", 0); //TODO
		$nbt->setByte("TerrainPopulated", $chunk->isPopulated() ? 1 : 0);
		$nbt->setByte("LightPopulated", $chunk->isLightPopulated() ? 1 : 0);

		$ids = "";
		$data = "";
		$skyLight = "";
		$blockLight = "";
		$subChunks = $chunk->getSubChunks();
		for($x = 0; $x < 16; ++$x){
			for($z = 0; $z < 16; ++$z){
				for($y = 0; $y < 8; ++$y){
					$subChunk = $subChunks[$y];
					$ids .= $subChunk->getBlockIdColumn($x, $z);
					$data .= $subChunk->getBlockDataColumn($x, $z);
					$skyLight .= $subChunk->getBlockSkyLightColumn($x, $z);
					$blockLight .= $subChunk->getBlockLightColumn($x, $z);
				}
			}
		}

		$nbt->setByteArray("Blocks", $ids);
		$nbt->setByteArray("Data", $data);
		$nbt->setByteArray("SkyLight", $skyLight);
		$nbt->setByteArray("BlockLight", $blockLight);

		$nbt->setByteArray("Biomes", $chunk->getBiomeIdArray()); //doesn't exist in regular McRegion, this is here for PocketMine-MP only
		$nbt->setByteArray("HeightMap", pack("C*", ...$chunk->getHeightMapArray())); //this is ByteArray in McRegion, but IntArray in Anvil (due to raised build height)

		$entities = [];

		foreach($chunk->getSavableEntities() as $entity){
			$entity->saveNBT();
			$entities[] = $entity->namedtag;
		}

		$nbt->setTag(new ListTag("Entities", $entities, NBT::TAG_Compound));

		$tiles = [];
		foreach($chunk->getTiles() as $tile){
			$tiles[] = $tile->saveNBT();
		}

		$nbt->setTag(new ListTag("TileEntities", $tiles, NBT::TAG_Compound));

		$writer = new BigEndianNBTStream();
		return $writer->writeCompressed(new CompoundTag("", [$nbt]), ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
	}

	/**
	 * @throws CorruptedChunkException
	 */
	protected function nbtDeserialize(string $data) : Chunk{
		$nbt = new BigEndianNBTStream();
		$chunk = $nbt->readCompressed($data);
		if(!($chunk instanceof CompoundTag) or !$chunk->hasTag("Level")){
			throw new CorruptedChunkException("'Level' key is missing from chunk NBT");
		}

		$chunk = $chunk->getCompoundTag("Level");

		$subChunks = [];
		$fullIds = $chunk->hasTag("Blocks", ByteArrayTag::class) ? $chunk->getByteArray("Blocks") : str_repeat("\x00", 32768);
		$fullData = $chunk->hasTag("Data", ByteArrayTag::class) ? $chunk->getByteArray("Data") : str_repeat("\x00", 16384);
		$fullSkyLight = $chunk->hasTag("SkyLight", ByteArrayTag::class) ? $chunk->getByteArray("SkyLight") : str_repeat("\xff", 16384);
		$fullBlockLight = $chunk->hasTag("BlockLight", ByteArrayTag::class) ? $chunk->getByteArray("BlockLight") : str_repeat("\x00", 16384);

		for($y = 0; $y < 8; ++$y){
			$offset = ($y << 4);
			$ids = "";
			for($i = 0; $i < 256; ++$i){
				$ids .= substr($fullIds, $offset, 16);
				$offset += 128;
			}
			$data = "";
			$offset = ($y << 3);
			for($i = 0; $i < 256; ++$i){
				$data .= substr($fullData, $offset, 8);
				$offset += 64;
			}
			$skyLight = "";
			$offset = ($y << 3);
			for($i = 0; $i < 256; ++$i){
				$skyLight .= substr($fullSkyLight, $offset, 8);
				$offset += 64;
			}
			$blockLight = "";
			$offset = ($y << 3);
			for($i = 0; $i < 256; ++$i){
				$blockLight .= substr($fullBlockLight, $offset, 8);
				$offset += 64;
			}
			$subChunks[$y] = new SubChunk($ids, $data, $skyLight, $blockLight);
		}

		if($chunk->hasTag("BiomeColors", IntArrayTag::class)){
			$biomeIds = ChunkUtils::convertBiomeColors($chunk->getIntArray("BiomeColors")); //Convert back to original format
		}elseif($chunk->hasTag("Biomes", ByteArrayTag::class)){
			$biomeIds = $chunk->getByteArray("Biomes");
		}else{
			$biomeIds = "";
		}

		$heightMap = [];
		if($chunk->hasTag("HeightMap", ByteArrayTag::class)){
			$heightMap = array_values(unpack("C*", $chunk->getByteArray("HeightMap")));
		}elseif($chunk->hasTag("HeightMap", IntArrayTag::class)){
			$heightMap = $chunk->getIntArray("HeightMap"); #blameshoghicp
		}

		$result = new Chunk(
			$chunk->getInt("xPos"),
			$chunk->getInt("zPos"),
			$subChunks,
			$chunk->hasTag("Entities", ListTag::class) ? self::getCompoundList("Entities", $chunk->getListTag("Entities")) : [],
			$chunk->hasTag("TileEntities", ListTag::class) ? self::getCompoundList("TileEntities", $chunk->getListTag("TileEntities")) : [],
			$biomeIds,
			$heightMap
		);
		$result->setLightPopulated($chunk->getByte("LightPopulated", 0) !== 0);
		$result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0);
		$result->setGenerated(true);
		return $result;
	}

	/**
	 * @return CompoundTag[]
	 * @throws CorruptedChunkException
	 */
	protected static function getCompoundList(string $context, ListTag $list) : array{
		if($list->count() === 0){ //empty lists might have wrong types, we don't care
			return [];
		}
		if($list->getTagType() !== NBT::TAG_Compound){
			throw new CorruptedChunkException("Expected TAG_List<TAG_Compound> for '$context'");
		}
		$result = [];
		foreach($list as $tag){
			if(!($tag instanceof CompoundTag)){
				//this should never happen, but it's still possible due to lack of native type safety
				throw new CorruptedChunkException("Expected TAG_List<TAG_Compound> for '$context'");
			}
			$result[] = $tag;
		}
		return $result;
	}

	public static function getProviderName() : string{
		return "mcregion";
	}

	/**
	 * Returns the storage version as per Minecraft PC world formats.
	 */
	public static function getPcWorldFormatVersion() : int{
		return 19132; //mcregion
	}

	public function getWorldHeight() : int{
		//TODO: add world height options
		return 128;
	}

	public static function isValid(string $path) : bool{
		$isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/"));

		if($isValid){
			$files = array_filter(scandir($path . "/region/", SCANDIR_SORT_NONE), function(string $file) : bool{
				return substr($file, strrpos($file, ".") + 1, 2) === "mc"; //region file
			});

			foreach($files as $f){
				if(substr($f, strrpos($f, ".") + 1) !== static::REGION_FILE_EXTENSION){
					$isValid = false;
					break;
				}
			}
		}

		return $isValid;
	}

	public static function generate(string $path, string $name, int $seed, string $generator, array $options = []){
		if(!file_exists($path)){
			mkdir($path, 0777, true);
		}

		if(!file_exists($path . "/region")){
			mkdir($path . "/region", 0777);
		}
		//TODO, add extra details
		$levelData = new CompoundTag("Data", [
			new ByteTag("hardcore", ($options["hardcore"] ?? false) === true ? 1 : 0),
			new ByteTag("Difficulty", Level::getDifficultyFromString((string) ($options["difficulty"] ?? "normal"))),
			new ByteTag("initialized", 1),
			new IntTag("GameType", 0),
			new IntTag("generatorVersion", 1), //2 in MCPE
			new IntTag("SpawnX", 256),
			new IntTag("SpawnY", 70),
			new IntTag("SpawnZ", 256),
			new IntTag("version", static::getPcWorldFormatVersion()),
			new IntTag("DayTime", 0),
			new LongTag("LastPlayed", (int) (microtime(true) * 1000)),
			new LongTag("RandomSeed", $seed),
			new LongTag("SizeOnDisk", 0),
			new LongTag("Time", 0),
			new StringTag("generatorName", GeneratorManager::getGeneratorName($generator)),
			new StringTag("generatorOptions", $options["preset"] ?? ""),
			new StringTag("LevelName", $name),
			new CompoundTag("GameRules", [])
		]);
		$nbt = new BigEndianNBTStream();
		$buffer = $nbt->writeCompressed(new CompoundTag("", [
			$levelData
		]));
		file_put_contents($path . "level.dat", $buffer);
	}

	public function getGenerator() : string{
		return $this->levelData->getString("generatorName", "DEFAULT");
	}

	public function getGeneratorOptions() : array{
		return ["preset" => $this->levelData->getString("generatorOptions", "")];
	}

	public function getDifficulty() : int{
		return $this->levelData->getByte("Difficulty", Level::DIFFICULTY_NORMAL);
	}

	public function setDifficulty(int $difficulty){
		$this->levelData->setByte("Difficulty", $difficulty);
	}

	public function doGarbageCollection(){
		$limit = time() - 300;
		foreach($this->regions as $index => $region){
			if($region->lastUsed <= $limit){
				$region->close();
				unset($this->regions[$index]);
			}
		}
	}

	/**
	 * @param int $regionX reference parameter
	 * @param int $regionZ reference parameter
	 *
	 * @return void
	 */
	public static function getRegionIndex(int $chunkX, int $chunkZ, &$regionX, &$regionZ){
		$regionX = $chunkX >> 5;
		$regionZ = $chunkZ >> 5;
	}

	/**
	 * @return RegionLoader|null
	 */
	protected function getRegion(int $regionX, int $regionZ){
		return $this->regions[((($regionX) & 0xFFFFFFFF) << 32) | (( $regionZ) & 0xFFFFFFFF)] ?? null;
	}

	/**
	 * Returns the path to a specific region file based on its X/Z coordinates
	 */
	protected function pathToRegion(int $regionX, int $regionZ) : string{
		return $this->path . "region/r.$regionX.$regionZ." . static::REGION_FILE_EXTENSION;
	}

	/**
	 * @return void
	 */
	protected function loadRegion(int $regionX, int $regionZ){
		if(!isset($this->regions[$index = ((($regionX) & 0xFFFFFFFF) << 32) | (( $regionZ) & 0xFFFFFFFF)])){
			$path = $this->pathToRegion($regionX, $regionZ);

			$region = new RegionLoader($path, $regionX, $regionZ);
			try{
				$region->open();
			}catch(CorruptedRegionException $e){
				$logger = MainLogger::getLogger();
				$logger->error("Corrupted region file detected: " . $e->getMessage());

				$region->close(false); //Do not write anything to the file

				$backupPath = $path . ".bak." . time();
				rename($path, $backupPath);
				$logger->error("Corrupted region file has been backed up to " . $backupPath);

				$region = new RegionLoader($path, $regionX, $regionZ);
				$region->open(); //this will create a new empty region to replace the corrupted one
			}

			$this->regions[$index] = $region;
		}
	}

	public function close(){
		foreach($this->regions as $index => $region){
			$region->close();
			unset($this->regions[$index]);
		}
	}

	/**
	 * @throws CorruptedChunkException
	 */
	protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk{
		$regionX = $regionZ = null;
		self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
		assert(is_int($regionX) and is_int($regionZ));

		$this->loadRegion($regionX, $regionZ);

		$chunkData = $this->getRegion($regionX, $regionZ)->readChunk($chunkX & 0x1f, $chunkZ & 0x1f);
		if($chunkData !== null){
			return $this->nbtDeserialize($chunkData);
		}

		return null;
	}

	protected function writeChunk(Chunk $chunk) : void{
		$chunkX = $chunk->getX();
		$chunkZ = $chunk->getZ();

		self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
		$this->loadRegion($regionX, $regionZ);

		$this->getRegion($regionX, $regionZ)->writeChunk($chunkX & 0x1f, $chunkZ & 0x1f, $this->nbtSerialize($chunk));
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io;

use pocketmine\level\format\Chunk;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\level\format\io\exception\UnsupportedChunkFormatException;
use pocketmine\level\LevelException;
use pocketmine\math\Vector3;
use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function mkdir;

abstract class BaseLevelProvider implements LevelProvider{
	/** @var string */
	protected $path;
	/** @var CompoundTag */
	protected $levelData;

	public function __construct(string $path){
		$this->path = $path;
		if(!file_exists($this->path)){
			mkdir($this->path, 0777, true);
		}

		$this->loadLevelData();
		$this->fixLevelData();
	}

	protected function loadLevelData() : void{
		$nbt = new BigEndianNBTStream();
		$levelData = $nbt->readCompressed(file_get_contents($this->getPath() . "level.dat"));

		if(!($levelData instanceof CompoundTag) or !$levelData->hasTag("Data", CompoundTag::class)){
			throw new LevelException("Invalid level.dat");
		}

		$this->levelData = $levelData->getCompoundTag("Data");
	}

	protected function fixLevelData() : void{
		if(!$this->levelData->hasTag("generatorName", StringTag::class)){
			$this->levelData->setString("generatorName", "default", true);
		}elseif(($generatorName = self::hackyFixForGeneratorClasspathInLevelDat($this->levelData->getString("generatorName"))) !== null){
			$this->levelData->setString("generatorName", $generatorName);
		}

		if(!$this->levelData->hasTag("generatorOptions", StringTag::class)){
			$this->levelData->setString("generatorOptions", "");
		}
	}

	/**
	 * Hack to fix worlds broken previously by older versions of PocketMine-MP which incorrectly saved classpaths of
	 * generators into level.dat on imported (not generated) worlds.
	 *
	 * This should only have affected leveldb worlds as far as I know, because PC format worlds include the
	 * generatorName tag by default. However, MCPE leveldb ones didn't, and so they would get filled in with something
	 * broken.
	 *
	 * This bug took a long time to get found because previously the generator manager would just return the default
	 * generator silently on failure to identify the correct generator, which caused lots of unexpected bugs.
	 *
	 * Only classnames which were written into the level.dat from "fixing" the level data are included here. These are
	 * hardcoded to avoid problems fixing broken worlds in the future if these classes get moved, renamed or removed.
	 *
	 * @param string $className Classname saved in level.dat
	 *
	 * @return null|string Name of the correct generator to replace the broken value
	 */
	protected static function hackyFixForGeneratorClasspathInLevelDat(string $className) : ?string{
		//THESE ARE DELIBERATELY HARDCODED, DO NOT CHANGE!
		switch($className){
			case 'pocketmine\level\generator\normal\Normal':
				return "normal";
			case 'pocketmine\level\generator\Flat':
				return "flat";
		}

		return null;
	}

	public function getPath() : string{
		return $this->path;
	}

	public function getName() : string{
		return $this->levelData->getString("LevelName");
	}

	public function getTime() : int{
		return $this->levelData->getLong("Time", 0, true);
	}

	public function setTime(int $value){
		$this->levelData->setLong("Time", $value, true); //some older PM worlds had this in the wrong format
	}

	public function getSeed() : int{
		return $this->levelData->getLong("RandomSeed");
	}

	public function setSeed(int $value){
		$this->levelData->setLong("RandomSeed", $value);
	}

	public function getSpawn() : Vector3{
		return new Vector3($this->levelData->getInt("SpawnX"), $this->levelData->getInt("SpawnY"), $this->levelData->getInt("SpawnZ"));
	}

	public function setSpawn(Vector3 $pos){
		$this->levelData->setInt("SpawnX", $pos->getFloorX());
		$this->levelData->setInt("SpawnY", $pos->getFloorY());
		$this->levelData->setInt("SpawnZ", $pos->getFloorZ());
	}

	public function doGarbageCollection(){

	}

	public function getLevelData() : CompoundTag{
		return $this->levelData;
	}

	/**
	 * @return void
	 */
	public function saveLevelData(){
		$nbt = new BigEndianNBTStream();
		$buffer = $nbt->writeCompressed(new CompoundTag("", [
			$this->levelData
		]));
		file_put_contents($this->getPath() . "level.dat", $buffer);
	}

	/**
	 * @throws CorruptedChunkException
	 * @throws UnsupportedChunkFormatException
	 */
	public function loadChunk(int $chunkX, int $chunkZ) : ?Chunk{
		return $this->readChunk($chunkX, $chunkZ);
	}

	public function saveChunk(Chunk $chunk) : void{
		if(!$chunk->isGenerated()){
			throw new \InvalidStateException("Cannot save un-generated chunk");
		}
		$this->writeChunk($chunk);
	}

	/**
	 * @throws UnsupportedChunkFormatException
	 * @throws CorruptedChunkException
	 */
	abstract protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk;

	abstract protected function writeChunk(Chunk $chunk) : void;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io;

use pocketmine\level\format\Chunk;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\level\format\io\exception\UnsupportedChunkFormatException;
use pocketmine\level\generator\Generator;
use pocketmine\math\Vector3;

interface LevelProvider{

	public function __construct(string $path);

	/**
	 * Returns the full provider name, like "anvil" or "mcregion", will be used to find the correct format.
	 */
	public static function getProviderName() : string;

	/**
	 * Gets the build height limit of this world
	 */
	public function getWorldHeight() : int;

	public function getPath() : string;

	/**
	 * Tells if the path is a valid level.
	 * This must tell if the current format supports opening the files in the directory
	 */
	public static function isValid(string $path) : bool;

	/**
	 * Generate the needed files in the path given
	 *
	 * @param mixed[] $options
	 * @phpstan-param class-string<Generator> $generator
	 * @phpstan-param array<string, mixed>    $options
	 *
	 * @return void
	 */
	public static function generate(string $path, string $name, int $seed, string $generator, array $options = []);

	/**
	 * Returns the generator name
	 */
	public function getGenerator() : string;

	/**
	 * @return mixed[]
	 * @phpstan-return array<string, mixed>
	 */
	public function getGeneratorOptions() : array;

	/**
	 * Saves a chunk (usually to disk).
	 */
	public function saveChunk(Chunk $chunk) : void;

	/**
	 * Loads a chunk (usually from disk storage) and returns it. If the chunk does not exist, null is returned.
	 *
	 * @throws CorruptedChunkException
	 * @throws UnsupportedChunkFormatException
	 */
	public function loadChunk(int $chunkX, int $chunkZ) : ?Chunk;

	public function getName() : string;

	public function getTime() : int;

	/**
	 * @return void
	 */
	public function setTime(int $value);

	public function getSeed() : int;

	/**
	 * @return void
	 */
	public function setSeed(int $value);

	public function getSpawn() : Vector3;

	/**
	 * @return void
	 */
	public function setSpawn(Vector3 $pos);

	/**
	 * Returns the world difficulty. This will be one of the Level constants.
	 */
	public function getDifficulty() : int;

	/**
	 * Sets the world difficulty.
	 *
	 * @return void
	 */
	public function setDifficulty(int $difficulty);

	/**
	 * Performs garbage collection in the level provider, such as cleaning up regions in Region-based worlds.
	 *
	 * @return void
	 */
	public function doGarbageCollection();

	/**
	 * Performs cleanups necessary when the level provider is closed and no longer needed.
	 *
	 * @return void
	 */
	public function close();

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io\region;

use pocketmine\level\format\SubChunk;
use pocketmine\nbt\tag\ByteArrayTag;
use pocketmine\nbt\tag\CompoundTag;

/**
 * This format is exactly the same as the PC Anvil format, with the only difference being that the stored data order
 * is XZY instead of YZX for more performance loading and saving worlds.
 */
class PMAnvil extends Anvil{

	public const REGION_FILE_EXTENSION = "mcapm";

	protected function serializeSubChunk(SubChunk $subChunk) : CompoundTag{
		return new CompoundTag("", [
			new ByteArrayTag("Blocks",     $subChunk->getBlockIdArray()),
			new ByteArrayTag("Data",       $subChunk->getBlockDataArray()),
			new ByteArrayTag("SkyLight",   $subChunk->getBlockSkyLightArray()),
			new ByteArrayTag("BlockLight", $subChunk->getBlockLightArray())
		]);
	}

	protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
		return new SubChunk(
			$subChunk->getByteArray("Blocks"),
			$subChunk->getByteArray("Data"),
			$subChunk->getByteArray("SkyLight"),
			$subChunk->getByteArray("BlockLight")
		);
	}

	public static function getProviderName() : string{
		return "pmanvil";
	}

	public static function getPcWorldFormatVersion() : int{
		return -1; //Not a PC format, only PocketMine-MP
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io\leveldb;

use pocketmine\level\format\Chunk;
use pocketmine\level\format\io\BaseLevelProvider;
use pocketmine\level\format\io\ChunkUtils;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\level\format\io\exception\UnsupportedChunkFormatException;
use pocketmine\level\format\SubChunk;
use pocketmine\level\generator\Flat;
use pocketmine\level\generator\GeneratorManager;
use pocketmine\level\Level;
use pocketmine\level\LevelException;
use pocketmine\nbt\LittleEndianNBTStream;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\LongTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\utils\Binary;
use pocketmine\utils\BinaryStream;
use function array_values;
use function chr;
use function count;
use function defined;
use function explode;
use function extension_loaded;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function is_array;
use function is_dir;
use function mkdir;
use function ord;
use function pack;
use function rtrim;
use function strlen;
use function substr;
use function time;
use function trim;
use function unpack;
use const INT32_MAX;
use const LEVELDB_ZLIB_RAW_COMPRESSION;

class LevelDB extends BaseLevelProvider{

	//According to Tomasso, these aren't supposed to be readable anymore. Thankfully he didn't change the readable ones...
	public const TAG_DATA_2D = "\x2d";
	public const TAG_DATA_2D_LEGACY = "\x2e";
	public const TAG_SUBCHUNK_PREFIX = "\x2f";
	public const TAG_LEGACY_TERRAIN = "0";
	public const TAG_BLOCK_ENTITY = "1";
	public const TAG_ENTITY = "2";
	public const TAG_PENDING_TICK = "3";
	public const TAG_BLOCK_EXTRA_DATA = "4";
	public const TAG_BIOME_STATE = "5";
	public const TAG_STATE_FINALISATION = "6";

	public const TAG_BORDER_BLOCKS = "8";
	public const TAG_HARDCODED_SPAWNERS = "9";

	public const FINALISATION_NEEDS_INSTATICKING = 0;
	public const FINALISATION_NEEDS_POPULATION = 1;
	public const FINALISATION_DONE = 2;

	public const TAG_VERSION = "v";

	public const ENTRY_FLAT_WORLD_LAYERS = "game_flatworldlayers";

	public const GENERATOR_LIMITED = 0;
	public const GENERATOR_INFINITE = 1;
	public const GENERATOR_FLAT = 2;

	public const CURRENT_STORAGE_VERSION = 6; //Current MCPE level format version
	public const CURRENT_LEVEL_CHUNK_VERSION = 7;
	public const CURRENT_LEVEL_SUBCHUNK_VERSION = 0;

	/** @var \LevelDB */
	protected $db;

	private static function checkForLevelDBExtension() : void{
		if(!extension_loaded('leveldb')){
			throw new LevelException("The leveldb PHP extension is required to use this world format");
		}

		if(!defined('LEVELDB_ZLIB_RAW_COMPRESSION')){
			throw new LevelException("Given version of php-leveldb doesn't support zlib raw compression");
		}
	}

	private static function createDB(string $path) : \LevelDB{
		return new \LevelDB($path . "/db", [
			"compression" => LEVELDB_ZLIB_RAW_COMPRESSION
		]);
	}

	public function __construct(string $path){
		self::checkForLevelDBExtension();
		parent::__construct($path);

		$this->db = self::createDB($path);
	}

	protected function loadLevelData() : void{
		$rawLevelData = file_get_contents($this->getPath() . "level.dat");
		if($rawLevelData === false or strlen($rawLevelData) <= 8){
			throw new LevelException("Truncated level.dat");
		}
		$nbt = new LittleEndianNBTStream();
		$levelData = $nbt->read(substr($rawLevelData, 8));
		if($levelData instanceof CompoundTag){
			$this->levelData = $levelData;
		}else{
			throw new LevelException("Invalid level.dat");
		}

		$version = $this->levelData->getInt("StorageVersion", INT32_MAX, true);
		if($version > self::CURRENT_STORAGE_VERSION){
			throw new LevelException("Specified LevelDB world format version ($version) is not supported");
		}
	}

	protected function fixLevelData() : void{
		$db = self::createDB($this->path);

		if(!$this->levelData->hasTag("generatorName", StringTag::class)){
			if($this->levelData->hasTag("Generator", IntTag::class)){
				switch($this->levelData->getInt("Generator")){ //Detect correct generator from MCPE data
					case self::GENERATOR_FLAT:
						$this->levelData->setString("generatorName", "flat");
						if(($layers = $db->get(self::ENTRY_FLAT_WORLD_LAYERS)) !== false){ //Detect existing custom flat layers
							$layers = trim($layers, "[]");
						}else{
							$layers = "7,3,3,2";
						}
						$this->levelData->setString("generatorOptions", "2;" . $layers . ";1");
						break;
					case self::GENERATOR_INFINITE:
						//TODO: add a null generator which does not generate missing chunks (to allow importing back to MCPE and generating more normal terrain without PocketMine messing things up)
						$this->levelData->setString("generatorName", "default");
						$this->levelData->setString("generatorOptions", "");
						break;
					case self::GENERATOR_LIMITED:
						throw new LevelException("Limited worlds are not currently supported");
					default:
						throw new LevelException("Unknown LevelDB world format type, this level cannot be loaded");
				}
			}else{
				$this->levelData->setString("generatorName", "default");
			}
		}elseif(($generatorName = self::hackyFixForGeneratorClasspathInLevelDat($this->levelData->getString("generatorName"))) !== null){
			$this->levelData->setString("generatorName", $generatorName);
		}

		if(!$this->levelData->hasTag("generatorOptions", StringTag::class)){
			$this->levelData->setString("generatorOptions", "");
		}

		$db->close();
	}

	public static function getProviderName() : string{
		return "leveldb";
	}

	public function getWorldHeight() : int{
		return 256;
	}

	public static function isValid(string $path) : bool{
		return file_exists($path . "/level.dat") and is_dir($path . "/db/");
	}

	public static function generate(string $path, string $name, int $seed, string $generator, array $options = []){
		self::checkForLevelDBExtension();

		if(!file_exists($path . "/db")){
			mkdir($path . "/db", 0777, true);
		}

		switch($generator){
			case Flat::class:
				$generatorType = self::GENERATOR_FLAT;
				break;
			default:
				$generatorType = self::GENERATOR_INFINITE;
			//TODO: add support for limited worlds
		}

		$levelData = new CompoundTag("", [
			//Vanilla fields
			new IntTag("DayCycleStopTime", -1),
			new IntTag("Difficulty", Level::getDifficultyFromString((string) ($options["difficulty"] ?? "normal"))),
			new ByteTag("ForceGameType", 0),
			new IntTag("GameType", 0),
			new IntTag("Generator", $generatorType),
			new LongTag("LastPlayed", time()),
			new StringTag("LevelName", $name),
			new IntTag("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL),
			//new IntTag("Platform", 2), //TODO: find out what the possible values are for
			new LongTag("RandomSeed", $seed),
			new IntTag("SpawnX", 0),
			new IntTag("SpawnY", 32767),
			new IntTag("SpawnZ", 0),
			new IntTag("StorageVersion", self::CURRENT_STORAGE_VERSION),
			new LongTag("Time", 0),
			new ByteTag("eduLevel", 0),
			new ByteTag("falldamage", 1),
			new ByteTag("firedamage", 1),
			new ByteTag("hasBeenLoadedInCreative", 1), //badly named, this actually determines whether achievements can be earned in this world...
			new ByteTag("immutableWorld", 0),
			new FloatTag("lightningLevel", 0.0),
			new IntTag("lightningTime", 0),
			new ByteTag("pvp", 1),
			new FloatTag("rainLevel", 0.0),
			new IntTag("rainTime", 0),
			new ByteTag("spawnMobs", 1),
			new ByteTag("texturePacksRequired", 0), //TODO

			//Additional PocketMine-MP fields
			new CompoundTag("GameRules", []),
			new ByteTag("hardcore", ($options["hardcore"] ?? false) === true ? 1 : 0),
			new StringTag("generatorName", GeneratorManager::getGeneratorName($generator)),
			new StringTag("generatorOptions", $options["preset"] ?? "")
		]);

		$nbt = new LittleEndianNBTStream();
		$buffer = $nbt->write($levelData);
		file_put_contents($path . "level.dat", (\pack("V", self::CURRENT_STORAGE_VERSION)) . (\pack("V", strlen($buffer))) . $buffer);

		$db = self::createDB($path);

		if($generatorType === self::GENERATOR_FLAT and isset($options["preset"])){
			$layers = explode(";", $options["preset"])[1] ?? "";
			if($layers !== ""){
				$out = "[";
				foreach(Flat::parseLayers($layers) as $result){
					$out .= $result[0] . ","; //only id, meta will unfortunately not survive :(
				}
				$out = rtrim($out, ",") . "]"; //remove trailing comma
				$db->put(self::ENTRY_FLAT_WORLD_LAYERS, $out); //Add vanilla flatworld layers to allow terrain generation by MCPE to continue seamlessly
			}
		}

		$db->close();

	}

	public function saveLevelData(){
		$this->levelData->setInt("NetworkVersion", ProtocolInfo::CURRENT_PROTOCOL);
		$this->levelData->setInt("StorageVersion", self::CURRENT_STORAGE_VERSION);

		$nbt = new LittleEndianNBTStream();
		$buffer = $nbt->write($this->levelData);
		file_put_contents($this->getPath() . "level.dat", (\pack("V", self::CURRENT_STORAGE_VERSION)) . (\pack("V", strlen($buffer))) . $buffer);
	}

	public function getGenerator() : string{
		return $this->levelData->getString("generatorName", "");
	}

	public function getGeneratorOptions() : array{
		return ["preset" => $this->levelData->getString("generatorOptions", "")];
	}

	public function getDifficulty() : int{
		return $this->levelData->getInt("Difficulty", Level::DIFFICULTY_NORMAL);
	}

	public function setDifficulty(int $difficulty){
		$this->levelData->setInt("Difficulty", $difficulty); //yes, this is intended! (in PE: int, PC: byte)
	}

	/**
	 * @throws UnsupportedChunkFormatException
	 */
	protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk{
		$index = LevelDB::chunkIndex($chunkX, $chunkZ);

		if(!$this->chunkExists($chunkX, $chunkZ)){
			return null;
		}

		/** @var SubChunk[] $subChunks */
		$subChunks = [];

		/** @var int[] $heightMap */
		$heightMap = [];
		/** @var string $biomeIds */
		$biomeIds = "";

		/** @var bool $lightPopulated */
		$lightPopulated = true;

		$chunkVersion = ord($this->db->get($index . self::TAG_VERSION));
		$hasBeenUpgraded = $chunkVersion < self::CURRENT_LEVEL_CHUNK_VERSION;

		$binaryStream = new BinaryStream();

		switch($chunkVersion){
			case 7: //MCPE 1.2 (???)
			case 4: //MCPE 1.1
				//TODO: check beds
			case 3: //MCPE 1.0
				for($y = 0; $y < Chunk::MAX_SUBCHUNKS; ++$y){
					if(($data = $this->db->get($index . self::TAG_SUBCHUNK_PREFIX . chr($y))) === false){
						continue;
					}

					$binaryStream->setBuffer($data, 0);
					$subChunkVersion = $binaryStream->getByte();
					if($subChunkVersion < self::CURRENT_LEVEL_SUBCHUNK_VERSION){
						$hasBeenUpgraded = true;
					}

					switch($subChunkVersion){
						case 0:
							$blocks = $binaryStream->get(4096);
							$blockData = $binaryStream->get(2048);
							if($chunkVersion < 4){
								$blockSkyLight = $binaryStream->get(2048);
								$blockLight = $binaryStream->get(2048);
								$hasBeenUpgraded = true; //drop saved light
							}else{
								//Mojang didn't bother changing the subchunk version when they stopped saving sky light -_-
								$blockSkyLight = "";
								$blockLight = "";
								$lightPopulated = false;
							}

							$subChunks[$y] = new SubChunk($blocks, $blockData, $blockSkyLight, $blockLight);
							break;
						default:
							//TODO: set chunks read-only so the version on disk doesn't get overwritten
							throw new UnsupportedChunkFormatException("don't know how to decode LevelDB subchunk format version $subChunkVersion");
					}
				}

				if(($maps2d = $this->db->get($index . self::TAG_DATA_2D)) !== false){
					$binaryStream->setBuffer($maps2d, 0);

					$heightMap = array_values(unpack("v*", $binaryStream->get(512)));
					$biomeIds = $binaryStream->get(256);
				}
				break;
			case 2: // < MCPE 1.0
				$binaryStream->setBuffer($this->db->get($index . self::TAG_LEGACY_TERRAIN));
				$fullIds = $binaryStream->get(32768);
				$fullData = $binaryStream->get(16384);
				$fullSkyLight = $binaryStream->get(16384);
				$fullBlockLight = $binaryStream->get(16384);

				for($yy = 0; $yy < 8; ++$yy){
					$subOffset = ($yy << 4);
					$ids = "";
					for($i = 0; $i < 256; ++$i){
						$ids .= substr($fullIds, $subOffset, 16);
						$subOffset += 128;
					}
					$data = "";
					$subOffset = ($yy << 3);
					for($i = 0; $i < 256; ++$i){
						$data .= substr($fullData, $subOffset, 8);
						$subOffset += 64;
					}
					$skyLight = "";
					$subOffset = ($yy << 3);
					for($i = 0; $i < 256; ++$i){
						$skyLight .= substr($fullSkyLight, $subOffset, 8);
						$subOffset += 64;
					}
					$blockLight = "";
					$subOffset = ($yy << 3);
					for($i = 0; $i < 256; ++$i){
						$blockLight .= substr($fullBlockLight, $subOffset, 8);
						$subOffset += 64;
					}
					$subChunks[$yy] = new SubChunk($ids, $data, $skyLight, $blockLight);
				}

				$heightMap = array_values(unpack("C*", $binaryStream->get(256)));
				$biomeIds = ChunkUtils::convertBiomeColors(array_values(unpack("N*", $binaryStream->get(1024))));
				break;
			default:
				//TODO: set chunks read-only so the version on disk doesn't get overwritten
				throw new UnsupportedChunkFormatException("don't know how to decode chunk format version $chunkVersion");
		}

		$nbt = new LittleEndianNBTStream();

		/** @var CompoundTag[] $entities */
		$entities = [];
		if(($entityData = $this->db->get($index . self::TAG_ENTITY)) !== false and $entityData !== ""){
			$entityTags = $nbt->read($entityData, true);
			foreach((is_array($entityTags) ? $entityTags : [$entityTags]) as $entityTag){
				if(!($entityTag instanceof CompoundTag)){
					throw new CorruptedChunkException("Entity root tag should be TAG_Compound");
				}
				if($entityTag->hasTag("id", IntTag::class)){
					$entityTag->setInt("id", $entityTag->getInt("id") & 0xff); //remove type flags - TODO: use these instead of removing them)
				}
				$entities[] = $entityTag;
			}
		}

		/** @var CompoundTag[] $tiles */
		$tiles = [];
		if(($tileData = $this->db->get($index . self::TAG_BLOCK_ENTITY)) !== false and $tileData !== ""){
			$tileTags = $nbt->read($tileData, true);
			foreach((is_array($tileTags) ? $tileTags : [$tileTags]) as $tileTag){
				if(!($tileTag instanceof CompoundTag)){
					throw new CorruptedChunkException("Tile root tag should be TAG_Compound");
				}
				$tiles[] = $tileTag;
			}
		}

		//TODO: extra data should be converted into blockstorage layers (first they need to be implemented!)
		/*
		$extraData = [];
		if(($extraRawData = $this->db->get($index . self::TAG_BLOCK_EXTRA_DATA)) !== false and $extraRawData !== ""){
			$binaryStream->setBuffer($extraRawData, 0);
			$count = $binaryStream->getLInt();
			for($i = 0; $i < $count; ++$i){
				$key = $binaryStream->getLInt();
				$value = $binaryStream->getLShort();
				$extraData[$key] = $value;
			}
		}*/

		$chunk = new Chunk(
			$chunkX,
			$chunkZ,
			$subChunks,
			$entities,
			$tiles,
			$biomeIds,
			$heightMap
		);

		//TODO: tile ticks, biome states (?)

		$chunk->setGenerated(true);
		$chunk->setPopulated(true);
		$chunk->setLightPopulated($lightPopulated);
		$chunk->setChanged($hasBeenUpgraded); //trigger rewriting chunk to disk if it was converted from an older format

		return $chunk;
	}

	protected function writeChunk(Chunk $chunk) : void{
		$index = LevelDB::chunkIndex($chunk->getX(), $chunk->getZ());
		$this->db->put($index . self::TAG_VERSION, chr(self::CURRENT_LEVEL_CHUNK_VERSION));

		$subChunks = $chunk->getSubChunks();
		foreach($subChunks as $y => $subChunk){
			$key = $index . self::TAG_SUBCHUNK_PREFIX . chr($y);
			if($subChunk->isEmpty(false)){ //MCPE doesn't save light anymore as of 1.1
				$this->db->delete($key);
			}else{
				$this->db->put($key,
					chr(self::CURRENT_LEVEL_SUBCHUNK_VERSION) .
					$subChunk->getBlockIdArray() .
					$subChunk->getBlockDataArray()
				);
			}
		}

		$this->db->put($index . self::TAG_DATA_2D, pack("v*", ...$chunk->getHeightMapArray()) . $chunk->getBiomeIdArray());

		//TODO: use this properly
		$this->db->put($index . self::TAG_STATE_FINALISATION, chr(self::FINALISATION_DONE));

		/** @var CompoundTag[] $tiles */
		$tiles = [];
		foreach($chunk->getTiles() as $tile){
			$tiles[] = $tile->saveNBT();
		}
		$this->writeTags($tiles, $index . self::TAG_BLOCK_ENTITY);

		/** @var CompoundTag[] $entities */
		$entities = [];
		foreach($chunk->getSavableEntities() as $entity){
			$entity->saveNBT();
			$entities[] = $entity->namedtag;
		}
		$this->writeTags($entities, $index . self::TAG_ENTITY);

		$this->db->delete($index . self::TAG_DATA_2D_LEGACY);
		$this->db->delete($index . self::TAG_LEGACY_TERRAIN);
	}

	/**
	 * @param CompoundTag[] $targets
	 */
	private function writeTags(array $targets, string $index) : void{
		if(count($targets) > 0){
			$nbt = new LittleEndianNBTStream();
			$this->db->put($index, $nbt->write($targets));
		}else{
			$this->db->delete($index);
		}
	}

	public function getDatabase() : \LevelDB{
		return $this->db;
	}

	public static function chunkIndex(int $chunkX, int $chunkZ) : string{
		return (\pack("V", $chunkX)) . (\pack("V", $chunkZ));
	}

	private function chunkExists(int $chunkX, int $chunkZ) : bool{
		return $this->db->get(LevelDB::chunkIndex($chunkX, $chunkZ) . self::TAG_VERSION) !== false;
	}

	public function close(){
		$this->db->close();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\generator;

use pocketmine\level\generator\hell\Nether;
use pocketmine\level\generator\normal\Normal;
use function array_keys;
use function is_subclass_of;
use function strtolower;

final class GeneratorManager{
	/**
	 * @var string[] name => classname mapping
	 * @phpstan-var array<string, class-string<Generator>>
	 */
	private static $list = [];

	/**
	 * Registers the default known generators.
	 */
	public static function registerDefaultGenerators() : void{
		self::addGenerator(Flat::class, "flat");
		self::addGenerator(Normal::class, "normal");
		self::addGenerator(Normal::class, "default");
		self::addGenerator(Nether::class, "hell");
		self::addGenerator(Nether::class, "nether");
	}

	/**
	 * @param string $class Fully qualified name of class that extends \pocketmine\level\generator\Generator
	 * @param string $name Alias for this generator type that can be written in configs
	 * @param bool   $overwrite Whether to force overwriting any existing registered generator with the same name
	 * @phpstan-param class-string<Generator> $class
	 */
	public static function addGenerator(string $class, string $name, bool $overwrite = false) : void{
		if(!is_subclass_of($class, Generator::class)){
			throw new \InvalidArgumentException("Class $class does not extend " . Generator::class);
		}

		if(!$overwrite and isset(self::$list[$name = strtolower($name)])){
			throw new \InvalidArgumentException("Alias \"$name\" is already assigned");
		}

		self::$list[$name] = $class;
	}

	/**
	 * Returns a list of names for registered generators.
	 *
	 * @return string[]
	 */
	public static function getGeneratorList() : array{
		return array_keys(self::$list);
	}

	/**
	 * Returns a class name of a registered Generator matching the given name.
	 *
	 * @param bool   $throwOnMissing @deprecated this is for backwards compatibility only
	 *
	 * @return string Name of class that extends Generator
	 * @phpstan-return class-string<Generator>
	 *
	 * @throws \InvalidArgumentException if the generator type isn't registered
	 */
	public static function getGenerator(string $name, bool $throwOnMissing = false){
		if(isset(self::$list[$name = strtolower($name)])){
			return self::$list[$name];
		}

		if($throwOnMissing){
			throw new \InvalidArgumentException("Alias \"$name\" does not map to any known generator");
		}
		return Normal::class;
	}

	/**
	 * Returns the registered name of the given Generator class.
	 *
	 * @param string $class Fully qualified name of class that extends \pocketmine\level\generator\Generator
	 * @phpstan-param class-string<Generator> $class
	 */
	public static function getGeneratorName(string $class) : string{
		foreach(self::$list as $name => $c){
			if($c === $class){
				return $name;
			}
		}

		return "unknown";
	}

	private function __construct(){
		//NOOP
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\generator;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\item\ItemFactory;
use pocketmine\level\ChunkManager;
use pocketmine\level\format\Chunk;
use pocketmine\level\generator\object\OreType;
use pocketmine\level\generator\populator\Ore;
use pocketmine\level\generator\populator\Populator;
use pocketmine\math\Vector3;
use pocketmine\utils\Random;
use function array_map;
use function count;
use function explode;
use function preg_match;
use function preg_match_all;

class Flat extends Generator{
	/** @var Chunk */
	private $chunk;
	/** @var Populator[] */
	private $populators = [];
	/**
	 * @var int[][]
	 * @phpstan-var array<int, array{0: int, 1: int}>
	 */
	private $structure;
	/** @var int */
	private $floorLevel;
	/** @var int */
	private $biome;
	/**
	 * @var mixed[]
	 * @phpstan-var array<string, mixed>
	 */
	private $options;
	/** @var string */
	private $preset;

	public function getSettings() : array{
		return $this->options;
	}

	public function getName() : string{
		return "flat";
	}

	/**
	 * @param mixed[] $options
	 * @phpstan-param array<string, mixed> $options
	 *
	 * @throws InvalidGeneratorOptionsException
	 */
	public function __construct(array $options = []){
		$this->options = $options;
		if(isset($this->options["preset"]) and $this->options["preset"] != ""){
			$this->preset = $this->options["preset"];
		}else{
			$this->preset = "2;7,2x3,2;1;";
			//$this->preset = "2;7,59x1,3x3,2;1;spawn(radius=10 block=89),decoration(treecount=80 grasscount=45)";
		}

		$this->parsePreset();

		if(isset($this->options["decoration"])){
			$ores = new Ore();
			$ores->setOreTypes([
				new OreType(BlockFactory::get(Block::COAL_ORE), 20, 16, 0, 128),
				new OreType(BlockFactory::get(Block::IRON_ORE), 20, 8, 0, 64),
				new OreType(BlockFactory::get(Block::REDSTONE_ORE), 8, 7, 0, 16),
				new OreType(BlockFactory::get(Block::LAPIS_ORE), 1, 6, 0, 32),
				new OreType(BlockFactory::get(Block::GOLD_ORE), 2, 8, 0, 32),
				new OreType(BlockFactory::get(Block::DIAMOND_ORE), 1, 7, 0, 16),
				new OreType(BlockFactory::get(Block::DIRT), 20, 32, 0, 128),
				new OreType(BlockFactory::get(Block::GRAVEL), 10, 16, 0, 128)
			]);
			$this->populators[] = $ores;
		}
	}

	/**
	 * @return int[][]
	 * @phpstan-return array<int, array{0: int, 1: int}>
	 *
	 * @throws InvalidGeneratorOptionsException
	 */
	public static function parseLayers(string $layers) : array{
		$result = [];
		$split = array_map('\trim', explode(',', $layers));
		$y = 0;
		foreach($split as $line){
			preg_match('#^(?:(\d+)[x|*])?(.+)$#', $line, $matches);
			if(count($matches) !== 3){
				throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\"");
			}

			$cnt = $matches[1] !== "" ? (int) $matches[1] : 1;
			try{
				$b = ItemFactory::fromString($matches[2])->getBlock();
			}catch(\InvalidArgumentException $e){
				throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\": " . $e->getMessage(), 0, $e);
			}
			for($cY = $y, $y += $cnt; $cY < $y; ++$cY){
				$result[$cY] = [$b->getId(), $b->getDamage()];
			}
		}

		return $result;
	}

	protected function parsePreset() : void{
		$preset = explode(";", $this->preset);
		$blocks = $preset[1] ?? "";
		$this->biome = (int) ($preset[2] ?? 1);
		$options = $preset[3] ?? "";
		$this->structure = self::parseLayers($blocks);

		$this->floorLevel = count($this->structure);

		//TODO: more error checking
		preg_match_all('#(([0-9a-z_]{1,})\(?([0-9a-z_ =:]{0,})\)?),?#', $options, $matches);
		foreach($matches[2] as $i => $option){
			$params = true;
			if($matches[3][$i] !== ""){
				$params = [];
				$p = explode(" ", $matches[3][$i]);
				foreach($p as $k){
					$k = explode("=", $k);
					if(isset($k[1])){
						$params[$k[0]] = $k[1];
					}
				}
			}
			$this->options[$option] = $params;
		}
	}

	protected function generateBaseChunk() : void{
		$this->chunk = new Chunk(0, 0);
		$this->chunk->setGenerated();

		for($Z = 0; $Z < 16; ++$Z){
			for($X = 0; $X < 16; ++$X){
				$this->chunk->setBiomeId($X, $Z, $this->biome);
			}
		}

		$count = count($this->structure);
		for($sy = 0; $sy < $count; $sy += 16){
			$subchunk = $this->chunk->getSubChunk($sy >> 4, true);
			for($y = 0; $y < 16 and isset($this->structure[$y | $sy]); ++$y){
				list($id, $meta) = $this->structure[$y | $sy];

				for($Z = 0; $Z < 16; ++$Z){
					for($X = 0; $X < 16; ++$X){
						$subchunk->setBlock($X, $y, $Z, $id, $meta);
					}
				}
			}
		}
	}

	public function init(ChunkManager $level, Random $random) : void{
		parent::init($level, $random);
		$this->generateBaseChunk();
	}

	public function generateChunk(int $chunkX, int $chunkZ) : void{
		$chunk = clone $this->chunk;
		$chunk->setX($chunkX);
		$chunk->setZ($chunkZ);
		$this->level->setChunk($chunkX, $chunkZ, $chunk);
	}

	public function populateChunk(int $chunkX, int $chunkZ) : void{
		$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
		foreach($this->populators as $populator){
			$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
		}

	}

	public function getSpawn() : Vector3{
		return new Vector3(128, $this->floorLevel, 128);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Noise classes used in Levels
 */
namespace pocketmine\level\generator;

use pocketmine\level\ChunkManager;
use pocketmine\math\Vector3;
use pocketmine\utils\Random;
use pocketmine\utils\Utils;
use function preg_match;

abstract class Generator{

	/**
	 * Converts a string level seed into an integer for use by the generator.
	 */
	public static function convertSeed(string $seed) : ?int{
		if($seed === ""){ //empty seed should cause a random seed to be selected - can't use 0 here because 0 is a valid seed
			$convertedSeed = null;
		}elseif(preg_match('/^-?\d+$/', $seed) === 1){ //this avoids treating seeds like "404.4" as integer seeds
			$convertedSeed = (int) $seed;
		}else{
			$convertedSeed = Utils::javaStringHash($seed);
		}

		return $convertedSeed;
	}

	/** @var ChunkManager */
	protected $level;
	/** @var Random */
	protected $random;

	/**
	 * @throws InvalidGeneratorOptionsException
	 *
	 * @param mixed[] $settings
	 * @phpstan-param array<string, mixed> $settings
	 */
	abstract public function __construct(array $settings = []);

	public function init(ChunkManager $level, Random $random) : void{
		$this->level = $level;
		$this->random = $random;
	}

	abstract public function generateChunk(int $chunkX, int $chunkZ) : void;

	abstract public function populateChunk(int $chunkX, int $chunkZ) : void;

	/**
	 * @return mixed[]
	 * @phpstan-return array<string, mixed>
	 */
	abstract public function getSettings() : array;

	abstract public function getName() : string;

	abstract public function getSpawn() : Vector3;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\generator\normal;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\level\biome\Biome;
use pocketmine\level\ChunkManager;
use pocketmine\level\generator\biome\BiomeSelector;
use pocketmine\level\generator\Generator;
use pocketmine\level\generator\InvalidGeneratorOptionsException;
use pocketmine\level\generator\noise\Simplex;
use pocketmine\level\generator\object\OreType;
use pocketmine\level\generator\populator\GroundCover;
use pocketmine\level\generator\populator\Ore;
use pocketmine\level\generator\populator\Populator;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\utils\Random;
use function exp;

class Normal extends Generator{

	/** @var Populator[] */
	private $populators = [];
	/** @var int */
	private $waterHeight = 62;

	/** @var Populator[] */
	private $generationPopulators = [];
	/** @var Simplex */
	private $noiseBase;

	/** @var BiomeSelector */
	private $selector;

	/** @var float[][]|null */
	private static $GAUSSIAN_KERNEL = null;
	/** @var int */
	private static $SMOOTH_SIZE = 2;

	/**
	 * @param mixed[] $options
	 * @phpstan-param array<string, mixed> $options
	 *
	 * @throws InvalidGeneratorOptionsException
	 */
	public function __construct(array $options = []){
		if(self::$GAUSSIAN_KERNEL === null){
			self::generateKernel();
		}
	}

	private static function generateKernel() : void{
		self::$GAUSSIAN_KERNEL = [];

		$bellSize = 1 / self::$SMOOTH_SIZE;
		$bellHeight = 2 * self::$SMOOTH_SIZE;

		for($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx){
			self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE] = [];

			for($sz = -self::$SMOOTH_SIZE; $sz <= self::$SMOOTH_SIZE; ++$sz){
				$bx = $bellSize * $sx;
				$bz = $bellSize * $sz;
				self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE][$sz + self::$SMOOTH_SIZE] = $bellHeight * exp(-($bx * $bx + $bz * $bz) / 2);
			}
		}
	}

	public function getName() : string{
		return "normal";
	}

	public function getSettings() : array{
		return [];
	}

	private function pickBiome(int $x, int $z) : Biome{
		$hash = $x * 2345803 ^ $z * 9236449 ^ $this->level->getSeed();
		$hash *= $hash + 223;
		$xNoise = $hash >> 20 & 3;
		$zNoise = $hash >> 22 & 3;
		if($xNoise == 3){
			$xNoise = 1;
		}
		if($zNoise == 3){
			$zNoise = 1;
		}

		return $this->selector->pickBiome($x + $xNoise - 1, $z + $zNoise - 1);
	}

	public function init(ChunkManager $level, Random $random) : void{
		parent::init($level, $random);
		$this->random->setSeed($this->level->getSeed());
		$this->noiseBase = new Simplex($this->random, 4, 1 / 4, 1 / 32);
		$this->random->setSeed($this->level->getSeed());
		$this->selector = new class($this->random) extends BiomeSelector{
			protected function lookup(float $temperature, float $rainfall) : int{
				if($rainfall < 0.25){
					if($temperature < 0.7){
						return Biome::OCEAN;
					}elseif($temperature < 0.85){
						return Biome::RIVER;
					}else{
						return Biome::SWAMP;
					}
				}elseif($rainfall < 0.60){
					if($temperature < 0.25){
						return Biome::ICE_PLAINS;
					}elseif($temperature < 0.75){
						return Biome::PLAINS;
					}else{
						return Biome::DESERT;
					}
				}elseif($rainfall < 0.80){
					if($temperature < 0.25){
						return Biome::TAIGA;
					}elseif($temperature < 0.75){
						return Biome::FOREST;
					}else{
						return Biome::BIRCH_FOREST;
					}
				}else{
					//FIXME: This will always cause River to be used since the rainfall is always greater than 0.8 if we
					//reached this branch. However I don't think that substituting temperature for rainfall is correct given
					//that mountain biomes are supposed to be pretty cold.
					if($rainfall < 0.25){
						return Biome::MOUNTAINS;
					}elseif($rainfall < 0.70){
						return Biome::SMALL_MOUNTAINS;
					}else{
						return Biome::RIVER;
					}
				}
			}
		};

		$this->selector->recalculate();

		$cover = new GroundCover();
		$this->generationPopulators[] = $cover;

		$ores = new Ore();
		$ores->setOreTypes([
			new OreType(BlockFactory::get(Block::COAL_ORE), 20, 16, 0, 128),
			new OreType(BlockFactory::get(Block::IRON_ORE), 20, 8, 0, 64),
			new OreType(BlockFactory::get(Block::REDSTONE_ORE), 8, 7, 0, 16),
			new OreType(BlockFactory::get(Block::LAPIS_ORE), 1, 6, 0, 32),
			new OreType(BlockFactory::get(Block::GOLD_ORE), 2, 8, 0, 32),
			new OreType(BlockFactory::get(Block::DIAMOND_ORE), 1, 7, 0, 16),
			new OreType(BlockFactory::get(Block::DIRT), 20, 32, 0, 128),
			new OreType(BlockFactory::get(Block::GRAVEL), 10, 16, 0, 128)
		]);
		$this->populators[] = $ores;
	}

	public function generateChunk(int $chunkX, int $chunkZ) : void{
		$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());

		$noise = $this->noiseBase->getFastNoise3D(16, 128, 16, 4, 8, 4, $chunkX * 16, 0, $chunkZ * 16);

		$chunk = $this->level->getChunk($chunkX, $chunkZ);

		$biomeCache = [];

		for($x = 0; $x < 16; ++$x){
			for($z = 0; $z < 16; ++$z){
				$minSum = 0;
				$maxSum = 0;
				$weightSum = 0;

				$biome = $this->pickBiome($chunkX * 16 + $x, $chunkZ * 16 + $z);
				$chunk->setBiomeId($x, $z, $biome->getId());

				for($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx){
					for($sz = -self::$SMOOTH_SIZE; $sz <= self::$SMOOTH_SIZE; ++$sz){

						$weight = self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE][$sz + self::$SMOOTH_SIZE];

						if($sx === 0 and $sz === 0){
							$adjacent = $biome;
						}else{
							$index = ((($chunkX * 16 + $x + $sx) & 0xFFFFFFFF) << 32) | (( $chunkZ * 16 + $z + $sz) & 0xFFFFFFFF);
							if(isset($biomeCache[$index])){
								$adjacent = $biomeCache[$index];
							}else{
								$biomeCache[$index] = $adjacent = $this->pickBiome($chunkX * 16 + $x + $sx, $chunkZ * 16 + $z + $sz);
							}
						}

						$minSum += ($adjacent->getMinElevation() - 1) * $weight;
						$maxSum += $adjacent->getMaxElevation() * $weight;

						$weightSum += $weight;
					}
				}

				$minSum /= $weightSum;
				$maxSum /= $weightSum;

				$smoothHeight = ($maxSum - $minSum) / 2;

				for($y = 0; $y < 128; ++$y){
					if($y === 0){
						$chunk->setBlockId($x, $y, $z, Block::BEDROCK);
						continue;
					}
					$noiseValue = $noise[$x][$z][$y] - 1 / $smoothHeight * ($y - $smoothHeight - $minSum);

					if($noiseValue > 0){
						$chunk->setBlockId($x, $y, $z, Block::STONE);
					}elseif($y <= $this->waterHeight){
						$chunk->setBlockId($x, $y, $z, Block::STILL_WATER);
					}
				}
			}
		}

		foreach($this->generationPopulators as $populator){
			$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
		}
	}

	public function populateChunk(int $chunkX, int $chunkZ) : void{
		$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
		foreach($this->populators as $populator){
			$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
		}

		$chunk = $this->level->getChunk($chunkX, $chunkZ);
		$biome = Biome::getBiome($chunk->getBiomeId(7, 7));
		$biome->populateChunk($this->level, $chunkX, $chunkZ, $this->random);
	}

	public function getSpawn() : Vector3{
		return new Vector3(127.5, 128, 127.5);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\generator\hell;

use pocketmine\block\Block;
use pocketmine\level\biome\Biome;
use pocketmine\level\ChunkManager;
use pocketmine\level\generator\Generator;
use pocketmine\level\generator\InvalidGeneratorOptionsException;
use pocketmine\level\generator\noise\Simplex;
use pocketmine\level\generator\populator\Populator;
use pocketmine\math\Vector3;
use pocketmine\utils\Random;
use function abs;

class Nether extends Generator{

	/** @var Populator[] */
	private $populators = [];
	/** @var int */
	private $waterHeight = 32;
	/** @var int */
	private $emptyHeight = 64;
	/** @var int */
	private $emptyAmplitude = 1;
	/** @var float */
	private $density = 0.5;

	/** @var Populator[] */
	private $generationPopulators = [];
	/** @var Simplex */
	private $noiseBase;

	/**
	 * @param mixed[] $options
	 * @phpstan-param array<string, mixed> $options
	 *
	 * @throws InvalidGeneratorOptionsException
	 */
	public function __construct(array $options = []){

	}

	public function getName() : string{
		return "nether";
	}

	public function getSettings() : array{
		return [];
	}

	public function init(ChunkManager $level, Random $random) : void{
		parent::init($level, $random);
		$this->random->setSeed($this->level->getSeed());
		$this->noiseBase = new Simplex($this->random, 4, 1 / 4, 1 / 64);
		$this->random->setSeed($this->level->getSeed());

		/*$ores = new Ore();
		$ores->setOreTypes([
			new OreType(new CoalOre(), 20, 16, 0, 128),
			new OreType(New IronOre(), 20, 8, 0, 64),
			new OreType(new RedstoneOre(), 8, 7, 0, 16),
			new OreType(new LapisOre(), 1, 6, 0, 32),
			new OreType(new GoldOre(), 2, 8, 0, 32),
			new OreType(new DiamondOre(), 1, 7, 0, 16),
			new OreType(new Dirt(), 20, 32, 0, 128),
			new OreType(new Gravel(), 10, 16, 0, 128)
		]);
		$this->populators[] = $ores;*/
	}

	public function generateChunk(int $chunkX, int $chunkZ) : void{
		$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());

		$noise = $this->noiseBase->getFastNoise3D(16, 128, 16, 4, 8, 4, $chunkX * 16, 0, $chunkZ * 16);

		$chunk = $this->level->getChunk($chunkX, $chunkZ);

		for($x = 0; $x < 16; ++$x){
			for($z = 0; $z < 16; ++$z){

				$biome = Biome::getBiome(Biome::HELL);
				$chunk->setBiomeId($x, $z, $biome->getId());

				for($y = 0; $y < 128; ++$y){
					if($y === 0 or $y === 127){
						$chunk->setBlockId($x, $y, $z, Block::BEDROCK);
						continue;
					}
					$noiseValue = (abs($this->emptyHeight - $y) / $this->emptyHeight) * $this->emptyAmplitude - $noise[$x][$z][$y];
					$noiseValue -= 1 - $this->density;

					if($noiseValue > 0){
						$chunk->setBlockId($x, $y, $z, Block::NETHERRACK);
					}elseif($y <= $this->waterHeight){
						$chunk->setBlockId($x, $y, $z, Block::STILL_LAVA);
					}
				}
			}
		}

		foreach($this->generationPopulators as $populator){
			$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
		}
	}

	public function populateChunk(int $chunkX, int $chunkZ) : void{
		$this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed());
		foreach($this->populators as $populator){
			$populator->populate($this->level, $chunkX, $chunkZ, $this->random);
		}

		$chunk = $this->level->getChunk($chunkX, $chunkZ);
		$biome = Biome::getBiome($chunk->getBiomeId(7, 7));
		$biome->populateChunk($this->level, $chunkX, $chunkZ, $this->random);
	}

	public function getSpawn() : Vector3{
		return new Vector3(127.5, 128, 127.5);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
use pocketmine\Server;
use pocketmine\timings\Timings;
use function array_map;
use function file_get_contents;
use function json_decode;
use function json_encode;
use function usort;
use const DIRECTORY_SEPARATOR;

class CraftingManager{
	/** @var ShapedRecipe[][] */
	protected $shapedRecipes = [];
	/** @var ShapelessRecipe[][] */
	protected $shapelessRecipes = [];
	/** @var FurnaceRecipe[] */
	protected $furnaceRecipes = [];

	/** @var BatchPacket|null */
	private $craftingDataCache;

	public function __construct(){
		$this->init();
	}

	public function init() : void{
		$recipes = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla" . DIRECTORY_SEPARATOR . "recipes.json"), true);

		$itemDeserializerFunc = \Closure::fromCallable([Item::class, 'jsonDeserialize']);
		foreach($recipes as $recipe){
			switch($recipe["type"]){
				case "shapeless":
					if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
						break;
					}
					$this->registerRecipe(new ShapelessRecipe(
						array_map($itemDeserializerFunc, $recipe["input"]),
						array_map($itemDeserializerFunc, $recipe["output"])
					));
					break;
				case "shaped":
					if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
						break;
					}
					$this->registerRecipe(new ShapedRecipe(
						$recipe["shape"],
						array_map($itemDeserializerFunc, $recipe["input"]),
						array_map($itemDeserializerFunc, $recipe["output"])
					));
					break;
				case "smelting":
					if($recipe["block"] !== "furnace"){ //TODO: filter others out for now to avoid breaking economics
						break;
					}
					$this->registerRecipe(new FurnaceRecipe(
						Item::jsonDeserialize($recipe["output"]),
						Item::jsonDeserialize($recipe["input"]))
					);
					break;
				default:
					break;
			}
		}

		$this->buildCraftingDataCache();
	}

	/**
	 * Rebuilds the cached CraftingDataPacket.
	 */
	public function buildCraftingDataCache() : void{
		Timings::$craftingDataCacheRebuildTimer->startTiming();
		$pk = new CraftingDataPacket();
		$pk->cleanRecipes = true;

		foreach($this->shapelessRecipes as $list){
			foreach($list as $recipe){
				$pk->addShapelessRecipe($recipe);
			}
		}
		foreach($this->shapedRecipes as $list){
			foreach($list as $recipe){
				$pk->addShapedRecipe($recipe);
			}
		}

		foreach($this->furnaceRecipes as $recipe){
			$pk->addFurnaceRecipe($recipe);
		}

		$pk->encode();

		$batch = new BatchPacket();
		$batch->addPacket($pk);
		$batch->setCompressionLevel(Server::getInstance()->networkCompressionLevel);
		$batch->encode();

		$this->craftingDataCache = $batch;
		Timings::$craftingDataCacheRebuildTimer->stopTiming();
	}

	/**
	 * Returns a pre-compressed CraftingDataPacket for sending to players. Rebuilds the cache if it is not found.
	 */
	public function getCraftingDataPacket() : BatchPacket{
		if($this->craftingDataCache === null){
			$this->buildCraftingDataCache();
		}

		return $this->craftingDataCache;
	}

	/**
	 * Function used to arrange Shapeless Recipe ingredient lists into a consistent order.
	 *
	 * @return int
	 */
	public static function sort(Item $i1, Item $i2){
		//Use spaceship operator to compare each property, then try the next one if they are equivalent.
		($retval = $i1->getId() <=> $i2->getId()) === 0 && ($retval = $i1->getDamage() <=> $i2->getDamage()) === 0 && ($retval = $i1->getCount() <=> $i2->getCount()) === 0;

		return $retval;
	}

	/**
	 * @param Item[] $items
	 *
	 * @return Item[]
	 */
	private static function pack(array $items) : array{
		/** @var Item[] $result */
		$result = [];

		foreach($items as $i => $item){
			foreach($result as $otherItem){
				if($item->equals($otherItem)){
					$otherItem->setCount($otherItem->getCount() + $item->getCount());
					continue 2;
				}
			}

			//No matching item found
			$result[] = clone $item;
		}

		return $result;
	}

	/**
	 * @param Item[] $outputs
	 */
	private static function hashOutputs(array $outputs) : string{
		$outputs = self::pack($outputs);
		usort($outputs, [self::class, "sort"]);
		foreach($outputs as $o){
			//this reduces accuracy of hash, but it's necessary to deal with recipe book shift-clicking stupidity
			$o->setCount(1);
		}

		return json_encode($outputs);
	}

	/**
	 * @return ShapelessRecipe[][]
	 */
	public function getShapelessRecipes() : array{
		return $this->shapelessRecipes;
	}

	/**
	 * @return ShapedRecipe[][]
	 */
	public function getShapedRecipes() : array{
		return $this->shapedRecipes;
	}

	/**
	 * @return FurnaceRecipe[]
	 */
	public function getFurnaceRecipes() : array{
		return $this->furnaceRecipes;
	}

	public function registerShapedRecipe(ShapedRecipe $recipe) : void{
		$this->shapedRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;

		$this->craftingDataCache = null;
	}

	public function registerShapelessRecipe(ShapelessRecipe $recipe) : void{
		$this->shapelessRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;

		$this->craftingDataCache = null;
	}

	public function registerFurnaceRecipe(FurnaceRecipe $recipe) : void{
		$input = $recipe->getInput();
		$this->furnaceRecipes[$input->getId() . ":" . ($input->hasAnyDamageValue() ? "?" : $input->getDamage())] = $recipe;
		$this->craftingDataCache = null;
	}

	/**
	 * @param Item[]       $outputs
	 */
	public function matchRecipe(CraftingGrid $grid, array $outputs) : ?CraftingRecipe{
		//TODO: try to match special recipes before anything else (first they need to be implemented!)

		$outputHash = self::hashOutputs($outputs);

		if(isset($this->shapedRecipes[$outputHash])){
			foreach($this->shapedRecipes[$outputHash] as $recipe){
				if($recipe->matchesCraftingGrid($grid)){
					return $recipe;
				}
			}
		}

		if(isset($this->shapelessRecipes[$outputHash])){
			foreach($this->shapelessRecipes[$outputHash] as $recipe){
				if($recipe->matchesCraftingGrid($grid)){
					return $recipe;
				}
			}
		}

		return null;
	}

	/**
	 * @param Item[] $outputs
	 *
	 * @return CraftingRecipe[]|\Generator
	 * @phpstan-return \Generator<int, CraftingRecipe, void, void>
	 */
	public function matchRecipeByOutputs(array $outputs) : \Generator{
		//TODO: try to match special recipes before anything else (first they need to be implemented!)

		$outputHash = self::hashOutputs($outputs);

		if(isset($this->shapedRecipes[$outputHash])){
			foreach($this->shapedRecipes[$outputHash] as $recipe){
				yield $recipe;
			}
		}

		if(isset($this->shapelessRecipes[$outputHash])){
			foreach($this->shapelessRecipes[$outputHash] as $recipe){
				yield $recipe;
			}
		}
	}

	public function matchFurnaceRecipe(Item $input) : ?FurnaceRecipe{
		return $this->furnaceRecipes[$input->getId() . ":" . $input->getDamage()] ?? $this->furnaceRecipes[$input->getId() . ":?"] ?? null;
	}

	public function registerRecipe(Recipe $recipe) : void{
		$recipe->registerToCraftingManager($this);
	}
}
[{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":340,"damage":-1}},"output":[{"id":47}],"priority":50,"recipe_id":"Bookshelf_woodplanks_recipeId","shape":["AAA","BBB","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1}},"output":[{"id":281,"count":4}],"priority":50,"recipe_id":"Bowl_recipeId","shape":["A A"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4}},"output":[{"id":-140}],"priority":50,"recipe_id":"ButtonAcacia_recipeId","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2}},"output":[{"id":-141}],"priority":50,"recipe_id":"ButtonBirch_recipeId","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5}},"output":[{"id":-142}],"priority":50,"recipe_id":"ButtonDarkOak_recipeId","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3}},"output":[{"id":-143}],"priority":50,"recipe_id":"ButtonJungle_recipeId","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1}},"output":[{"id":-144}],"priority":50,"recipe_id":"ButtonSpruce_recipeId","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1}},"output":[{"id":54}],"priority":50,"recipe_id":"Chest_recipeId","shape":["AAA","A A","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20},"B":{"id":406,"damage":-1},"C":{"id":158,"damage":-1}},"output":[{"id":151}],"priority":50,"recipe_id":"DaylightDetector_recipeId","shape":["AAA","BBB","CCC"],"type":"shaped"},{"block":"crafting_table","input":[{"id":377,"damage":-1},{"id":263,"damage":1},{"id":289,"damage":-1}],"output":[{"id":385,"count":3}],"priority":50,"recipe_id":"FireCharge_blaze_powder_coal_sulphur_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":377,"damage":-1},{"id":263,"damage":-1},{"id":289,"damage":-1}],"output":[{"id":385,"count":3}],"priority":50,"recipe_id":"FireCharge_coal_sulphur_recipeId","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":264,"damage":-1}},"output":[{"id":84}],"priority":50,"recipe_id":"Jukebox_recipeId","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":331,"damage":-1}},"output":[{"id":25}],"priority":50,"recipe_id":"Note_recipeId","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4}},"output":[{"id":44,"damage":3,"count":6}],"priority":50,"recipe_id":"Painting_Cobblestone_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":112}},"output":[{"id":44,"damage":7,"count":6}],"priority":50,"recipe_id":"Painting_NetherBrick_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":24}},"output":[{"id":44,"damage":1,"count":6}],"priority":50,"recipe_id":"Painting_VanillaBlocks_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":35,"damage":-1}},"output":[{"id":321}],"priority":50,"recipe_id":"Painting_recipeId","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":4},"C":{"id":265,"damage":-1},"D":{"id":331,"damage":-1}},"output":[{"id":33,"damage":1}],"priority":50,"recipe_id":"Piston_recipeId","shape":["AAA","BCB","BDB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4}},"output":[{"id":-150}],"priority":50,"recipe_id":"PressurePlateAcacia_recipeId","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2}},"output":[{"id":-151}],"priority":50,"recipe_id":"PressurePlateBirch_recipeId","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5}},"output":[{"id":-152}],"priority":50,"recipe_id":"PressurePlateDarkOak_recipeId","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3}},"output":[{"id":-153}],"priority":50,"recipe_id":"PressurePlateJungle_recipeId","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1}},"output":[{"id":-154}],"priority":50,"recipe_id":"PressurePlateSpruce_recipeId","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-163}},"output":[{"id":280}],"priority":2,"recipe_id":"Stick_bamboo_recipeId","shape":["A","A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1}},"output":[{"id":-166,"damage":2,"count":6}],"priority":50,"recipe_id":"StoneSlab4_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":98,"damage":1}},"output":[{"id":-166,"count":6}],"priority":50,"recipe_id":"StoneSlab4_stoneBrick_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":45}},"output":[{"id":44,"damage":4,"count":6}],"priority":50,"recipe_id":"StoneSlab_Brick_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":98}},"output":[{"id":44,"damage":5,"count":6}],"priority":50,"recipe_id":"StoneSlab_StoneBrick_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-183}},"output":[{"id":44,"count":6}],"priority":50,"recipe_id":"StoneSlab_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":263,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":50,"count":4}],"priority":50,"recipe_id":"Torch_recipeId","shape":["A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4}},"output":[{"id":-145,"count":2}],"priority":50,"recipe_id":"TrapdoorAcacia_recipeId","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2}},"output":[{"id":-146,"count":2}],"priority":50,"recipe_id":"TrapdoorBirch_recipeId","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5}},"output":[{"id":-147,"count":2}],"priority":50,"recipe_id":"TrapdoorDarkOak_recipeId","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3}},"output":[{"id":-148,"count":2}],"priority":50,"recipe_id":"TrapdoorJungle_recipeId","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1}},"output":[{"id":-149,"count":2}],"priority":50,"recipe_id":"TrapdoorSpruce_recipeId","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5}},"output":[{"id":96,"count":2}],"priority":50,"recipe_id":"Trapdoor_recipeId","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":280,"damage":-1},"C":{"id":5,"damage":-1}},"output":[{"id":131,"count":2}],"priority":50,"recipe_id":"TripwireHook_recipeId","shape":["A","B","C"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5}},"output":[{"id":143}],"priority":50,"recipe_id":"WoodButton_recipeId","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5}},"output":[{"id":72}],"priority":50,"recipe_id":"WoodPressurePlate_recipeId","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1}},"output":[{"id":58}],"priority":50,"recipe_id":"WorkBench_recipeId","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4}},"output":[{"id":163,"count":4}],"priority":50,"recipe_id":"acacia_stairs_acacia_recipeId","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":102},"C":{"id":499,"damage":14}},"output":[{"id":190,"count":3}],"priority":0,"recipe_id":"agb_glass_plane_recipeId","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":20},"C":{"id":499,"damage":14}},"output":[{"id":253,"count":3}],"priority":0,"recipe_id":"agb_glass_recipeId","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"type":"special_hardcoded","uuid":"d81aaeaf-e172-4440-9225-868df030d27b"},{"type":"special_hardcoded","uuid":"b5c5d105-75a2-4076-af2b-923ea2bf4bf0"},{"type":"special_hardcoded","uuid":"00000000-0000-0000-0000-000000000002"},{"block":"crafting_table","input":{"A":{"id":35},"B":{"id":5,"damage":-1}},"output":[{"id":355}],"priority":1,"recipe_id":"bed_color_0","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":1},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":1}],"priority":1,"recipe_id":"bed_color_1","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":10},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":10}],"priority":1,"recipe_id":"bed_color_10","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":11},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":11}],"priority":1,"recipe_id":"bed_color_11","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":12},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":12}],"priority":1,"recipe_id":"bed_color_12","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":13},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":13}],"priority":1,"recipe_id":"bed_color_13","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":14},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":14}],"priority":1,"recipe_id":"bed_color_14","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":15},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":15}],"priority":1,"recipe_id":"bed_color_15","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":2},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":2}],"priority":1,"recipe_id":"bed_color_2","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":3},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":3}],"priority":1,"recipe_id":"bed_color_3","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":4},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":4}],"priority":1,"recipe_id":"bed_color_4","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":5},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":5}],"priority":1,"recipe_id":"bed_color_5","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":6},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":6}],"priority":1,"recipe_id":"bed_color_6","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":7},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":7}],"priority":1,"recipe_id":"bed_color_7","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":8},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":8}],"priority":1,"recipe_id":"bed_color_8","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":9},"B":{"id":5,"damage":-1}},"output":[{"id":355,"damage":9}],"priority":1,"recipe_id":"bed_color_9","shape":["AAA","BBB"],"type":"shaped"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_0_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":10}],"output":[{"id":355,"damage":5}],"priority":50,"recipe_id":"bed_dye_10_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":11}],"output":[{"id":355,"damage":4}],"priority":50,"recipe_id":"bed_dye_11_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":12}],"output":[{"id":355,"damage":3}],"priority":50,"recipe_id":"bed_dye_12_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":13}],"output":[{"id":355,"damage":2}],"priority":50,"recipe_id":"bed_dye_13_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":14}],"output":[{"id":355,"damage":1}],"priority":50,"recipe_id":"bed_dye_14_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":15}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_15_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":16}],"output":[{"id":355,"damage":15}],"priority":50,"recipe_id":"bed_dye_16_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":17}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_17_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":18}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_18_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":19}],"output":[{"id":355}],"priority":50,"recipe_id":"bed_dye_19_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":1}],"output":[{"id":355,"damage":14}],"priority":50,"recipe_id":"bed_dye_1_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":2}],"output":[{"id":355,"damage":13}],"priority":50,"recipe_id":"bed_dye_2_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":3}],"output":[{"id":355,"damage":12}],"priority":50,"recipe_id":"bed_dye_3_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":4}],"output":[{"id":355,"damage":11}],"priority":50,"recipe_id":"bed_dye_4_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":5}],"output":[{"id":355,"damage":10}],"priority":50,"recipe_id":"bed_dye_5_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":6}],"output":[{"id":355,"damage":9}],"priority":50,"recipe_id":"bed_dye_6_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":7}],"output":[{"id":355,"damage":8}],"priority":50,"recipe_id":"bed_dye_7_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":6},{"id":351,"damage":8}],"output":[{"id":355,"damage":7}],"priority":50,"recipe_id":"bed_dye_8_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":15},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":14},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":5},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":4},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":3},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":2},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":1},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":355},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":13},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":12},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":11},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":10},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":9},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":8},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":355,"damage":7},{"id":351,"damage":9}],"output":[{"id":355,"damage":6}],"priority":50,"recipe_id":"bed_dye_9_8","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2}},"output":[{"id":135,"count":4}],"priority":50,"recipe_id":"birch_stairs_birch_recipeId","shape":["A  ","AA ","AAA"],"type":"shaped"},{"type":"special_hardcoded","uuid":"d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":15}],"priority":0,"recipe_id":"chemistry_balloon_0","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":1},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":14}],"priority":0,"recipe_id":"chemistry_balloon_1","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":10},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":5}],"priority":0,"recipe_id":"chemistry_balloon_10","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":11},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":4}],"priority":0,"recipe_id":"chemistry_balloon_11","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":12},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":3}],"priority":0,"recipe_id":"chemistry_balloon_12","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":13},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":2}],"priority":0,"recipe_id":"chemistry_balloon_13","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":14},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":1}],"priority":0,"recipe_id":"chemistry_balloon_14","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":15},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448}],"priority":0,"recipe_id":"chemistry_balloon_15","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":16},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":15}],"priority":0,"recipe_id":"chemistry_balloon_16","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":17},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":12}],"priority":0,"recipe_id":"chemistry_balloon_17","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":18},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":11}],"priority":0,"recipe_id":"chemistry_balloon_18","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":19},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448}],"priority":0,"recipe_id":"chemistry_balloon_19","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":2},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":13}],"priority":0,"recipe_id":"chemistry_balloon_2","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":3},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":12}],"priority":0,"recipe_id":"chemistry_balloon_3","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":4},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":11}],"priority":0,"recipe_id":"chemistry_balloon_4","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":5},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":10}],"priority":0,"recipe_id":"chemistry_balloon_5","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":6},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":9}],"priority":0,"recipe_id":"chemistry_balloon_6","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":7},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":8}],"priority":0,"recipe_id":"chemistry_balloon_7","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":8},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":7}],"priority":0,"recipe_id":"chemistry_balloon_8","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":30},"B":{"id":351,"damage":9},"C":{"id":-13},"D":{"id":420,"damage":-1}},"output":[{"id":448,"damage":6}],"priority":0,"recipe_id":"chemistry_balloon_9","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":15},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":15,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_0","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":14},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":14,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_1","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":5},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":5,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_10","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":4},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":4,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_11","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":3},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":3,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_12","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":2},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":2,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_13","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":1},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":1,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_14","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241},"C":{"id":499,"damage":14}},"output":[{"id":254,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_15","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":15},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":15,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_16","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":12},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":12,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_17","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":11},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":11,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_18","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241},"C":{"id":499,"damage":14}},"output":[{"id":254,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_19","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":13},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":13,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_2","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":12},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":12,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_3","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":11},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":11,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_4","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":10},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":10,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_5","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":9},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":9,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_6","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":8},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":8,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_7","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":7},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":7,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_8","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":241,"damage":6},"C":{"id":499,"damage":14}},"output":[{"id":254,"damage":6,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_9","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":15}},"output":[{"id":191,"damage":15,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_0","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":14}},"output":[{"id":191,"damage":14,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_1","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":5}},"output":[{"id":191,"damage":5,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_10","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":4}},"output":[{"id":191,"damage":4,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_11","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":3}},"output":[{"id":191,"damage":3,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_12","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":2}},"output":[{"id":191,"damage":2,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_13","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":1}},"output":[{"id":191,"damage":1,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_14","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254}},"output":[{"id":191,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_15","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":15}},"output":[{"id":191,"damage":15,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_16","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":12}},"output":[{"id":191,"damage":12,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_17","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":11}},"output":[{"id":191,"damage":11,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_18","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254}},"output":[{"id":191,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_19","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":13}},"output":[{"id":191,"damage":13,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_2","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":12}},"output":[{"id":191,"damage":12,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_3","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":11}},"output":[{"id":191,"damage":11,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_4","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":10}},"output":[{"id":191,"damage":10,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_5","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":9}},"output":[{"id":191,"damage":9,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_6","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":8}},"output":[{"id":191,"damage":8,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_7","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":7}},"output":[{"id":191,"damage":7,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_8","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":254,"damage":6}},"output":[{"id":191,"damage":6,"count":16}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_color_9","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351}},"output":[{"id":254,"damage":15,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_0","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":1}},"output":[{"id":254,"damage":14,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_1","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":10}},"output":[{"id":254,"damage":5,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_10","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":11}},"output":[{"id":254,"damage":4,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_11","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":12}},"output":[{"id":254,"damage":3,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_12","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":13}},"output":[{"id":254,"damage":2,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_13","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":14}},"output":[{"id":254,"damage":1,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_14","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":15}},"output":[{"id":254,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_15","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":16}},"output":[{"id":254,"damage":15,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_16","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":17}},"output":[{"id":254,"damage":12,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_17","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":18}},"output":[{"id":254,"damage":11,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_18","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":19}},"output":[{"id":254,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_19","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":2}},"output":[{"id":254,"damage":13,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_2","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":3}},"output":[{"id":254,"damage":12,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_3","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":4}},"output":[{"id":254,"damage":11,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_4","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":5}},"output":[{"id":254,"damage":10,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_5","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":6}},"output":[{"id":254,"damage":9,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_6","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":7}},"output":[{"id":254,"damage":8,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_7","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":8}},"output":[{"id":254,"damage":7,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_8","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":253},"B":{"id":351,"damage":9}},"output":[{"id":254,"damage":6,"count":8}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_dye_9","shape":["AAA","ABA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":15},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":15,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_0","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":14},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":14,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_1","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":5},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":5,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_10","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":4},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":4,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_11","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":3},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":3,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_12","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":2},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":2,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_13","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":1},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":1,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_14","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160},"C":{"id":499,"damage":14}},"output":[{"id":191,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_15","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":15},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":15,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_16","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":12},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":12,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_17","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":11},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":11,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_18","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160},"C":{"id":499,"damage":14}},"output":[{"id":191,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_19","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":13},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":13,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_2","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":12},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":12,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_3","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":11},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":11,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_4","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":10},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":10,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_5","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":9},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":9,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_6","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":8},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":8,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_7","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":7},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":7,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_8","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":13},"B":{"id":160,"damage":6},"C":{"id":499,"damage":14}},"output":[{"id":191,"damage":6,"count":3}],"priority":0,"recipe_id":"chemistry_hard_stained_glass_pane_9","shape":["AAA","BBB","CCC"],"type":"shaped_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":10}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_10_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":11}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_11_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":12}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_12_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":13}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_13_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":14}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_14_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":15}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_15_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":1}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_1_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":2}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_2_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":3}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_3_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":4}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_4_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":5}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_5_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":6}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_6_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":7}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_7_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":8}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_8_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":355,"damage":9}],"output":[{"id":355}],"priority":0,"recipe_id":"chemistry_notDyedBed_9_2","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":10}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_10_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":11}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_11_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":12}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_12_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":13}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_13_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":14}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_14_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":15}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_15_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":1}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_1_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":2}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_2_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":3}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_3_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":4}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_4_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":5}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_5_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":6}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_6_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":7}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_7_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":8}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_8_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":171,"damage":9}],"output":[{"id":171}],"priority":0,"recipe_id":"chemistry_notDyedCarpet_9_1","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":10}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_10_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":11}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_11_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":12}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_12_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":13}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_13_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":14}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_14_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_15_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":1}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_1_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":2}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_2_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":3}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_3_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":4}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_4_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":5}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_5_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":6}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_6_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":7}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_7_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":8}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_8_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":446,"damage":9}],"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"chemistry_notDyedStandingBanner_9_3","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":10}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_10_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":11}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_11_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":12}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_12_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":13}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_13_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":14}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_14_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":15}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_15_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":1}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_1_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":2}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_2_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":3}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_3_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":4}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_4_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":5}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_5_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":6}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_6_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":7}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_7_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":8}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_8_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":[{"id":451,"damage":-1},{"id":35,"damage":9}],"output":[{"id":35}],"priority":0,"recipe_id":"chemistry_notDyed_9_0","type":"shapeless_chemistry"},{"block":"crafting_table","input":{"A":{"id":44,"damage":6}},"output":[{"id":155,"damage":1}],"priority":50,"recipe_id":"chiseled_quartz_recipeId","shape":["A","A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":44,"damage":5}},"output":[{"id":98,"damage":3}],"priority":50,"recipe_id":"chiseled_stonebrick_recipeId","shape":["A","A"],"type":"shaped"},{"type":"special_hardcoded","uuid":"85939755-ba10-4d9d-a4cc-efb7a8e943c4"},{"block":"crafting_table","input":{"A":{"id":499,"damage":23},"B":{"id":50}},"output":[{"id":204}],"priority":0,"recipe_id":"ct_cerium_recipeId","shape":["A","B"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":22},"B":{"id":50}},"output":[{"id":202}],"priority":0,"recipe_id":"ct_mercuric_recipeId","shape":["A","B"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":21},"B":{"id":50}},"output":[{"id":204,"damage":8}],"priority":0,"recipe_id":"ct_potassium_recipeId","shape":["A","B"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":24},"B":{"id":50}},"output":[{"id":202,"damage":8}],"priority":0,"recipe_id":"ct_tungsten_recipeId","shape":["A","B"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5}},"output":[{"id":164,"count":4}],"priority":50,"recipe_id":"dark_oak_stairs_dark_oak_recipeId","shape":["A  ","AA ","AAA"],"type":"shaped"},{"type":"special_hardcoded","uuid":"d392b075-4ba1-40ae-8789-af868d56f6ce"},{"block":"crafting_table","input":{"A":{"id":253}},"output":[{"id":190,"count":16}],"priority":0,"recipe_id":"ggg_hard_glass_recipeId","shape":["AAA","AAA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":182}},"output":[{"id":179,"damage":1}],"priority":50,"recipe_id":"heiroglyphs_redsandstone_recipeId","shape":["A","A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":44,"damage":1}},"output":[{"id":24,"damage":1}],"priority":50,"recipe_id":"heiroglyphs_sandstone_recipeId","shape":["A","A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3}},"output":[{"id":136,"count":4}],"priority":50,"recipe_id":"jungle_stairs_jungle_recipeId","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":182,"damage":1}},"output":[{"id":201,"damage":2}],"priority":50,"recipe_id":"lines_purpur_recipeId","shape":["A","A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":287,"damage":-1},"B":{"id":5,"damage":-1}},"output":[{"id":-204}],"priority":50,"recipe_id":"loom_block_wood_planks_recipeId","shape":["AA","BB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4},"B":{"id":269}},"output":[{"id":333,"damage":4}],"priority":0,"recipe_id":"minecraft:acacia_boat","shape":["ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4}},"output":[{"id":430,"count":3}],"priority":0,"recipe_id":"minecraft:acacia_door","shape":["AA","AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4},"B":{"id":280,"damage":-1}},"output":[{"id":85,"damage":4,"count":3}],"priority":0,"recipe_id":"minecraft:acacia_fence","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":5,"damage":4}},"output":[{"id":187}],"priority":0,"recipe_id":"minecraft:acacia_fence_gate","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":162}},"output":[{"id":5,"damage":4,"count":4}],"priority":0,"recipe_id":"minecraft:acacia_planks","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-8,"damage":-1}},"output":[{"id":5,"damage":4,"count":4}],"priority":0,"recipe_id":"minecraft:acacia_planks_from_stripped","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":12}},"output":[{"id":5,"damage":4,"count":4}],"priority":0,"recipe_id":"minecraft:acacia_planks_from_stripped_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":4}},"output":[{"id":5,"damage":4,"count":4}],"priority":0,"recipe_id":"minecraft:acacia_planks_from_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4}},"output":[{"id":163,"count":4}],"priority":0,"recipe_id":"minecraft:acacia_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":162}},"output":[{"id":-212,"damage":4,"count":3}],"priority":0,"recipe_id":"minecraft:acacia_wood","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-8,"damage":-1}},"output":[{"id":-212,"damage":12,"count":3}],"priority":0,"recipe_id":"minecraft:acacia_wood_stripped","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4}},"output":[{"id":158,"damage":4,"count":6}],"priority":0,"recipe_id":"minecraft:acacia_wooden_slab","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":280,"damage":-1},"C":{"id":76,"damage":-1}},"output":[{"id":126,"count":6}],"priority":0,"recipe_id":"minecraft:activator_rail","shape":["ABA","ACA","ABA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":1,"damage":3},{"id":4,"damage":-1}],"output":[{"id":1,"damage":5,"count":2}],"priority":0,"recipe_id":"minecraft:andesite","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":1,"damage":5}},"output":[{"id":-171,"count":4}],"priority":0,"recipe_id":"minecraft:andesite_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":5}},"output":[{"id":139,"damage":4,"count":6}],"priority":0,"recipe_id":"minecraft:andesite_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":42,"damage":-1},"B":{"id":265,"damage":-1}},"output":[{"id":145}],"priority":0,"recipe_id":"minecraft:anvil","shape":["AAA"," B ","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":44}},"output":[{"id":425}],"priority":0,"recipe_id":"minecraft:armor_stand","shape":["AAA"," A ","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":318,"damage":-1},"B":{"id":280,"damage":-1},"C":{"id":288,"damage":-1}},"output":[{"id":262,"count":4}],"priority":0,"recipe_id":"minecraft:arrow","shape":["A","B","C"],"type":"shaped"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":45,"damage":-1}],"output":[{"id":434,"damage":4}],"priority":0,"recipe_id":"minecraft:banner_pattern_bricks","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":397,"damage":4}],"output":[{"id":434}],"priority":0,"recipe_id":"minecraft:banner_pattern_creeper","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":38,"damage":8}],"output":[{"id":434,"damage":2}],"priority":0,"recipe_id":"minecraft:banner_pattern_flower","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":397,"damage":1}],"output":[{"id":434,"damage":1}],"priority":0,"recipe_id":"minecraft:banner_pattern_skull","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":466,"damage":-1}],"output":[{"id":434,"damage":3}],"priority":0,"recipe_id":"minecraft:banner_pattern_thing","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":106,"damage":-1}],"output":[{"id":434,"damage":5}],"priority":0,"recipe_id":"minecraft:banner_pattern_vines","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":158,"damage":-1}},"output":[{"id":-203}],"priority":0,"recipe_id":"minecraft:barrel","shape":["ABA","A A","ABA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":395,"damage":1},{"id":345,"damage":-1}],"output":[{"id":395,"damage":2}],"priority":0,"recipe_id":"minecraft:basic_map_to_enhanced","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":399,"damage":-1},"C":{"id":49,"damage":-1}},"output":[{"id":138}],"priority":0,"recipe_id":"minecraft:beacon","shape":["AAA","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":736,"damage":-1}},"output":[{"id":-219}],"priority":0,"recipe_id":"minecraft:beehive","shape":["AAA","BBB","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":281,"damage":-1},{"id":457,"damage":-1},{"id":457,"damage":-1},{"id":457,"damage":-1},{"id":457,"damage":-1},{"id":457,"damage":-1},{"id":457,"damage":-1}],"output":[{"id":459}],"priority":0,"recipe_id":"minecraft:beetroot_soup","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2},"B":{"id":269}},"output":[{"id":333,"damage":2}],"priority":0,"recipe_id":"minecraft:birch_boat","shape":["ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2}},"output":[{"id":428,"count":3}],"priority":0,"recipe_id":"minecraft:birch_door","shape":["AA","AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2},"B":{"id":280,"damage":-1}},"output":[{"id":85,"damage":2,"count":3}],"priority":0,"recipe_id":"minecraft:birch_fence","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":5,"damage":2}},"output":[{"id":184}],"priority":0,"recipe_id":"minecraft:birch_fence_gate","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":17,"damage":2}},"output":[{"id":5,"damage":2,"count":4}],"priority":0,"recipe_id":"minecraft:birch_planks","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-6,"damage":-1}},"output":[{"id":5,"damage":2,"count":4}],"priority":0,"recipe_id":"minecraft:birch_planks_from_stripped","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":10}},"output":[{"id":5,"damage":2,"count":4}],"priority":0,"recipe_id":"minecraft:birch_planks_from_stripped_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":2}},"output":[{"id":5,"damage":2,"count":4}],"priority":0,"recipe_id":"minecraft:birch_planks_from_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2}},"output":[{"id":135,"count":4}],"priority":0,"recipe_id":"minecraft:birch_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":17,"damage":2}},"output":[{"id":-212,"damage":2,"count":3}],"priority":0,"recipe_id":"minecraft:birch_wood","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-6,"damage":-1}},"output":[{"id":-212,"damage":10,"count":3}],"priority":0,"recipe_id":"minecraft:birch_wood_stripped","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2}},"output":[{"id":158,"damage":2,"count":6}],"priority":0,"recipe_id":"minecraft:birch_wooden_slab","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":15},"B":{"id":280,"damage":-1}},"output":[{"id":446}],"priority":0,"recipe_id":"minecraft:black_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":15}},"output":[{"id":171,"damage":15,"count":3}],"priority":0,"recipe_id":"minecraft:black_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":16}},"output":[{"id":171,"damage":15,"count":8}],"priority":1,"recipe_id":"minecraft:black_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":15,"count":8}],"priority":0,"recipe_id":"minecraft:black_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":15,"count":8}],"priority":1,"recipe_id":"minecraft:black_concrete_powder_from_ink_sac","type":"shapeless"},{"block":"crafting_table","input":[{"id":351}],"output":[{"id":351,"damage":16}],"priority":0,"recipe_id":"minecraft:black_dye_from_ink_sac","type":"shapeless"},{"block":"crafting_table","input":[{"id":-216,"damage":-1}],"output":[{"id":351,"damage":16}],"priority":0,"recipe_id":"minecraft:black_dye_from_wither_rose","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":16}},"output":[{"id":241,"damage":15,"count":8}],"priority":0,"recipe_id":"minecraft:black_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351}},"output":[{"id":241,"damage":15,"count":8}],"priority":1,"recipe_id":"minecraft:black_stained_glass_from_ink_sac","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":15}},"output":[{"id":160,"damage":15,"count":16}],"priority":0,"recipe_id":"minecraft:black_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":16}},"output":[{"id":160,"damage":15,"count":8}],"priority":0,"recipe_id":"minecraft:black_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":16}},"output":[{"id":159,"damage":15,"count":8}],"priority":0,"recipe_id":"minecraft:black_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351}},"output":[{"id":159,"damage":15,"count":8}],"priority":1,"recipe_id":"minecraft:black_stained_hardened_clay_from_ink_sac","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":61,"damage":-1},"C":{"id":-183,"damage":-1}},"output":[{"id":-196}],"priority":0,"recipe_id":"minecraft:blast_furnace","shape":["AAA","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":[{"id":369,"damage":-1}],"output":[{"id":377,"count":2}],"priority":0,"recipe_id":"minecraft:blaze_powder","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":35,"damage":11},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":4}],"priority":0,"recipe_id":"minecraft:blue_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":11}},"output":[{"id":171,"damage":11,"count":3}],"priority":0,"recipe_id":"minecraft:blue_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":18}},"output":[{"id":171,"damage":11,"count":8}],"priority":0,"recipe_id":"minecraft:blue_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":11,"count":8}],"priority":0,"recipe_id":"minecraft:blue_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":11,"count":8}],"priority":1,"recipe_id":"minecraft:blue_concrete_powder_from_lapis_lazuli","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":9}],"output":[{"id":351,"damage":18}],"priority":0,"recipe_id":"minecraft:blue_dye_from_cornflower","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4}],"output":[{"id":351,"damage":18}],"priority":0,"recipe_id":"minecraft:blue_dye_from_lapis_lazuli","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":174,"damage":-1}},"output":[{"id":-11}],"priority":0,"recipe_id":"minecraft:blue_ice","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":18}},"output":[{"id":241,"damage":11,"count":8}],"priority":0,"recipe_id":"minecraft:blue_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":4}},"output":[{"id":241,"damage":11,"count":8}],"priority":1,"recipe_id":"minecraft:blue_stained_glass_from_lapis_lazuli","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":11}},"output":[{"id":160,"damage":11,"count":16}],"priority":0,"recipe_id":"minecraft:blue_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":18}},"output":[{"id":160,"damage":11,"count":8}],"priority":0,"recipe_id":"minecraft:blue_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":18}},"output":[{"id":159,"damage":11,"count":8}],"priority":0,"recipe_id":"minecraft:blue_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":4}},"output":[{"id":159,"damage":11,"count":8}],"priority":1,"recipe_id":"minecraft:blue_stained_hardened_clay_from_lapis_lazuli","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5},"B":{"id":269}},"output":[{"id":333}],"priority":0,"recipe_id":"minecraft:boat","shape":["ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":351,"damage":15}},"output":[{"id":216}],"priority":0,"recipe_id":"minecraft:bone_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":216,"damage":-1}],"output":[{"id":351,"damage":15,"count":9}],"priority":0,"recipe_id":"minecraft:bone_meal_from_block","type":"shapeless"},{"block":"crafting_table","input":[{"id":352,"damage":-1}],"output":[{"id":351,"damage":15,"count":3}],"priority":0,"recipe_id":"minecraft:bone_meal_from_bone","type":"shapeless"},{"block":"crafting_table","input":[{"id":339},{"id":339},{"id":339},{"id":334}],"output":[{"id":340}],"priority":0,"recipe_id":"minecraft:book","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":287,"damage":-1}},"output":[{"id":261}],"priority":0,"recipe_id":"minecraft:bow","shape":[" AB","A B"," AB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":296,"damage":-1}},"output":[{"id":297}],"priority":0,"recipe_id":"minecraft:bread","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":369,"damage":-1},"B":{"id":4,"damage":-1}},"output":[{"id":379}],"priority":0,"recipe_id":"minecraft:brewing_stand","shape":[" A ","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":336,"damage":-1}},"output":[{"id":45}],"priority":0,"recipe_id":"minecraft:brick_block","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":45,"damage":-1}},"output":[{"id":108,"count":4}],"priority":0,"recipe_id":"minecraft:brick_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":45,"damage":-1}},"output":[{"id":139,"damage":6,"count":6}],"priority":0,"recipe_id":"minecraft:brick_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":12},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":3}],"priority":0,"recipe_id":"minecraft:brown_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":12}},"output":[{"id":171,"damage":12,"count":3}],"priority":0,"recipe_id":"minecraft:brown_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":17}},"output":[{"id":171,"damage":12,"count":8}],"priority":0,"recipe_id":"minecraft:brown_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":12,"count":8}],"priority":0,"recipe_id":"minecraft:brown_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":12,"count":8}],"priority":1,"recipe_id":"minecraft:brown_concrete_powder_from_cocoa_beans","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3}],"output":[{"id":351,"damage":17}],"priority":0,"recipe_id":"minecraft:brown_dye_from_cocoa_beans","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":17}},"output":[{"id":241,"damage":12,"count":8}],"priority":0,"recipe_id":"minecraft:brown_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":3}},"output":[{"id":241,"damage":12,"count":8}],"priority":1,"recipe_id":"minecraft:brown_stained_glass_from_cocoa_beans","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":12}},"output":[{"id":160,"damage":12,"count":16}],"priority":0,"recipe_id":"minecraft:brown_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":17}},"output":[{"id":160,"damage":12,"count":8}],"priority":0,"recipe_id":"minecraft:brown_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":17}},"output":[{"id":159,"damage":12,"count":8}],"priority":0,"recipe_id":"minecraft:brown_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":3}},"output":[{"id":159,"damage":12,"count":8}],"priority":1,"recipe_id":"minecraft:brown_stained_hardened_clay_from_cocoa_beans","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":325}],"priority":0,"recipe_id":"minecraft:bucket","shape":["A A"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":325,"damage":1},"B":{"id":353,"damage":-1},"C":{"id":344,"damage":-1},"D":{"id":296,"damage":-1}},"output":[{"id":354},{"id":325,"count":3}],"priority":0,"recipe_id":"minecraft:cake","shape":["AAA","BCB","DDD"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":263,"damage":-1},"C":{"id":17,"damage":-1}},"output":[{"id":720}],"priority":0,"recipe_id":"minecraft:campfire","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":263,"damage":-1},"C":{"id":162,"damage":-1}},"output":[{"id":720}],"priority":0,"recipe_id":"minecraft:campfire_from_log2","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":263,"damage":-1},"C":{"id":-8,"damage":-1}},"output":[{"id":720}],"priority":0,"recipe_id":"minecraft:campfire_from_stripped_acacia_log","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":263,"damage":-1},"C":{"id":-6,"damage":-1}},"output":[{"id":720}],"priority":0,"recipe_id":"minecraft:campfire_from_stripped_birch_log","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":263,"damage":-1},"C":{"id":-9,"damage":-1}},"output":[{"id":720}],"priority":0,"recipe_id":"minecraft:campfire_from_stripped_dark_oak_log","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":263,"damage":-1},"C":{"id":-7,"damage":-1}},"output":[{"id":720}],"priority":0,"recipe_id":"minecraft:campfire_from_stripped_jungle_log","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":263,"damage":-1},"C":{"id":-10,"damage":-1}},"output":[{"id":720}],"priority":0,"recipe_id":"minecraft:campfire_from_stripped_oak_log","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":263,"damage":-1},"C":{"id":-5,"damage":-1}},"output":[{"id":720}],"priority":0,"recipe_id":"minecraft:campfire_from_stripped_spruce_log","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":263,"damage":-1},"C":{"id":-212,"damage":-1}},"output":[{"id":720}],"priority":0,"recipe_id":"minecraft:campfire_from_wood","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":346},"B":{"id":391,"damage":-1}},"output":[{"id":398}],"priority":0,"recipe_id":"minecraft:carrot_on_a_stick","shape":["A "," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":339,"damage":-1},"B":{"id":5,"damage":-1}},"output":[{"id":-200}],"priority":0,"recipe_id":"minecraft:cartography_table","shape":["AA","BB","BB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":380}],"priority":0,"recipe_id":"minecraft:cauldron","shape":["A A","A A","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":54,"damage":-1},"B":{"id":328,"damage":-1}},"output":[{"id":342}],"priority":0,"recipe_id":"minecraft:chest_minecart","shape":["A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":337,"damage":-1}},"output":[{"id":82}],"priority":0,"recipe_id":"minecraft:clay","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1},"B":{"id":331,"damage":-1}},"output":[{"id":347}],"priority":0,"recipe_id":"minecraft:clock","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":173,"damage":-1}},"output":[{"id":263,"count":9}],"priority":0,"recipe_id":"minecraft:coal","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":263}},"output":[{"id":173}],"priority":0,"recipe_id":"minecraft:coal_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":3},"B":{"id":13,"damage":-1}},"output":[{"id":3,"damage":1,"count":4}],"priority":0,"recipe_id":"minecraft:coarse_dirt","shape":["AB","BA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1}},"output":[{"id":67,"count":4}],"priority":0,"recipe_id":"minecraft:cobblestone_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1}},"output":[{"id":139,"count":6}],"priority":0,"recipe_id":"minecraft:cobblestone_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":30,"damage":-1}],"output":[{"id":287,"count":9}],"priority":0,"recipe_id":"minecraft:cobweb_to_string","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":76,"damage":-1},"B":{"id":406,"damage":-1},"C":{"id":1}},"output":[{"id":404}],"priority":0,"recipe_id":"minecraft:comparator","shape":[" A ","ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":331,"damage":-1}},"output":[{"id":345}],"priority":0,"recipe_id":"minecraft:compass","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":158,"damage":-1}},"output":[{"id":-213}],"priority":0,"recipe_id":"minecraft:composter","shape":["A A","A A","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":465,"damage":-1},"B":{"id":467,"damage":-1}},"output":[{"id":-157}],"priority":0,"recipe_id":"minecraft:conduit","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":296,"damage":-1},"B":{"id":351,"damage":3}},"output":[{"id":357,"count":8}],"priority":0,"recipe_id":"minecraft:cookie","shape":["ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":265,"damage":-1},"C":{"id":287,"damage":-1},"D":{"id":131,"damage":-1}},"output":[{"id":471}],"priority":0,"recipe_id":"minecraft:crossbow","shape":["ABA","CDC"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":9},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":6}],"priority":0,"recipe_id":"minecraft:cyan_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":9}},"output":[{"id":171,"damage":9,"count":3}],"priority":0,"recipe_id":"minecraft:cyan_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":6}},"output":[{"id":171,"damage":9,"count":8}],"priority":0,"recipe_id":"minecraft:cyan_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":9,"count":8}],"priority":0,"recipe_id":"minecraft:cyan_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":351,"damage":2}],"output":[{"id":351,"damage":6,"count":2}],"priority":0,"recipe_id":"minecraft:cyan_dye","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":351,"damage":2}],"output":[{"id":351,"damage":6,"count":2}],"priority":1,"recipe_id":"minecraft:cyan_dye_from_lapis_lazuli","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":6}},"output":[{"id":241,"damage":9,"count":8}],"priority":0,"recipe_id":"minecraft:cyan_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":9}},"output":[{"id":160,"damage":9,"count":16}],"priority":0,"recipe_id":"minecraft:cyan_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":6}},"output":[{"id":160,"damage":9,"count":8}],"priority":0,"recipe_id":"minecraft:cyan_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":6}},"output":[{"id":159,"damage":9,"count":8}],"priority":0,"recipe_id":"minecraft:cyan_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5},"B":{"id":269}},"output":[{"id":333,"damage":5}],"priority":0,"recipe_id":"minecraft:dark_oak_boat","shape":["ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5}},"output":[{"id":431,"count":3}],"priority":0,"recipe_id":"minecraft:dark_oak_door","shape":["AA","AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5},"B":{"id":280,"damage":-1}},"output":[{"id":85,"damage":5,"count":3}],"priority":0,"recipe_id":"minecraft:dark_oak_fence","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":5,"damage":5}},"output":[{"id":186}],"priority":0,"recipe_id":"minecraft:dark_oak_fence_gate","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":162,"damage":1}},"output":[{"id":5,"damage":5,"count":4}],"priority":0,"recipe_id":"minecraft:dark_oak_planks","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-9,"damage":-1}},"output":[{"id":5,"damage":5,"count":4}],"priority":0,"recipe_id":"minecraft:dark_oak_planks_from_stripped","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":13}},"output":[{"id":5,"damage":5,"count":4}],"priority":0,"recipe_id":"minecraft:dark_oak_planks_from_stripped_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":5}},"output":[{"id":5,"damage":5,"count":4}],"priority":0,"recipe_id":"minecraft:dark_oak_planks_from_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5}},"output":[{"id":164,"count":4}],"priority":0,"recipe_id":"minecraft:dark_oak_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":162,"damage":1}},"output":[{"id":-212,"damage":5,"count":3}],"priority":0,"recipe_id":"minecraft:dark_oak_wood","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-9,"damage":-1}},"output":[{"id":-212,"damage":13,"count":3}],"priority":0,"recipe_id":"minecraft:dark_oak_wood_stripped","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5}},"output":[{"id":158,"damage":5,"count":6}],"priority":0,"recipe_id":"minecraft:dark_oak_wooden_slab","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":409,"damage":-1},"B":{"id":351,"damage":16}},"output":[{"id":168,"damage":1}],"priority":0,"recipe_id":"minecraft:dark_prismarine","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":409,"damage":-1},"B":{"id":351}},"output":[{"id":168,"damage":1}],"priority":1,"recipe_id":"minecraft:dark_prismarine_from_ink_sac","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":70,"damage":-1},"C":{"id":331,"damage":-1}},"output":[{"id":28,"count":6}],"priority":0,"recipe_id":"minecraft:detector_rail","shape":["A A","ABA","ACA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":57,"damage":-1}},"output":[{"id":264,"count":9}],"priority":0,"recipe_id":"minecraft:diamond","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":279}],"priority":0,"recipe_id":"minecraft:diamond_axe","shape":["AA","AB"," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1}},"output":[{"id":57}],"priority":0,"recipe_id":"minecraft:diamond_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1}},"output":[{"id":313}],"priority":0,"recipe_id":"minecraft:diamond_boots","shape":["A A","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1}},"output":[{"id":311}],"priority":0,"recipe_id":"minecraft:diamond_chestplate","shape":["A A","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1}},"output":[{"id":310}],"priority":0,"recipe_id":"minecraft:diamond_helmet","shape":["AAA","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":293}],"priority":0,"recipe_id":"minecraft:diamond_hoe","shape":["AA"," B"," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1}},"output":[{"id":312}],"priority":0,"recipe_id":"minecraft:diamond_leggings","shape":["AAA","A A","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":278}],"priority":0,"recipe_id":"minecraft:diamond_pickaxe","shape":["AAA"," B "," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":277}],"priority":0,"recipe_id":"minecraft:diamond_shovel","shape":["A","B","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":264,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":276}],"priority":0,"recipe_id":"minecraft:diamond_sword","shape":["A","A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1},"B":{"id":406,"damage":-1}},"output":[{"id":1,"damage":3,"count":2}],"priority":0,"recipe_id":"minecraft:diorite","shape":["AB","BA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":3}},"output":[{"id":-170,"count":4}],"priority":0,"recipe_id":"minecraft:diorite_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":3}},"output":[{"id":139,"damage":3,"count":6}],"priority":0,"recipe_id":"minecraft:diorite_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1},"B":{"id":261},"C":{"id":331,"damage":-1}},"output":[{"id":23,"damage":3}],"priority":0,"recipe_id":"minecraft:dispenser","shape":["AAA","ABA","ACA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-139,"damage":-1}},"output":[{"id":464,"count":9}],"priority":0,"recipe_id":"minecraft:dried_kelp","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":464,"damage":-1}},"output":[{"id":-139}],"priority":0,"recipe_id":"minecraft:dried_kelp_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1},"B":{"id":331,"damage":-1}},"output":[{"id":125,"damage":3}],"priority":0,"recipe_id":"minecraft:dropper","shape":["AAA","A A","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":133,"damage":-1}},"output":[{"id":388,"count":9}],"priority":0,"recipe_id":"minecraft:emerald","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":388,"damage":-1}},"output":[{"id":133}],"priority":0,"recipe_id":"minecraft:emerald_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":395},{"id":345,"damage":-1}],"output":[{"id":395,"damage":2}],"priority":0,"recipe_id":"minecraft:empty_map_to_enhanced","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":340,"damage":-1},"B":{"id":264,"damage":-1},"C":{"id":49,"damage":-1}},"output":[{"id":116}],"priority":0,"recipe_id":"minecraft:enchanting_table","shape":[" A ","BCB","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":206,"damage":-1}},"output":[{"id":-178,"count":4}],"priority":0,"recipe_id":"minecraft:end_brick_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":206,"damage":-1}},"output":[{"id":139,"damage":10,"count":6}],"priority":0,"recipe_id":"minecraft:end_brick_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":121,"damage":-1}},"output":[{"id":206,"count":4}],"priority":0,"recipe_id":"minecraft:end_bricks","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":381,"damage":-1},"C":{"id":370,"damage":-1}},"output":[{"id":426}],"priority":0,"recipe_id":"minecraft:end_crystal","shape":["AAA","ABA","ACA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":369,"damage":-1},"B":{"id":433,"damage":-1}},"output":[{"id":208,"count":4}],"priority":0,"recipe_id":"minecraft:end_rod","shape":["A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":49,"damage":-1},"B":{"id":381,"damage":-1}},"output":[{"id":130}],"priority":0,"recipe_id":"minecraft:ender_chest","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":368,"damage":-1},{"id":377,"damage":-1}],"output":[{"id":381}],"priority":0,"recipe_id":"minecraft:ender_eye","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":5},"B":{"id":280,"damage":-1}},"output":[{"id":85,"count":3}],"priority":0,"recipe_id":"minecraft:fence","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":5}},"output":[{"id":107}],"priority":0,"recipe_id":"minecraft:fence_gate","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":375,"damage":-1},{"id":39,"damage":-1},{"id":353,"damage":-1}],"output":[{"id":376}],"priority":0,"recipe_id":"minecraft:fermented_spider_eye","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":287,"damage":-1}},"output":[{"id":346}],"priority":0,"recipe_id":"minecraft:fishing_rod","shape":["  A"," AB","A B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":318,"damage":-1},"B":{"id":5,"damage":-1}},"output":[{"id":-201}],"priority":0,"recipe_id":"minecraft:fletching_table","shape":["AA","BB","BB"],"type":"shaped"},{"block":"crafting_table","input":[{"id":265,"damage":-1},{"id":318,"damage":-1}],"output":[{"id":259}],"priority":0,"recipe_id":"minecraft:flint_and_steel","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":336,"damage":-1}},"output":[{"id":390}],"priority":0,"recipe_id":"minecraft:flower_pot","shape":["A A"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1}},"output":[{"id":61}],"priority":0,"recipe_id":"minecraft:furnace","shape":["AAA","A A","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1}},"output":[{"id":374,"count":3}],"priority":0,"recipe_id":"minecraft:glass_bottle","shape":["A A"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1}},"output":[{"id":102,"count":16}],"priority":0,"recipe_id":"minecraft:glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":348,"damage":-1}},"output":[{"id":89}],"priority":0,"recipe_id":"minecraft:glowstone","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1}},"output":[{"id":41}],"priority":0,"recipe_id":"minecraft:gold_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":41,"damage":-1}},"output":[{"id":266,"count":9}],"priority":0,"recipe_id":"minecraft:gold_ingot_from_block","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":371,"damage":-1}},"output":[{"id":266}],"priority":0,"recipe_id":"minecraft:gold_ingot_from_nuggets","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1}},"output":[{"id":371,"count":9}],"priority":0,"recipe_id":"minecraft:gold_nugget","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1},"B":{"id":260,"damage":-1}},"output":[{"id":322}],"priority":0,"recipe_id":"minecraft:golden_apple","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":286}],"priority":0,"recipe_id":"minecraft:golden_axe","shape":["AA","AB"," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1}},"output":[{"id":317}],"priority":0,"recipe_id":"minecraft:golden_boots","shape":["A A","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":371,"damage":-1},"B":{"id":391,"damage":-1}},"output":[{"id":396}],"priority":0,"recipe_id":"minecraft:golden_carrot","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1}},"output":[{"id":315}],"priority":0,"recipe_id":"minecraft:golden_chestplate","shape":["A A","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1}},"output":[{"id":314}],"priority":0,"recipe_id":"minecraft:golden_helmet","shape":["AAA","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":294}],"priority":0,"recipe_id":"minecraft:golden_hoe","shape":["AA"," B"," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1}},"output":[{"id":316}],"priority":0,"recipe_id":"minecraft:golden_leggings","shape":["AAA","A A","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":285}],"priority":0,"recipe_id":"minecraft:golden_pickaxe","shape":["AAA"," B "," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1},"B":{"id":280,"damage":-1},"C":{"id":331,"damage":-1}},"output":[{"id":27,"count":6}],"priority":0,"recipe_id":"minecraft:golden_rail","shape":["A A","ABA","ACA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":284}],"priority":0,"recipe_id":"minecraft:golden_shovel","shape":["A","B","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":283}],"priority":0,"recipe_id":"minecraft:golden_sword","shape":["A","A","B"],"type":"shaped"},{"block":"crafting_table","input":[{"id":1,"damage":3},{"id":406,"damage":-1}],"output":[{"id":1,"damage":1}],"priority":0,"recipe_id":"minecraft:granite","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":1,"damage":1}},"output":[{"id":-169,"count":4}],"priority":0,"recipe_id":"minecraft:granite_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":1}},"output":[{"id":139,"damage":2,"count":6}],"priority":0,"recipe_id":"minecraft:granite_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":7},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":8}],"priority":0,"recipe_id":"minecraft:gray_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":7}},"output":[{"id":171,"damage":7,"count":3}],"priority":0,"recipe_id":"minecraft:gray_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":8}},"output":[{"id":171,"damage":7,"count":8}],"priority":0,"recipe_id":"minecraft:gray_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":7,"count":8}],"priority":0,"recipe_id":"minecraft:gray_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":351,"damage":19}],"output":[{"id":351,"damage":8,"count":2}],"priority":0,"recipe_id":"minecraft:gray_dye","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":351,"damage":15}],"output":[{"id":351,"damage":8,"count":2}],"priority":1,"recipe_id":"minecraft:gray_dye_from_black_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":351,"damage":15}],"output":[{"id":351,"damage":8,"count":2}],"priority":3,"recipe_id":"minecraft:gray_dye_from_ink_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":351,"damage":19}],"output":[{"id":351,"damage":8,"count":2}],"priority":2,"recipe_id":"minecraft:gray_dye_from_ink_white","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":8}},"output":[{"id":241,"damage":7,"count":8}],"priority":0,"recipe_id":"minecraft:gray_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":7}},"output":[{"id":160,"damage":7,"count":16}],"priority":0,"recipe_id":"minecraft:gray_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":8}},"output":[{"id":160,"damage":7,"count":8}],"priority":0,"recipe_id":"minecraft:gray_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":8}},"output":[{"id":159,"damage":7,"count":8}],"priority":0,"recipe_id":"minecraft:gray_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":13},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":2}],"priority":0,"recipe_id":"minecraft:green_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":13}},"output":[{"id":171,"damage":13,"count":3}],"priority":0,"recipe_id":"minecraft:green_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":2}},"output":[{"id":171,"damage":13,"count":8}],"priority":0,"recipe_id":"minecraft:green_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":13,"count":8}],"priority":0,"recipe_id":"minecraft:green_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":2}},"output":[{"id":241,"damage":13,"count":8}],"priority":0,"recipe_id":"minecraft:green_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":13}},"output":[{"id":160,"damage":13,"count":16}],"priority":0,"recipe_id":"minecraft:green_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":2}},"output":[{"id":160,"damage":13,"count":8}],"priority":0,"recipe_id":"minecraft:green_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":2}},"output":[{"id":159,"damage":13,"count":8}],"priority":0,"recipe_id":"minecraft:green_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":-166,"damage":2},"C":{"id":5,"damage":-1}},"output":[{"id":-195}],"priority":0,"recipe_id":"minecraft:grindstone","shape":["ABA","C C"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":296,"damage":-1}},"output":[{"id":170}],"priority":0,"recipe_id":"minecraft:hay_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":148}],"priority":0,"recipe_id":"minecraft:heavy_weighted_pressure_plate","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":737,"damage":-1}},"output":[{"id":-220},{"id":374,"count":4}],"priority":0,"recipe_id":"minecraft:honey_block","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":-220,"damage":-1},{"id":374,"damage":-1},{"id":374,"damage":-1},{"id":374,"damage":-1},{"id":374,"damage":-1}],"output":[{"id":737,"count":4}],"priority":0,"recipe_id":"minecraft:honey_bottle","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":737,"damage":-1}},"output":[{"id":353,"count":3},{"id":374}],"priority":0,"recipe_id":"minecraft:honey_bottle_to_sugar","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":736,"damage":-1}},"output":[{"id":-221}],"priority":0,"recipe_id":"minecraft:honeycomb_block","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":54,"damage":-1}},"output":[{"id":410}],"priority":0,"recipe_id":"minecraft:hopper","shape":["A A","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":410,"damage":-1},"B":{"id":328,"damage":-1}},"output":[{"id":408}],"priority":0,"recipe_id":"minecraft:hopper_minecart","shape":["A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":258}],"priority":0,"recipe_id":"minecraft:iron_axe","shape":["AA","AB"," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":101,"count":16}],"priority":0,"recipe_id":"minecraft:iron_bars","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":42}],"priority":0,"recipe_id":"minecraft:iron_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":309}],"priority":0,"recipe_id":"minecraft:iron_boots","shape":["A A","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":307}],"priority":0,"recipe_id":"minecraft:iron_chestplate","shape":["A A","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":330,"count":3}],"priority":0,"recipe_id":"minecraft:iron_door","shape":["AA","AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":306}],"priority":0,"recipe_id":"minecraft:iron_helmet","shape":["AAA","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":292}],"priority":0,"recipe_id":"minecraft:iron_hoe","shape":["AA"," B"," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":42,"damage":-1}},"output":[{"id":265,"count":9}],"priority":0,"recipe_id":"minecraft:iron_ingot_from_block","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":452,"damage":-1}},"output":[{"id":265}],"priority":0,"recipe_id":"minecraft:iron_ingot_from_nuggets","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":308}],"priority":0,"recipe_id":"minecraft:iron_leggings","shape":["AAA","A A","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":452,"count":9}],"priority":0,"recipe_id":"minecraft:iron_nugget","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":257}],"priority":0,"recipe_id":"minecraft:iron_pickaxe","shape":["AAA"," B "," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":256}],"priority":0,"recipe_id":"minecraft:iron_shovel","shape":["A","B","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":267}],"priority":0,"recipe_id":"minecraft:iron_sword","shape":["A","A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":167}],"priority":0,"recipe_id":"minecraft:iron_trapdoor","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":334,"damage":-1}},"output":[{"id":389}],"priority":0,"recipe_id":"minecraft:item_frame","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3},"B":{"id":269}},"output":[{"id":333,"damage":3}],"priority":0,"recipe_id":"minecraft:jungle_boat","shape":["ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3}},"output":[{"id":429,"count":3}],"priority":0,"recipe_id":"minecraft:jungle_door","shape":["AA","AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3},"B":{"id":280,"damage":-1}},"output":[{"id":85,"damage":3,"count":3}],"priority":0,"recipe_id":"minecraft:jungle_fence","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":5,"damage":3}},"output":[{"id":185}],"priority":0,"recipe_id":"minecraft:jungle_fence_gate","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":17,"damage":3}},"output":[{"id":5,"damage":3,"count":4}],"priority":0,"recipe_id":"minecraft:jungle_planks","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-7,"damage":-1}},"output":[{"id":5,"damage":3,"count":4}],"priority":0,"recipe_id":"minecraft:jungle_planks_from_stripped","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":11}},"output":[{"id":5,"damage":3,"count":4}],"priority":0,"recipe_id":"minecraft:jungle_planks_from_stripped_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":3}},"output":[{"id":5,"damage":3,"count":4}],"priority":0,"recipe_id":"minecraft:jungle_planks_from_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3}},"output":[{"id":136,"count":4}],"priority":0,"recipe_id":"minecraft:jungle_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":17,"damage":3}},"output":[{"id":-212,"damage":3,"count":3}],"priority":0,"recipe_id":"minecraft:jungle_wood","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-7,"damage":-1}},"output":[{"id":-212,"damage":11,"count":3}],"priority":0,"recipe_id":"minecraft:jungle_wood_stripped","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3}},"output":[{"id":158,"damage":3,"count":6}],"priority":0,"recipe_id":"minecraft:jungle_wooden_slab","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1}},"output":[{"id":65,"count":3}],"priority":0,"recipe_id":"minecraft:ladder","shape":["A A","AAA","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":452,"damage":-1},"B":{"id":50,"damage":-1}},"output":[{"id":-208}],"priority":0,"recipe_id":"minecraft:lantern","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":351,"damage":4}},"output":[{"id":22}],"priority":0,"recipe_id":"minecraft:lapis_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":22,"damage":-1}},"output":[{"id":351,"damage":4,"count":9}],"priority":0,"recipe_id":"minecraft:lapis_lazuli","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":287,"damage":-1},"B":{"id":341,"damage":-1}},"output":[{"id":420,"count":2}],"priority":0,"recipe_id":"minecraft:lead","shape":["AA ","AB ","  A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":415,"damage":-1}},"output":[{"id":334}],"priority":0,"recipe_id":"minecraft:leather","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":334,"damage":-1}},"output":[{"id":301}],"priority":0,"recipe_id":"minecraft:leather_boots","shape":["A A","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":334,"damage":-1}},"output":[{"id":299}],"priority":0,"recipe_id":"minecraft:leather_chestplate","shape":["A A","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":334,"damage":-1}},"output":[{"id":298}],"priority":0,"recipe_id":"minecraft:leather_helmet","shape":["AAA","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":334,"damage":-1}},"output":[{"id":416}],"priority":0,"recipe_id":"minecraft:leather_horse_armor","shape":["A A","AAA","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":334,"damage":-1}},"output":[{"id":300}],"priority":0,"recipe_id":"minecraft:leather_leggings","shape":["AAA","A A","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":158,"damage":-1},"B":{"id":47,"damage":-1}},"output":[{"id":-194}],"priority":0,"recipe_id":"minecraft:lectern","shape":["AAA"," B "," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":4,"damage":-1}},"output":[{"id":69}],"priority":0,"recipe_id":"minecraft:lever","shape":["A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":3},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":12}],"priority":0,"recipe_id":"minecraft:light_blue_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":3}},"output":[{"id":171,"damage":3,"count":3}],"priority":0,"recipe_id":"minecraft:light_blue_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":12}},"output":[{"id":171,"damage":3,"count":8}],"priority":0,"recipe_id":"minecraft:light_blue_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":3,"count":8}],"priority":0,"recipe_id":"minecraft:light_blue_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":351,"damage":19}],"output":[{"id":351,"damage":12,"count":2}],"priority":1,"recipe_id":"minecraft:light_blue_dye","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":351,"damage":15}],"output":[{"id":351,"damage":12,"count":2}],"priority":2,"recipe_id":"minecraft:light_blue_dye_from_blue_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":1}],"output":[{"id":351,"damage":12}],"priority":0,"recipe_id":"minecraft:light_blue_dye_from_blue_orchid","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":351,"damage":15}],"output":[{"id":351,"damage":12,"count":2}],"priority":4,"recipe_id":"minecraft:light_blue_dye_from_lapis_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":351,"damage":19}],"output":[{"id":351,"damage":12,"count":2}],"priority":3,"recipe_id":"minecraft:light_blue_dye_from_lapis_white","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":12}},"output":[{"id":241,"damage":3,"count":8}],"priority":0,"recipe_id":"minecraft:light_blue_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":3}},"output":[{"id":160,"damage":3,"count":16}],"priority":0,"recipe_id":"minecraft:light_blue_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":12}},"output":[{"id":160,"damage":3,"count":8}],"priority":0,"recipe_id":"minecraft:light_blue_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":12}},"output":[{"id":159,"damage":3,"count":8}],"priority":0,"recipe_id":"minecraft:light_blue_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":7}},"output":[{"id":171,"damage":8,"count":8}],"priority":0,"recipe_id":"minecraft:light_gray__carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":8},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":7}],"priority":0,"recipe_id":"minecraft:light_gray_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":8}},"output":[{"id":171,"damage":8,"count":3}],"priority":0,"recipe_id":"minecraft:light_gray_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":8,"count":8}],"priority":0,"recipe_id":"minecraft:light_gray_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":351,"damage":19},{"id":351,"damage":19}],"output":[{"id":351,"damage":7,"count":3}],"priority":3,"recipe_id":"minecraft:light_gray_dye","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":3}],"output":[{"id":351,"damage":7}],"priority":2,"recipe_id":"minecraft:light_gray_dye_from_azure_bluet","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":351,"damage":15},{"id":351,"damage":15}],"output":[{"id":351,"damage":7,"count":3}],"priority":7,"recipe_id":"minecraft:light_gray_dye_from_black_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":351,"damage":15}],"output":[{"id":351,"damage":7,"count":2}],"priority":6,"recipe_id":"minecraft:light_gray_dye_from_gray_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":351,"damage":19}],"output":[{"id":351,"damage":7,"count":2}],"priority":4,"recipe_id":"minecraft:light_gray_dye_from_gray_white","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":351,"damage":15},{"id":351,"damage":15}],"output":[{"id":351,"damage":7,"count":3}],"priority":8,"recipe_id":"minecraft:light_gray_dye_from_ink_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":351,"damage":19},{"id":351,"damage":19}],"output":[{"id":351,"damage":7,"count":3}],"priority":5,"recipe_id":"minecraft:light_gray_dye_from_ink_white","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":8}],"output":[{"id":351,"damage":7}],"priority":1,"recipe_id":"minecraft:light_gray_dye_from_oxeye_daisy","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":6}],"output":[{"id":351,"damage":7}],"priority":0,"recipe_id":"minecraft:light_gray_dye_from_white_tulip","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":7}},"output":[{"id":241,"damage":8,"count":8}],"priority":0,"recipe_id":"minecraft:light_gray_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":8}},"output":[{"id":160,"damage":8,"count":16}],"priority":0,"recipe_id":"minecraft:light_gray_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":7}},"output":[{"id":160,"damage":8,"count":8}],"priority":0,"recipe_id":"minecraft:light_gray_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":7}},"output":[{"id":159,"damage":8,"count":8}],"priority":0,"recipe_id":"minecraft:light_gray_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":266,"damage":-1}},"output":[{"id":147}],"priority":0,"recipe_id":"minecraft:light_weighted_pressure_plate","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":10}},"output":[{"id":171,"damage":5,"count":8}],"priority":0,"recipe_id":"minecraft:lime__carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":5},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":10}],"priority":0,"recipe_id":"minecraft:lime_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":5}},"output":[{"id":171,"damage":5,"count":3}],"priority":0,"recipe_id":"minecraft:lime_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":5,"count":8}],"priority":0,"recipe_id":"minecraft:lime_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":351,"damage":19}],"output":[{"id":351,"damage":10,"count":2}],"priority":0,"recipe_id":"minecraft:lime_dye","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":351,"damage":15}],"output":[{"id":351,"damage":10,"count":2}],"priority":1,"recipe_id":"minecraft:lime_dye_from_bonemeal","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":10}},"output":[{"id":241,"damage":5,"count":8}],"priority":0,"recipe_id":"minecraft:lime_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":5}},"output":[{"id":160,"damage":5,"count":16}],"priority":0,"recipe_id":"minecraft:lime_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":10}},"output":[{"id":160,"damage":5,"count":8}],"priority":0,"recipe_id":"minecraft:lime_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":10}},"output":[{"id":159,"damage":5,"count":8}],"priority":0,"recipe_id":"minecraft:lime_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-155,"damage":-1},"B":{"id":50,"damage":-1}},"output":[{"id":91}],"priority":0,"recipe_id":"minecraft:lit_pumpkin","shape":["A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":339,"damage":-1},"B":{"id":345,"damage":-1}},"output":[{"id":395,"damage":2}],"priority":0,"recipe_id":"minecraft:locator_map","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":2},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":13}],"priority":0,"recipe_id":"minecraft:magenta_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":2}},"output":[{"id":171,"damage":2,"count":3}],"priority":0,"recipe_id":"minecraft:magenta_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":13}},"output":[{"id":171,"damage":2,"count":8}],"priority":0,"recipe_id":"minecraft:magenta_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":2,"count":8}],"priority":0,"recipe_id":"minecraft:magenta_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":351,"damage":1},{"id":351,"damage":9}],"output":[{"id":351,"damage":13,"count":3}],"priority":2,"recipe_id":"minecraft:magenta_dye","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":2}],"output":[{"id":351,"damage":13}],"priority":1,"recipe_id":"minecraft:magenta_dye_from_allium","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":351,"damage":1},{"id":351,"damage":1},{"id":351,"damage":15}],"output":[{"id":351,"damage":13,"count":4}],"priority":6,"recipe_id":"minecraft:magenta_dye_from_blue_ink_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":351,"damage":1},{"id":351,"damage":1},{"id":351,"damage":19}],"output":[{"id":351,"damage":13,"count":4}],"priority":4,"recipe_id":"minecraft:magenta_dye_from_blue_ink_white","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":351,"damage":1},{"id":351,"damage":1},{"id":351,"damage":15}],"output":[{"id":351,"damage":13,"count":4}],"priority":8,"recipe_id":"minecraft:magenta_dye_from_lapis_ink_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":351,"damage":1},{"id":351,"damage":1},{"id":351,"damage":19}],"output":[{"id":351,"damage":13,"count":4}],"priority":7,"recipe_id":"minecraft:magenta_dye_from_lapis_ink_white","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":351,"damage":1},{"id":351,"damage":9}],"output":[{"id":351,"damage":13,"count":3}],"priority":5,"recipe_id":"minecraft:magenta_dye_from_lapis_red_pink","type":"shapeless"},{"block":"crafting_table","input":[{"id":175,"damage":1}],"output":[{"id":351,"damage":13,"count":2}],"priority":0,"recipe_id":"minecraft:magenta_dye_from_lilac","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":351,"damage":9}],"output":[{"id":351,"damage":13,"count":2}],"priority":3,"recipe_id":"minecraft:magenta_dye_from_purple_and_pink","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":13}},"output":[{"id":241,"damage":2,"count":8}],"priority":0,"recipe_id":"minecraft:magenta_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":2}},"output":[{"id":160,"damage":2,"count":16}],"priority":0,"recipe_id":"minecraft:magenta_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":13}},"output":[{"id":160,"damage":2,"count":8}],"priority":0,"recipe_id":"minecraft:magenta_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":13}},"output":[{"id":159,"damage":2,"count":8}],"priority":0,"recipe_id":"minecraft:magenta_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":378,"damage":-1}},"output":[{"id":213}],"priority":0,"recipe_id":"minecraft:magma","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":377,"damage":-1},{"id":341,"damage":-1}],"output":[{"id":378}],"priority":0,"recipe_id":"minecraft:magma_cream","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":339,"damage":-1}},"output":[{"id":395}],"priority":0,"recipe_id":"minecraft:map","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":360,"damage":-1}},"output":[{"id":103}],"priority":0,"recipe_id":"minecraft:melon_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":360,"damage":-1}},"output":[{"id":362}],"priority":0,"recipe_id":"minecraft:melon_seeds","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":328}],"priority":0,"recipe_id":"minecraft:minecart","shape":["A A","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":4,"damage":-1},{"id":106,"damage":-1}],"output":[{"id":48}],"priority":0,"recipe_id":"minecraft:mossy_cobblestone","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":48,"damage":-1}},"output":[{"id":-179,"count":4}],"priority":0,"recipe_id":"minecraft:mossy_cobblestone_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":48,"damage":-1}},"output":[{"id":139,"damage":1,"count":6}],"priority":0,"recipe_id":"minecraft:mossy_cobblestone_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":98,"damage":1}},"output":[{"id":-175,"count":4}],"priority":0,"recipe_id":"minecraft:mossy_stone_brick_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":98,"damage":1}},"output":[{"id":139,"damage":8,"count":6}],"priority":0,"recipe_id":"minecraft:mossy_stone_brick_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":98},{"id":106,"damage":-1}],"output":[{"id":98,"damage":1}],"priority":0,"recipe_id":"minecraft:mossy_stonebrick","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1}],"output":[{"id":282}],"priority":0,"recipe_id":"minecraft:mushroom_stew","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":405,"damage":-1}},"output":[{"id":112}],"priority":0,"recipe_id":"minecraft:nether_brick","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":112,"damage":-1},"B":{"id":405,"damage":-1}},"output":[{"id":113,"count":6}],"priority":0,"recipe_id":"minecraft:nether_brick_fence","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":112,"damage":-1}},"output":[{"id":114,"count":4}],"priority":0,"recipe_id":"minecraft:nether_brick_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":112,"damage":-1}},"output":[{"id":139,"damage":9,"count":6}],"priority":0,"recipe_id":"minecraft:nether_brick_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":372,"damage":-1}},"output":[{"id":214}],"priority":0,"recipe_id":"minecraft:nether_wart_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":17}},"output":[{"id":5,"count":4}],"priority":0,"recipe_id":"minecraft:oak_planks","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-10,"damage":-1}},"output":[{"id":5,"count":4}],"priority":0,"recipe_id":"minecraft:oak_planks_from_stripped","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":8}},"output":[{"id":5,"count":4}],"priority":0,"recipe_id":"minecraft:oak_planks_from_stripped_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212}},"output":[{"id":5,"count":4}],"priority":0,"recipe_id":"minecraft:oak_planks_from_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5}},"output":[{"id":53,"count":4}],"priority":0,"recipe_id":"minecraft:oak_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":17}},"output":[{"id":-212,"count":3}],"priority":0,"recipe_id":"minecraft:oak_wood","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-10,"damage":-1}},"output":[{"id":-212,"damage":8,"count":3}],"priority":0,"recipe_id":"minecraft:oak_wood_stripped","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5}},"output":[{"id":158,"count":6}],"priority":0,"recipe_id":"minecraft:oak_wooden_slab","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1},"B":{"id":331,"damage":-1},"C":{"id":406,"damage":-1}},"output":[{"id":251}],"priority":0,"recipe_id":"minecraft:observer","shape":["AAA","BBC","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":1},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":14}],"priority":0,"recipe_id":"minecraft:orange_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":1}},"output":[{"id":171,"damage":1,"count":3}],"priority":0,"recipe_id":"minecraft:orange_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":14}},"output":[{"id":171,"damage":1,"count":8}],"priority":0,"recipe_id":"minecraft:orange_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":1,"count":8}],"priority":0,"recipe_id":"minecraft:orange_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":5}],"output":[{"id":351,"damage":14}],"priority":0,"recipe_id":"minecraft:orange_dye_from_orange_tulip","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":351,"damage":11}],"output":[{"id":351,"damage":14,"count":2}],"priority":0,"recipe_id":"minecraft:orange_dye_from_red_yellow","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":14}},"output":[{"id":241,"damage":1,"count":8}],"priority":0,"recipe_id":"minecraft:orange_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":1}},"output":[{"id":160,"damage":1,"count":16}],"priority":0,"recipe_id":"minecraft:orange_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":14}},"output":[{"id":160,"damage":1,"count":8}],"priority":0,"recipe_id":"minecraft:orange_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":14}},"output":[{"id":159,"damage":1,"count":8}],"priority":0,"recipe_id":"minecraft:orange_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":79,"damage":-1}},"output":[{"id":174}],"priority":0,"recipe_id":"minecraft:packed_ice","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":338,"damage":-1}},"output":[{"id":339,"count":3}],"priority":0,"recipe_id":"minecraft:paper","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":155}},"output":[{"id":155,"damage":2,"count":2}],"priority":0,"recipe_id":"minecraft:pillar_quartz_block","shape":["A","A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":6},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":9}],"priority":0,"recipe_id":"minecraft:pink_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":6}},"output":[{"id":171,"damage":6,"count":3}],"priority":0,"recipe_id":"minecraft:pink_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":9}},"output":[{"id":171,"damage":6,"count":8}],"priority":0,"recipe_id":"minecraft:pink_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":6,"count":8}],"priority":0,"recipe_id":"minecraft:pink_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":351,"damage":19}],"output":[{"id":351,"damage":9,"count":2}],"priority":0,"recipe_id":"minecraft:pink_dye","type":"shapeless"},{"block":"crafting_table","input":[{"id":175,"damage":5}],"output":[{"id":351,"damage":9,"count":2}],"priority":0,"recipe_id":"minecraft:pink_dye_from_peony","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":7}],"output":[{"id":351,"damage":9}],"priority":0,"recipe_id":"minecraft:pink_dye_from_pink_tulip","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":351,"damage":15}],"output":[{"id":351,"damage":9,"count":2}],"priority":0,"recipe_id":"minecraft:pink_dye_from_red_bonemeal","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":9}},"output":[{"id":241,"damage":6,"count":8}],"priority":0,"recipe_id":"minecraft:pink_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":6}},"output":[{"id":160,"damage":6,"count":16}],"priority":0,"recipe_id":"minecraft:pink_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":9}},"output":[{"id":160,"damage":6,"count":8}],"priority":0,"recipe_id":"minecraft:pink_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":9}},"output":[{"id":159,"damage":6,"count":8}],"priority":0,"recipe_id":"minecraft:pink_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":5}},"output":[{"id":1,"damage":6,"count":4}],"priority":0,"recipe_id":"minecraft:polished_andesite","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":6}},"output":[{"id":-174,"count":4}],"priority":0,"recipe_id":"minecraft:polished_andesite_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":3}},"output":[{"id":1,"damage":4,"count":4}],"priority":0,"recipe_id":"minecraft:polished_diorite","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":4}},"output":[{"id":-173,"count":4}],"priority":0,"recipe_id":"minecraft:polished_diorite_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":1}},"output":[{"id":1,"damage":2,"count":4}],"priority":0,"recipe_id":"minecraft:polished_granite","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":2}},"output":[{"id":-172,"count":4}],"priority":0,"recipe_id":"minecraft:polished_granite_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":409,"damage":-1}},"output":[{"id":168}],"priority":0,"recipe_id":"minecraft:prismarine","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":409,"damage":-1}},"output":[{"id":168,"damage":2}],"priority":0,"recipe_id":"minecraft:prismarine_bricks","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":168}},"output":[{"id":-2,"count":4}],"priority":0,"recipe_id":"minecraft:prismarine_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":168,"damage":2}},"output":[{"id":-4,"count":4}],"priority":0,"recipe_id":"minecraft:prismarine_stairs_bricks","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":168,"damage":1}},"output":[{"id":-3,"count":4}],"priority":0,"recipe_id":"minecraft:prismarine_stairs_dark","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":168}},"output":[{"id":139,"damage":11,"count":6}],"priority":0,"recipe_id":"minecraft:prismarine_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":86,"damage":-1},{"id":353,"damage":-1},{"id":344,"damage":-1}],"output":[{"id":400}],"priority":0,"recipe_id":"minecraft:pumpkin_pie","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":86,"damage":-1}},"output":[{"id":361,"count":4}],"priority":0,"recipe_id":"minecraft:pumpkin_seeds","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":10},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":5}],"priority":0,"recipe_id":"minecraft:purple_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":10}},"output":[{"id":171,"damage":10,"count":3}],"priority":0,"recipe_id":"minecraft:purple_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":5}},"output":[{"id":171,"damage":10,"count":8}],"priority":0,"recipe_id":"minecraft:purple_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":10,"count":8}],"priority":0,"recipe_id":"minecraft:purple_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":351,"damage":1}],"output":[{"id":351,"damage":5,"count":2}],"priority":0,"recipe_id":"minecraft:purple_dye","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":351,"damage":1}],"output":[{"id":351,"damage":5,"count":2}],"priority":1,"recipe_id":"minecraft:purple_dye_from_lapis_lazuli","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":5}},"output":[{"id":241,"damage":10,"count":8}],"priority":0,"recipe_id":"minecraft:purple_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":10}},"output":[{"id":160,"damage":10,"count":16}],"priority":0,"recipe_id":"minecraft:purple_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":5}},"output":[{"id":160,"damage":10,"count":8}],"priority":0,"recipe_id":"minecraft:purple_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":5}},"output":[{"id":159,"damage":10,"count":8}],"priority":0,"recipe_id":"minecraft:purple_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":433,"damage":-1}},"output":[{"id":201,"count":4}],"priority":0,"recipe_id":"minecraft:purpur_block","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":201,"damage":-1}},"output":[{"id":203,"count":4}],"priority":0,"recipe_id":"minecraft:purpur_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":406,"damage":-1}},"output":[{"id":155}],"priority":0,"recipe_id":"minecraft:quartz_block","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":155}},"output":[{"id":156,"count":4}],"priority":0,"recipe_id":"minecraft:quartz_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":281,"damage":-1},{"id":393,"damage":-1},{"id":391,"damage":-1},{"id":39,"damage":-1},{"id":412,"damage":-1}],"output":[{"id":413}],"priority":0,"recipe_id":"minecraft:rabbit_stew_from_brown_mushroom","type":"shapeless"},{"block":"crafting_table","input":[{"id":281,"damage":-1},{"id":393,"damage":-1},{"id":391,"damage":-1},{"id":40,"damage":-1},{"id":412,"damage":-1}],"output":[{"id":413}],"priority":0,"recipe_id":"minecraft:rabbit_stew_from_red_mushroom","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":66,"count":16}],"priority":0,"recipe_id":"minecraft:rail","shape":["A A","ABA","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":14},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":1}],"priority":0,"recipe_id":"minecraft:red_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":14}},"output":[{"id":171,"damage":14,"count":3}],"priority":0,"recipe_id":"minecraft:red_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":1}},"output":[{"id":171,"damage":14,"count":8}],"priority":0,"recipe_id":"minecraft:red_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":14,"count":8}],"priority":0,"recipe_id":"minecraft:red_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":457,"damage":-1}],"output":[{"id":351,"damage":1}],"priority":0,"recipe_id":"minecraft:red_dye_from_beetroot","type":"shapeless"},{"block":"crafting_table","input":[{"id":38}],"output":[{"id":351,"damage":1}],"priority":0,"recipe_id":"minecraft:red_dye_from_poppy","type":"shapeless"},{"block":"crafting_table","input":[{"id":175,"damage":4}],"output":[{"id":351,"damage":1,"count":2}],"priority":0,"recipe_id":"minecraft:red_dye_from_rose_bush","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":4}],"output":[{"id":351,"damage":1}],"priority":0,"recipe_id":"minecraft:red_dye_from_tulip","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":405,"damage":-1},"B":{"id":372,"damage":-1}},"output":[{"id":215}],"priority":0,"recipe_id":"minecraft:red_nether_brick","shape":["AB","BA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":215,"damage":-1}},"output":[{"id":-184,"count":4}],"priority":0,"recipe_id":"minecraft:red_nether_brick_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":215,"damage":-1}},"output":[{"id":139,"damage":13,"count":6}],"priority":0,"recipe_id":"minecraft:red_nether_brick_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":12,"damage":1}},"output":[{"id":179}],"priority":0,"recipe_id":"minecraft:red_sandstone","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":179}},"output":[{"id":180,"count":4}],"priority":0,"recipe_id":"minecraft:red_sandstone_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":179}},"output":[{"id":139,"damage":12,"count":6}],"priority":0,"recipe_id":"minecraft:red_sandstone_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":1}},"output":[{"id":241,"damage":14,"count":8}],"priority":0,"recipe_id":"minecraft:red_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":14}},"output":[{"id":160,"damage":14,"count":16}],"priority":0,"recipe_id":"minecraft:red_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":1}},"output":[{"id":160,"damage":14,"count":8}],"priority":0,"recipe_id":"minecraft:red_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":1}},"output":[{"id":159,"damage":14,"count":8}],"priority":0,"recipe_id":"minecraft:red_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":152,"damage":-1}},"output":[{"id":331,"count":9}],"priority":0,"recipe_id":"minecraft:redstone","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":331,"damage":-1}},"output":[{"id":152}],"priority":0,"recipe_id":"minecraft:redstone_block","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":331,"damage":-1},"B":{"id":89,"damage":-1}},"output":[{"id":123}],"priority":0,"recipe_id":"minecraft:redstone_lamp","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":331,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":76}],"priority":0,"recipe_id":"minecraft:redstone_torch","shape":["A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":76,"damage":-1},"B":{"id":331,"damage":-1},"C":{"id":1}},"output":[{"id":356}],"priority":0,"recipe_id":"minecraft:repeater","shape":["ABA","CCC"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":12}},"output":[{"id":24}],"priority":0,"recipe_id":"minecraft:sandstone","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":24}},"output":[{"id":128,"count":4}],"priority":0,"recipe_id":"minecraft:sandstone_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":24}},"output":[{"id":139,"damage":5,"count":6}],"priority":0,"recipe_id":"minecraft:sandstone_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-163,"damage":-1},"B":{"id":287,"damage":-1}},"output":[{"id":-165,"count":6}],"priority":0,"recipe_id":"minecraft:scaffolding","shape":["ABA","A A","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":409,"damage":-1},"B":{"id":422,"damage":-1}},"output":[{"id":169}],"priority":0,"recipe_id":"minecraft:sealantern","shape":["ABA","BBB","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1}},"output":[{"id":359}],"priority":0,"recipe_id":"minecraft:shears","shape":[" A","A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":265,"damage":-1}},"output":[{"id":513}],"priority":0,"recipe_id":"minecraft:shield","shape":["ABA","AAA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":445,"damage":-1},"B":{"id":54,"damage":-1}},"output":[{"id":205}],"priority":0,"recipe_id":"minecraft:shulker_box","shape":["A","B","A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":4},"B":{"id":280,"damage":-1}},"output":[{"id":475,"count":3}],"priority":0,"recipe_id":"minecraft:sign_acacia","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":2},"B":{"id":280,"damage":-1}},"output":[{"id":473,"count":3}],"priority":0,"recipe_id":"minecraft:sign_birch","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":5},"B":{"id":280,"damage":-1}},"output":[{"id":476,"count":3}],"priority":0,"recipe_id":"minecraft:sign_darkoak","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":3},"B":{"id":280,"damage":-1}},"output":[{"id":474,"count":3}],"priority":0,"recipe_id":"minecraft:sign_jungle","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5},"B":{"id":280,"damage":-1}},"output":[{"id":323,"count":3}],"priority":0,"recipe_id":"minecraft:sign_oak","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1},"B":{"id":280,"damage":-1}},"output":[{"id":472,"count":3}],"priority":0,"recipe_id":"minecraft:sign_spruce","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":341,"damage":-1}},"output":[{"id":165}],"priority":0,"recipe_id":"minecraft:slime","shape":["AAA","AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":165,"damage":-1}},"output":[{"id":341,"count":9}],"priority":0,"recipe_id":"minecraft:slime_ball","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":5,"damage":-1}},"output":[{"id":-202}],"priority":0,"recipe_id":"minecraft:smithing_table","shape":["AA","BB","BB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":17,"damage":-1},"B":{"id":61,"damage":-1}},"output":[{"id":-198}],"priority":0,"recipe_id":"minecraft:smoker","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":162,"damage":-1},"B":{"id":61,"damage":-1}},"output":[{"id":-198}],"priority":0,"recipe_id":"minecraft:smoker_from_log2","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-8,"damage":-1},"B":{"id":61,"damage":-1}},"output":[{"id":-198}],"priority":0,"recipe_id":"minecraft:smoker_from_stripped_acacia","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-6,"damage":-1},"B":{"id":61,"damage":-1}},"output":[{"id":-198}],"priority":0,"recipe_id":"minecraft:smoker_from_stripped_birch","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-9,"damage":-1},"B":{"id":61,"damage":-1}},"output":[{"id":-198}],"priority":0,"recipe_id":"minecraft:smoker_from_stripped_dark_oak","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-7,"damage":-1},"B":{"id":61,"damage":-1}},"output":[{"id":-198}],"priority":0,"recipe_id":"minecraft:smoker_from_stripped_jungle","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-10,"damage":-1},"B":{"id":61,"damage":-1}},"output":[{"id":-198}],"priority":0,"recipe_id":"minecraft:smoker_from_stripped_oak","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-5,"damage":-1},"B":{"id":61,"damage":-1}},"output":[{"id":-198}],"priority":0,"recipe_id":"minecraft:smoker_from_stripped_spruce","shape":[" A ","ABA"," A "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":155,"damage":3}},"output":[{"id":-185,"count":4}],"priority":0,"recipe_id":"minecraft:smooth_quartz_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":179}},"output":[{"id":179,"damage":2,"count":4}],"priority":0,"recipe_id":"minecraft:smooth_red_sandstone","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":179,"damage":3}},"output":[{"id":-176,"count":4}],"priority":0,"recipe_id":"minecraft:smooth_red_sandstone_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":24}},"output":[{"id":24,"damage":2,"count":4}],"priority":0,"recipe_id":"minecraft:smooth_sandstone","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":24,"damage":3}},"output":[{"id":-177,"count":4}],"priority":0,"recipe_id":"minecraft:smooth_sandstone_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":332,"damage":-1}},"output":[{"id":80}],"priority":0,"recipe_id":"minecraft:snow","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":80,"damage":-1}},"output":[{"id":78,"count":6}],"priority":0,"recipe_id":"minecraft:snow_layer","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":371,"damage":-1},"B":{"id":360,"damage":-1}},"output":[{"id":382}],"priority":0,"recipe_id":"minecraft:speckled_melon","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1},"B":{"id":269}},"output":[{"id":333,"damage":1}],"priority":0,"recipe_id":"minecraft:spruce_boat","shape":["ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1}},"output":[{"id":427,"count":3}],"priority":0,"recipe_id":"minecraft:spruce_door","shape":["AA","AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1},"B":{"id":280,"damage":-1}},"output":[{"id":85,"damage":1,"count":3}],"priority":0,"recipe_id":"minecraft:spruce_fence","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":280,"damage":-1},"B":{"id":5,"damage":1}},"output":[{"id":183}],"priority":0,"recipe_id":"minecraft:spruce_fence_gate","shape":["ABA","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":17,"damage":1}},"output":[{"id":5,"damage":1,"count":4}],"priority":0,"recipe_id":"minecraft:spruce_planks","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-5,"damage":-1}},"output":[{"id":5,"damage":1,"count":4}],"priority":0,"recipe_id":"minecraft:spruce_planks_from_stripped","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":9}},"output":[{"id":5,"damage":1,"count":4}],"priority":0,"recipe_id":"minecraft:spruce_planks_from_stripped_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-212,"damage":1}},"output":[{"id":5,"damage":1,"count":4}],"priority":0,"recipe_id":"minecraft:spruce_planks_from_wood","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1}},"output":[{"id":134,"count":4}],"priority":0,"recipe_id":"minecraft:spruce_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":17,"damage":1}},"output":[{"id":-212,"damage":1,"count":3}],"priority":0,"recipe_id":"minecraft:spruce_wood","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-5,"damage":-1}},"output":[{"id":-212,"damage":9,"count":3}],"priority":0,"recipe_id":"minecraft:spruce_wood_stripped","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1}},"output":[{"id":158,"damage":1,"count":6}],"priority":0,"recipe_id":"minecraft:spruce_wooden_slab","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":341,"damage":-1},"B":{"id":33,"damage":-1}},"output":[{"id":29,"damage":1}],"priority":0,"recipe_id":"minecraft:sticky_piston","shape":["A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":275}],"priority":0,"recipe_id":"minecraft:stone_axe","shape":["AA","AB"," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":98}},"output":[{"id":109,"count":4}],"priority":0,"recipe_id":"minecraft:stone_brick_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":98}},"output":[{"id":139,"damage":7,"count":6}],"priority":0,"recipe_id":"minecraft:stone_brick_wall","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1}},"output":[{"id":77}],"priority":0,"recipe_id":"minecraft:stone_button","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":291}],"priority":0,"recipe_id":"minecraft:stone_hoe","shape":["AA"," B"," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":274}],"priority":0,"recipe_id":"minecraft:stone_pickaxe","shape":["AAA"," B "," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1}},"output":[{"id":70}],"priority":0,"recipe_id":"minecraft:stone_pressure_plate","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":273}],"priority":0,"recipe_id":"minecraft:stone_shovel","shape":["A","B","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1}},"output":[{"id":-180,"count":4}],"priority":0,"recipe_id":"minecraft:stone_stairs","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":4,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":272}],"priority":0,"recipe_id":"minecraft:stone_sword","shape":["A","A","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1}},"output":[{"id":98,"count":4}],"priority":0,"recipe_id":"minecraft:stonebrick","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":265,"damage":-1},"B":{"id":1,"damage":-1}},"output":[{"id":-197}],"priority":0,"recipe_id":"minecraft:stonecutter","shape":[" A ","BBB"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":287,"damage":-1}},"output":[{"id":35}],"priority":0,"recipe_id":"minecraft:string_to_wool","shape":["AA","AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":338,"damage":-1}},"output":[{"id":353}],"priority":0,"recipe_id":"minecraft:sugar","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":2}],"output":[{"id":734,"damage":7}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_allium","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":3}],"output":[{"id":734,"damage":3}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_azure_bluet","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":1}],"output":[{"id":734,"damage":6}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_blue_orchid","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":9}],"output":[{"id":734,"damage":1}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_cornflower","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":37,"damage":-1}],"output":[{"id":734,"damage":5}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_dandelion","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":10}],"output":[{"id":734,"damage":4}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_lily_of_the_valley","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":8}],"output":[{"id":734,"damage":8}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_oxeye_daisy","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38}],"output":[{"id":734}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_poppy","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":5}],"output":[{"id":734,"damage":2}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_tulip_orange","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":7}],"output":[{"id":734,"damage":2}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_tulip_pink","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":4}],"output":[{"id":734,"damage":2}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_tulip_red","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":38,"damage":6}],"output":[{"id":734,"damage":2}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_tulip_white","type":"shapeless"},{"block":"crafting_table","input":[{"id":39,"damage":-1},{"id":40,"damage":-1},{"id":281,"damage":-1},{"id":-216,"damage":-1}],"output":[{"id":734,"damage":9}],"priority":0,"recipe_id":"minecraft:suspicious_stew_from_wither_rose","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":289,"damage":-1},"B":{"id":12,"damage":-1}},"output":[{"id":46}],"priority":0,"recipe_id":"minecraft:tnt","shape":["ABA","BAB","ABA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":46},"B":{"id":328,"damage":-1}},"output":[{"id":407}],"priority":0,"recipe_id":"minecraft:tnt_minecart","shape":["A","B"],"type":"shaped"},{"block":"crafting_table","input":[{"id":54,"damage":-1},{"id":131,"damage":-1}],"output":[{"id":146}],"priority":0,"recipe_id":"minecraft:trapped_chest","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":468,"damage":-1}},"output":[{"id":469}],"priority":0,"recipe_id":"minecraft:turtle_helmet","shape":["AAA","A A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":170,"damage":-1}},"output":[{"id":296,"count":9}],"priority":0,"recipe_id":"minecraft:wheat","shape":["A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":15}],"priority":0,"recipe_id":"minecraft:white_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35}},"output":[{"id":171,"count":3}],"priority":0,"recipe_id":"minecraft:white_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"count":8}],"priority":0,"recipe_id":"minecraft:white_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"count":8}],"priority":1,"recipe_id":"minecraft:white_concrete_powder_from_bonemeal","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15}],"output":[{"id":351,"damage":19}],"priority":0,"recipe_id":"minecraft:white_dye_from_bone_meal","type":"shapeless"},{"block":"crafting_table","input":[{"id":38,"damage":10}],"output":[{"id":351,"damage":19}],"priority":0,"recipe_id":"minecraft:white_dye_from_lily_of_the_valley","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":19}},"output":[{"id":241,"count":8}],"priority":0,"recipe_id":"minecraft:white_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":15}},"output":[{"id":241,"count":8}],"priority":1,"recipe_id":"minecraft:white_stained_glass_from_bonemeal","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241}},"output":[{"id":160,"count":16}],"priority":0,"recipe_id":"minecraft:white_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":19}},"output":[{"id":160,"count":8}],"priority":0,"recipe_id":"minecraft:white_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":19}},"output":[{"id":159,"count":8}],"priority":0,"recipe_id":"minecraft:white_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":15}},"output":[{"id":159,"count":8}],"priority":1,"recipe_id":"minecraft:white_stained_hardened_clay_from_bonemeal","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5}},"output":[{"id":324,"count":3}],"priority":0,"recipe_id":"minecraft:wooden_door","shape":["AA","AA","AA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":340,"damage":-1},{"id":351},{"id":288,"damage":-1}],"output":[{"id":386}],"priority":0,"recipe_id":"minecraft:writable_book","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":35,"damage":4},"B":{"id":280,"damage":-1}},"output":[{"id":446,"damage":11}],"priority":0,"recipe_id":"minecraft:yellow_banner","shape":["AAA","AAA"," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":35,"damage":4}},"output":[{"id":171,"damage":4,"count":3}],"priority":0,"recipe_id":"minecraft:yellow_carpet","shape":["AA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":171},"B":{"id":351,"damage":11}},"output":[{"id":171,"damage":4,"count":8}],"priority":0,"recipe_id":"minecraft:yellow_carpet_from_white","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":12},{"id":12},{"id":12},{"id":12},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1},{"id":13,"damage":-1}],"output":[{"id":237,"damage":4,"count":8}],"priority":0,"recipe_id":"minecraft:yellow_concrete_powder","type":"shapeless"},{"block":"crafting_table","input":[{"id":37}],"output":[{"id":351,"damage":11}],"priority":0,"recipe_id":"minecraft:yellow_dye_from_dandelion","type":"shapeless"},{"block":"crafting_table","input":[{"id":175}],"output":[{"id":351,"damage":11,"count":2}],"priority":0,"recipe_id":"minecraft:yellow_dye_from_sunflower","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":20,"damage":-1},"B":{"id":351,"damage":11}},"output":[{"id":241,"damage":4,"count":8}],"priority":0,"recipe_id":"minecraft:yellow_stained_glass","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":241,"damage":4}},"output":[{"id":160,"damage":4,"count":16}],"priority":0,"recipe_id":"minecraft:yellow_stained_glass_pane","shape":["AAA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":102,"damage":-1},"B":{"id":351,"damage":11}},"output":[{"id":160,"damage":4,"count":8}],"priority":0,"recipe_id":"minecraft:yellow_stained_glass_pane_from_pane","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":172,"damage":-1},"B":{"id":351,"damage":11}},"output":[{"id":159,"damage":4,"count":8}],"priority":0,"recipe_id":"minecraft:yellow_stained_hardened_clay","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-23},"B":{"id":50}},"output":[{"id":239}],"priority":0,"recipe_id":"mt_recipeId","shape":["A","B"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":5}},"output":[{"id":53,"count":4}],"priority":50,"recipe_id":"oak_stairs_oak_recipeId","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":-22},"B":{"id":46}},"output":[{"id":46,"damage":2}],"priority":0,"recipe_id":"ot_recipeId","shape":["A","B"],"type":"shaped_chemistry"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_0_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_10_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_11_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_12_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_13_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_14_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_15_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_16_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_17_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_18_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_19_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_1_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_2_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_3_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_4_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_5_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_6_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_7_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_8_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1},{"id":402,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_charge_9_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351}],"output":[{"id":402,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_0_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":10}],"output":[{"id":402,"damage":10,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_10_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":11}],"output":[{"id":402,"damage":11,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_11_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":12}],"output":[{"id":402,"damage":12,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_12_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":13}],"output":[{"id":402,"damage":13,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_13_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":14}],"output":[{"id":402,"damage":14,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_14_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":15}],"output":[{"id":402,"damage":15,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_15_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":16}],"output":[{"id":402,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_16_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":17}],"output":[{"id":402,"damage":3,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_17_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":18}],"output":[{"id":402,"damage":4,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_18_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":19}],"output":[{"id":402,"damage":15,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_19_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":1}],"output":[{"id":402,"damage":1,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_1_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":2}],"output":[{"id":402,"damage":2,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_2_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":3}],"output":[{"id":402,"damage":3,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_3_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":4}],"output":[{"id":402,"damage":4,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_4_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":5}],"output":[{"id":402,"damage":5,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_5_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":6}],"output":[{"id":402,"damage":6,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_6_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":7}],"output":[{"id":402,"damage":7,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_7_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":8}],"output":[{"id":402,"damage":8,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_8_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":289,"damage":-1},{"id":351,"damage":9}],"output":[{"id":402,"damage":9,"nbt_b64":"CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz\/wA="}],"priority":50,"recipe_id":"paper_sulphur_dye_9_recipeId","type":"shapeless"},{"block":"crafting_table","input":[{"id":339,"damage":-1},{"id":289,"damage":-1}],"output":[{"id":401,"count":3,"nbt_b64":"CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA"}],"priority":50,"recipe_id":"paper_sulphur_recipeId","type":"shapeless"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":1},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":1}],"priority":0,"recipe_id":"phld_glowstick_1","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":10},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":10}],"priority":0,"recipe_id":"phld_glowstick_10","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":11},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":11}],"priority":0,"recipe_id":"phld_glowstick_11","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":12},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":12}],"priority":0,"recipe_id":"phld_glowstick_12","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":13},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":13}],"priority":0,"recipe_id":"phld_glowstick_13","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":14},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":14}],"priority":0,"recipe_id":"phld_glowstick_14","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":15},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":15}],"priority":0,"recipe_id":"phld_glowstick_15","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":17},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":3}],"priority":0,"recipe_id":"phld_glowstick_17","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":18},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":4}],"priority":0,"recipe_id":"phld_glowstick_18","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":19},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":15}],"priority":0,"recipe_id":"phld_glowstick_19","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":2},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":2}],"priority":0,"recipe_id":"phld_glowstick_2","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":3},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":3}],"priority":0,"recipe_id":"phld_glowstick_3","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":4},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":4}],"priority":0,"recipe_id":"phld_glowstick_4","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":5},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":5}],"priority":0,"recipe_id":"phld_glowstick_5","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":6},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":6}],"priority":0,"recipe_id":"phld_glowstick_6","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":7},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":7}],"priority":0,"recipe_id":"phld_glowstick_7","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":8},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":8}],"priority":0,"recipe_id":"phld_glowstick_8","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":16},"B":{"id":499,"damage":35},"C":{"id":351,"damage":9},"D":{"id":499,"damage":10}},"output":[{"id":166,"damage":9}],"priority":0,"recipe_id":"phld_glowstick_9","shape":["ABA","ACA","ADA"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":23},"B":{"id":-23},"C":{"id":280,"damage":-1}},"output":[{"id":442,"damage":4}],"priority":0,"recipe_id":"phld_sparkler_0","shape":["A","B","C"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":24},"B":{"id":-23},"C":{"id":280,"damage":-1}},"output":[{"id":442,"damage":2}],"priority":0,"recipe_id":"phld_sparkler_1","shape":["A","B","C"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":25},"B":{"id":-23},"C":{"id":280,"damage":-1}},"output":[{"id":442,"damage":14}],"priority":0,"recipe_id":"phld_sparkler_2","shape":["A","B","C"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":21},"B":{"id":-23},"C":{"id":280,"damage":-1}},"output":[{"id":442,"damage":5}],"priority":0,"recipe_id":"phld_sparkler_3","shape":["A","B","C"],"type":"shaped_chemistry"},{"block":"crafting_table","input":{"A":{"id":499,"damage":22},"B":{"id":-23},"C":{"id":280,"damage":-1}},"output":[{"id":442,"damage":1}],"priority":0,"recipe_id":"phld_sparkler_4","shape":["A","B","C"],"type":"shaped_chemistry"},{"type":"special_hardcoded","uuid":"00000000-0000-0000-0000-000000000001"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_0_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_10_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_11_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_12_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_13_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_14_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_15_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_16_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_17_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_18_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_19_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_1_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_2_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_3_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_4_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_5_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_6_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_7_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":6},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_8_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":15},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":5},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":4},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":3},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":2},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":1},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":14},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":13},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":12},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":11},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":10},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":9},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":8},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":218,"damage":7},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_block_9_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_0_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":10}],"output":[{"id":218,"damage":5}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_10_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":11}],"output":[{"id":218,"damage":4}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_11_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":12}],"output":[{"id":218,"damage":3}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_12_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":13}],"output":[{"id":218,"damage":2}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_13_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":14}],"output":[{"id":218,"damage":1}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_14_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":15}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_15_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":16}],"output":[{"id":218,"damage":15}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_16_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":17}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_17_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":18}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_18_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":19}],"output":[{"id":218}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_19_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":1}],"output":[{"id":218,"damage":14}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_1_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":2}],"output":[{"id":218,"damage":13}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_2_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":3}],"output":[{"id":218,"damage":12}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_3_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":4}],"output":[{"id":218,"damage":11}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_4_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":5}],"output":[{"id":218,"damage":10}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_5_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":6}],"output":[{"id":218,"damage":9}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_6_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":7}],"output":[{"id":218,"damage":8}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_7_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":8}],"output":[{"id":218,"damage":7}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_8_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":[{"id":205},{"id":351,"damage":9}],"output":[{"id":218,"damage":6}],"priority":0,"recipe_id":"shulkerBox_shulker_box_color_dye_9_0","type":"shapeless_shulker_box"},{"block":"crafting_table","input":{"A":{"id":206}},"output":[{"id":-162,"count":6}],"priority":50,"recipe_id":"slab3_endstonebrick_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":1}},"output":[{"id":134,"count":4}],"priority":50,"recipe_id":"spruce_stairs_spruce_recipeId","shape":["A  ","AA ","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1}},"output":[{"id":280,"count":4}],"priority":1,"recipe_id":"stick_wood_recipeId","shape":["A","A"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":179}},"output":[{"id":182,"count":6}],"priority":50,"recipe_id":"stoneslab2_RedSandstone_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":168,"damage":2}},"output":[{"id":182,"damage":4,"count":6}],"priority":50,"recipe_id":"stoneslab2_prismarine_bricks_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":168,"damage":1}},"output":[{"id":182,"damage":3,"count":6}],"priority":50,"recipe_id":"stoneslab2_prismarine_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":201}},"output":[{"id":182,"damage":1,"count":6}],"priority":50,"recipe_id":"stoneslab2_purpur_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":48}},"output":[{"id":182,"damage":5,"count":6}],"priority":50,"recipe_id":"stoneslab2_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":215}},"output":[{"id":182,"damage":7,"count":6}],"priority":50,"recipe_id":"stoneslab2_rednetherbrick_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":179,"damage":1}},"output":[{"id":182,"count":6}],"priority":50,"recipe_id":"stoneslab2_redsandstone_heiroglyphs_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":24,"damage":3}},"output":[{"id":182,"damage":6,"count":6}],"priority":50,"recipe_id":"stoneslab2_smoothsandstone_smooth_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":5}},"output":[{"id":-162,"damage":3,"count":6}],"priority":50,"recipe_id":"stoneslab3_andesite_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":3}},"output":[{"id":-162,"damage":4,"count":6}],"priority":50,"recipe_id":"stoneslab3_diorite_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":1}},"output":[{"id":-162,"damage":6,"count":6}],"priority":50,"recipe_id":"stoneslab3_granite","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":2}},"output":[{"id":-162,"damage":7,"count":6}],"priority":50,"recipe_id":"stoneslab3_polishedGranite_GraniteSmooth_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":6}},"output":[{"id":-162,"damage":2,"count":6}],"priority":50,"recipe_id":"stoneslab3_polished_andesite_andesitesmooth_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":1,"damage":4}},"output":[{"id":-162,"damage":5,"count":6}],"priority":50,"recipe_id":"stoneslab3_polished_diorite_dioritesmooth_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":179,"damage":3}},"output":[{"id":-162,"damage":1,"count":6}],"priority":50,"recipe_id":"stoneslab3_smooth_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":179,"damage":2}},"output":[{"id":-166,"damage":4,"count":6}],"priority":50,"recipe_id":"stoneslab4_cut_redsandstone_cut_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":24,"damage":2}},"output":[{"id":-166,"damage":3,"count":6}],"priority":50,"recipe_id":"stoneslab4_cut_sandstone_cut_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":155,"damage":3}},"output":[{"id":-166,"damage":1,"count":6}],"priority":50,"recipe_id":"stoneslab4_smoothquartz_smooth_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":155}},"output":[{"id":44,"damage":6,"count":6}],"priority":50,"recipe_id":"stoneslab_quartz_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":168}},"output":[{"id":182,"damage":2,"count":6}],"priority":50,"recipe_id":"stoneslab_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":24,"damage":1}},"output":[{"id":44,"damage":1,"count":6}],"priority":50,"recipe_id":"stoneslab_sandstone_heiroglyphs_recipeId","shape":["AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":270}],"priority":50,"recipe_id":"tool_material_recipe_0_0","shape":["AAA"," B "," B "],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":269}],"priority":50,"recipe_id":"tool_material_recipe_0_1","shape":["A","B","B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":271}],"priority":50,"recipe_id":"tool_material_recipe_0_2","shape":["AA","AB"," B"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":290}],"priority":50,"recipe_id":"tool_material_recipe_0_3","shape":["AA"," B"," B"],"type":"shaped"},{"type":"special_hardcoded","uuid":"aecd2294-4b94-434b-8667-4499bb2c9327"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":10}},"output":[{"id":262,"damage":11,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_10","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":11}},"output":[{"id":262,"damage":12,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_11","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":12}},"output":[{"id":262,"damage":13,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_12","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":13}},"output":[{"id":262,"damage":14,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_13","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":14}},"output":[{"id":262,"damage":15,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_14","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":15}},"output":[{"id":262,"damage":16,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_15","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":16}},"output":[{"id":262,"damage":17,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_16","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":17}},"output":[{"id":262,"damage":18,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_17","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":18}},"output":[{"id":262,"damage":19,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_18","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":19}},"output":[{"id":262,"damage":20,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_19","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":20}},"output":[{"id":262,"damage":21,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_20","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":21}},"output":[{"id":262,"damage":22,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_21","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":22}},"output":[{"id":262,"damage":23,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_22","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":23}},"output":[{"id":262,"damage":24,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_23","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":24}},"output":[{"id":262,"damage":25,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_24","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":25}},"output":[{"id":262,"damage":26,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_25","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":26}},"output":[{"id":262,"damage":27,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_26","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":27}},"output":[{"id":262,"damage":28,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_27","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":28}},"output":[{"id":262,"damage":29,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_28","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":29}},"output":[{"id":262,"damage":30,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_29","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":30}},"output":[{"id":262,"damage":31,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_30","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":31}},"output":[{"id":262,"damage":32,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_31","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":32}},"output":[{"id":262,"damage":33,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_32","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":33}},"output":[{"id":262,"damage":34,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_33","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":34}},"output":[{"id":262,"damage":35,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_34","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":35}},"output":[{"id":262,"damage":36,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_35","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":36}},"output":[{"id":262,"damage":37,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_36","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":37}},"output":[{"id":262,"damage":38,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_37","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":38}},"output":[{"id":262,"damage":39,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_38","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":39}},"output":[{"id":262,"damage":40,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_39","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":40}},"output":[{"id":262,"damage":41,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_40","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":41}},"output":[{"id":262,"damage":42,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_41","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":5}},"output":[{"id":262,"damage":6,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_5","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":6}},"output":[{"id":262,"damage":7,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_6","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":7}},"output":[{"id":262,"damage":8,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_7","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":8}},"output":[{"id":262,"damage":9,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_8","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":262},"B":{"id":441,"damage":9}},"output":[{"id":262,"damage":10,"count":8}],"priority":50,"recipe_id":"weapon_arrow_recipe_9","shape":["AAA","ABA","AAA"],"type":"shaped"},{"block":"crafting_table","input":{"A":{"id":5,"damage":-1},"B":{"id":280,"damage":-1}},"output":[{"id":268}],"priority":50,"recipe_id":"weapon_stick_recipe_0_0","shape":["A","A","B"],"type":"shaped"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":14}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":5}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":4}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":3}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":2}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":1}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":13}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":12}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":11}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":10}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":9}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":8}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":7}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351},{"id":35,"damage":6}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_0_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":15}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":14}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":4}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":3}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":2}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":1}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":13}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":12}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":11}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":10}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":9}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":8}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":7}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":10},{"id":35,"damage":6}],"output":[{"id":35,"damage":5}],"priority":50,"recipe_id":"wool_dye_wool_10_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":15}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":14}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":5}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":3}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":2}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":1}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":13}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":12}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":11}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":10}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":9}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":8}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":7}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":11},{"id":35,"damage":6}],"output":[{"id":35,"damage":4}],"priority":50,"recipe_id":"wool_dye_wool_11_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":15}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":14}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":5}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":4}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":2}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":1}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":13}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":12}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":11}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":10}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":9}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":8}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":7}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":12},{"id":35,"damage":6}],"output":[{"id":35,"damage":3}],"priority":50,"recipe_id":"wool_dye_wool_12_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":15}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":14}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":5}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":4}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":3}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":1}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":13}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":12}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":11}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":10}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":9}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":8}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":7}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":13},{"id":35,"damage":6}],"output":[{"id":35,"damage":2}],"priority":50,"recipe_id":"wool_dye_wool_13_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":15}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":14}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":5}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":4}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":3}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":2}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":13}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":12}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":11}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":10}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":9}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":8}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":7}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":14},{"id":35,"damage":6}],"output":[{"id":35,"damage":1}],"priority":50,"recipe_id":"wool_dye_wool_14_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":15}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":14}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":5}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":4}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":3}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":2}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":1}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":13}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":12}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":11}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":10}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":9}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":8}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":7}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":15},{"id":35,"damage":6}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_15_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":14}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":5}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":4}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":3}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":2}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":1}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":13}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":12}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":11}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":10}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":9}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":8}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":7}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":16},{"id":35,"damage":6}],"output":[{"id":35,"damage":15}],"priority":50,"recipe_id":"wool_dye_wool_16_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":15}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":14}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":5}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":4}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":3}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":2}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":1}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":13}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":11}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":10}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":9}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":8}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":7}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":17},{"id":35,"damage":6}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_17_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":15}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":14}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":5}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":4}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":3}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":2}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":1}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":13}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":12}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":10}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":9}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":8}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":7}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":18},{"id":35,"damage":6}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_18_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":15}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":14}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":5}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":4}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":3}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":2}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":1}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":13}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":12}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":11}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":10}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":9}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":8}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":7}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":19},{"id":35,"damage":6}],"output":[{"id":35}],"priority":50,"recipe_id":"wool_dye_wool_19_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":15}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":5}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":4}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":3}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":2}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":1}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":13}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":12}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":11}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":10}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":9}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":8}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":7}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":1},{"id":35,"damage":6}],"output":[{"id":35,"damage":14}],"priority":50,"recipe_id":"wool_dye_wool_1_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":15}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":14}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":5}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":4}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":3}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":2}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":1}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":12}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":11}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":10}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":9}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":8}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":7}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":2},{"id":35,"damage":6}],"output":[{"id":35,"damage":13}],"priority":50,"recipe_id":"wool_dye_wool_2_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":15}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":14}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":5}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":4}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":3}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":2}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":1}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":13}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":11}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":10}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":9}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":8}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":7}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":3},{"id":35,"damage":6}],"output":[{"id":35,"damage":12}],"priority":50,"recipe_id":"wool_dye_wool_3_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":15}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":14}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":5}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":4}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":3}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":2}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":1}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":13}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":12}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":10}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":9}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":8}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":7}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":4},{"id":35,"damage":6}],"output":[{"id":35,"damage":11}],"priority":50,"recipe_id":"wool_dye_wool_4_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":15}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":14}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":5}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":4}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":3}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":2}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":1}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":13}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":12}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":11}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":9}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":8}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":7}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":5},{"id":35,"damage":6}],"output":[{"id":35,"damage":10}],"priority":50,"recipe_id":"wool_dye_wool_5_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":15}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":14}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":5}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":4}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":3}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":2}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":1}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":13}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":12}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":11}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":10}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":8}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":7}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":6},{"id":35,"damage":6}],"output":[{"id":35,"damage":9}],"priority":50,"recipe_id":"wool_dye_wool_6_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":15}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":14}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":5}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":4}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":3}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":2}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":1}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":13}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":12}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":11}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":10}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":9}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":7}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_8","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":7},{"id":35,"damage":6}],"output":[{"id":35,"damage":8}],"priority":50,"recipe_id":"wool_dye_wool_7_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":15}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":14}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":5}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":4}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":3}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":2}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":1}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":13}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":12}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":11}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":10}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":9}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":8}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":8},{"id":35,"damage":6}],"output":[{"id":35,"damage":7}],"priority":50,"recipe_id":"wool_dye_wool_8_9","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":15}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_0","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":14}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_1","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":5}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_10","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":4}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_11","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":3}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_12","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":2}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_13","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":1}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_14","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_15","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":13}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_2","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":12}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_3","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":11}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_4","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":10}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_5","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":9}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_6","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":8}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_7","type":"shapeless"},{"block":"crafting_table","input":[{"id":351,"damage":9},{"id":35,"damage":7}],"output":[{"id":35,"damage":6}],"priority":50,"recipe_id":"wool_dye_wool_9_8","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":5}],"output":[{"id":-162,"damage":3,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_andesite_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":5}],"output":[{"id":-171}],"priority":1,"recipe_id":"minecraft:stonecutter_andesite_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":5}],"output":[{"id":139,"damage":4}],"priority":2,"recipe_id":"minecraft:stonecutter_andesite_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":45}],"output":[{"id":44,"damage":4,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_brick_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":45}],"output":[{"id":108}],"priority":1,"recipe_id":"minecraft:stonecutter_brick_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":45}],"output":[{"id":139,"damage":6}],"priority":2,"recipe_id":"minecraft:stonecutter_brick_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":4}],"output":[{"id":44,"damage":3,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_cobbledouble_stone_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":4}],"output":[{"id":67}],"priority":1,"recipe_id":"minecraft:stonecutter_cobblestone_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":4}],"output":[{"id":139}],"priority":2,"recipe_id":"minecraft:stonecutter_cobblestone_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":168,"damage":1}],"output":[{"id":182,"damage":3,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_dark_prismarine_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":168,"damage":1}],"output":[{"id":-3}],"priority":1,"recipe_id":"minecraft:stonecutter_dark_prismarine_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":3}],"output":[{"id":-162,"damage":4,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_diorite_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":3}],"output":[{"id":-170}],"priority":1,"recipe_id":"minecraft:stonecutter_diorite_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":3}],"output":[{"id":139,"damage":3}],"priority":2,"recipe_id":"minecraft:stonecutter_diorite_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":1}],"output":[{"id":-166,"damage":2,"count":2}],"priority":5,"recipe_id":"minecraft:stonecutter_double_stone_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":121}],"output":[{"id":-162,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_endbrick_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":206}],"output":[{"id":-162,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_endbrick_slab2","type":"shapeless"},{"block":"stonecutter","input":[{"id":121}],"output":[{"id":-178}],"priority":1,"recipe_id":"minecraft:stonecutter_endbrick_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":206}],"output":[{"id":-178}],"priority":1,"recipe_id":"minecraft:stonecutter_endbrick_stairs2","type":"shapeless"},{"block":"stonecutter","input":[{"id":121}],"output":[{"id":139,"damage":10}],"priority":2,"recipe_id":"minecraft:stonecutter_endbrick_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":206}],"output":[{"id":139,"damage":10}],"priority":2,"recipe_id":"minecraft:stonecutter_endbrick_wall2","type":"shapeless"},{"block":"stonecutter","input":[{"id":121}],"output":[{"id":206}],"priority":3,"recipe_id":"minecraft:stonecutter_endbricks","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":1}],"output":[{"id":-162,"damage":6,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_granite_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":1}],"output":[{"id":-169}],"priority":1,"recipe_id":"minecraft:stonecutter_granite_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":1}],"output":[{"id":139,"damage":2}],"priority":2,"recipe_id":"minecraft:stonecutter_granite_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":48}],"output":[{"id":182,"damage":5,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_mossy_cobbledouble_stone_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":48}],"output":[{"id":-179}],"priority":1,"recipe_id":"minecraft:stonecutter_mossy_cobblestone_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":48}],"output":[{"id":139,"damage":1}],"priority":2,"recipe_id":"minecraft:stonecutter_mossy_cobblestone_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":98,"damage":1}],"output":[{"id":-166,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_mossy_stonebrick_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":98,"damage":1}],"output":[{"id":-175}],"priority":1,"recipe_id":"minecraft:stonecutter_mossy_stonebrick_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":98,"damage":1}],"output":[{"id":139,"damage":8}],"priority":2,"recipe_id":"minecraft:stonecutter_mossy_stonebrick_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":112}],"output":[{"id":44,"damage":7,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_nether_brick_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":112}],"output":[{"id":114}],"priority":1,"recipe_id":"minecraft:stonecutter_nether_brick_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":112}],"output":[{"id":139,"damage":9}],"priority":2,"recipe_id":"minecraft:stonecutter_nether_brick_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":5}],"output":[{"id":1,"damage":6}],"priority":3,"recipe_id":"minecraft:stonecutter_polished_andesite","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":5}],"output":[{"id":-162,"damage":2,"count":2}],"priority":4,"recipe_id":"minecraft:stonecutter_polished_andesite_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":6}],"output":[{"id":-162,"damage":2,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_polished_andesite_slab2","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":5}],"output":[{"id":-174}],"priority":5,"recipe_id":"minecraft:stonecutter_polished_andesite_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":6}],"output":[{"id":-174}],"priority":1,"recipe_id":"minecraft:stonecutter_polished_andesite_stairs2","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":3}],"output":[{"id":1,"damage":4}],"priority":3,"recipe_id":"minecraft:stonecutter_polished_diorite","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":3}],"output":[{"id":-162,"damage":5,"count":2}],"priority":4,"recipe_id":"minecraft:stonecutter_polished_diorite_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":4}],"output":[{"id":-162,"damage":5,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_polished_diorite_slab2","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":3}],"output":[{"id":-173}],"priority":5,"recipe_id":"minecraft:stonecutter_polished_diorite_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":4}],"output":[{"id":-173}],"priority":1,"recipe_id":"minecraft:stonecutter_polished_diorite_stairs2","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":1}],"output":[{"id":1,"damage":2}],"priority":3,"recipe_id":"minecraft:stonecutter_polished_granite","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":1}],"output":[{"id":-162,"damage":7,"count":2}],"priority":4,"recipe_id":"minecraft:stonecutter_polished_granite_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":2}],"output":[{"id":-162,"damage":7,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_polished_granite_slab2","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":1}],"output":[{"id":-172}],"priority":5,"recipe_id":"minecraft:stonecutter_polished_granite_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":1,"damage":2}],"output":[{"id":-172}],"priority":1,"recipe_id":"minecraft:stonecutter_polished_granite_stairs2","type":"shapeless"},{"block":"stonecutter","input":[{"id":168,"damage":2}],"output":[{"id":182,"damage":4,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_prismarine_brick_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":168,"damage":2}],"output":[{"id":-4}],"priority":1,"recipe_id":"minecraft:stonecutter_prismarine_brick_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":168}],"output":[{"id":182,"damage":2,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_prismarine_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":168}],"output":[{"id":-2}],"priority":1,"recipe_id":"minecraft:stonecutter_prismarine_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":168}],"output":[{"id":139,"damage":11}],"priority":2,"recipe_id":"minecraft:stonecutter_prismarine_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":201}],"output":[{"id":201,"damage":2}],"priority":0,"recipe_id":"minecraft:stonecutter_purpur_lines","type":"shapeless"},{"block":"stonecutter","input":[{"id":201}],"output":[{"id":182,"damage":1,"count":2}],"priority":1,"recipe_id":"minecraft:stonecutter_purpur_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":201}],"output":[{"id":203}],"priority":2,"recipe_id":"minecraft:stonecutter_purpur_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":155}],"output":[{"id":155,"damage":1}],"priority":0,"recipe_id":"minecraft:stonecutter_quartz_chiseled","type":"shapeless"},{"block":"stonecutter","input":[{"id":155}],"output":[{"id":155,"damage":2}],"priority":1,"recipe_id":"minecraft:stonecutter_quartz_lines","type":"shapeless"},{"block":"stonecutter","input":[{"id":155}],"output":[{"id":-166,"damage":1,"count":2}],"priority":2,"recipe_id":"minecraft:stonecutter_quartz_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":155}],"output":[{"id":156}],"priority":3,"recipe_id":"minecraft:stonecutter_quartz_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":215}],"output":[{"id":182,"damage":7,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_red_nether_brick_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":215}],"output":[{"id":-184}],"priority":1,"recipe_id":"minecraft:stonecutter_red_nether_brick_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":215}],"output":[{"id":139,"damage":13}],"priority":2,"recipe_id":"minecraft:stonecutter_red_nether_brick_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":179}],"output":[{"id":182,"count":2}],"priority":2,"recipe_id":"minecraft:stonecutter_red_sanddouble_stone_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":179}],"output":[{"id":179,"damage":2}],"priority":1,"recipe_id":"minecraft:stonecutter_red_sandstone_cut","type":"shapeless"},{"block":"stonecutter","input":[{"id":179}],"output":[{"id":179,"damage":1}],"priority":0,"recipe_id":"minecraft:stonecutter_red_sandstone_heiroglyphs","type":"shapeless"},{"block":"stonecutter","input":[{"id":179}],"output":[{"id":180}],"priority":3,"recipe_id":"minecraft:stonecutter_red_sandstone_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":179}],"output":[{"id":139,"damage":12}],"priority":4,"recipe_id":"minecraft:stonecutter_red_sandstone_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":24}],"output":[{"id":44,"damage":1,"count":2}],"priority":2,"recipe_id":"minecraft:stonecutter_sanddouble_stone_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":24}],"output":[{"id":24,"damage":2}],"priority":1,"recipe_id":"minecraft:stonecutter_sandstone_cut","type":"shapeless"},{"block":"stonecutter","input":[{"id":24}],"output":[{"id":24,"damage":1}],"priority":0,"recipe_id":"minecraft:stonecutter_sandstone_heiroglyphs","type":"shapeless"},{"block":"stonecutter","input":[{"id":24}],"output":[{"id":128}],"priority":3,"recipe_id":"minecraft:stonecutter_sandstone_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":24}],"output":[{"id":139,"damage":5}],"priority":4,"recipe_id":"minecraft:stonecutter_sandstone_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":-183}],"output":[{"id":44,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_smooth_double_stone_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":155,"damage":3}],"output":[{"id":-166,"damage":1,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_smooth_quartz_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":155,"damage":3}],"output":[{"id":-185}],"priority":1,"recipe_id":"minecraft:stonecutter_smooth_quartz_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":179,"damage":3}],"output":[{"id":-162,"damage":1,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_smooth_red_sanddouble_stone_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":179,"damage":3}],"output":[{"id":-176}],"priority":1,"recipe_id":"minecraft:stonecutter_smooth_red_sandstone_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":24,"damage":3}],"output":[{"id":182,"damage":6,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_smooth_sanddouble_stone_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":24,"damage":3}],"output":[{"id":-177}],"priority":1,"recipe_id":"minecraft:stonecutter_smooth_sandstone_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":1}],"output":[{"id":-180}],"priority":6,"recipe_id":"minecraft:stonecutter_stone_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":1}],"output":[{"id":98}],"priority":4,"recipe_id":"minecraft:stonecutter_stonebrick","type":"shapeless"},{"block":"stonecutter","input":[{"id":1}],"output":[{"id":98,"damage":3}],"priority":0,"recipe_id":"minecraft:stonecutter_stonebrick_chiseled","type":"shapeless"},{"block":"stonecutter","input":[{"id":1}],"output":[{"id":44,"damage":5,"count":2}],"priority":1,"recipe_id":"minecraft:stonecutter_stonebrick_slab","type":"shapeless"},{"block":"stonecutter","input":[{"id":98}],"output":[{"id":44,"damage":5,"count":2}],"priority":0,"recipe_id":"minecraft:stonecutter_stonebrick_slab2","type":"shapeless"},{"block":"stonecutter","input":[{"id":1}],"output":[{"id":109}],"priority":2,"recipe_id":"minecraft:stonecutter_stonebrick_stairs","type":"shapeless"},{"block":"stonecutter","input":[{"id":98}],"output":[{"id":109}],"priority":1,"recipe_id":"minecraft:stonecutter_stonebrick_stairs2","type":"shapeless"},{"block":"stonecutter","input":[{"id":1}],"output":[{"id":139,"damage":7}],"priority":3,"recipe_id":"minecraft:stonecutter_stonebrick_wall","type":"shapeless"},{"block":"stonecutter","input":[{"id":98}],"output":[{"id":139,"damage":7}],"priority":2,"recipe_id":"minecraft:stonecutter_stonebrick_wall2","type":"shapeless"},{"type":"special_hardcoded","uuid":"442d85ed-8272-4543-a6f1-418f90ded05d"},{"type":"special_hardcoded","uuid":"8b36268c-1829-483c-a0f1-993b7156a8f2"},{"type":"special_hardcoded","uuid":"602234e4-cac1-4353-8bb7-b1ebff70024b"},{"block":"cartography_table","input":[{"id":339,"damage":-1},{"id":345,"damage":-1}],"output":[{"id":395,"damage":2}],"priority":0,"recipe_id":"minecraft:cartography_table_locator_map","type":"shapeless"},{"block":"cartography_table","input":[{"id":339,"damage":-1}],"output":[{"id":395}],"priority":0,"recipe_id":"minecraft:cartography_table_map","type":"shapeless"},{"type":"special_hardcoded","uuid":"98c84b38-1085-46bd-b1ce-dd38c159e6cc"},{"block":"furnace","input":{"id":-212},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":1},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":2},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":3},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":4},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":5},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":8},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":9},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":10},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":11},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":12},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-212,"damage":13},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-156,"damage":-1},"output":{"id":351,"damage":10},"type":"smelting"},{"block":"furnace","input":{"id":-10,"damage":-1},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-9,"damage":-1},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-8,"damage":-1},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-7,"damage":-1},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-6,"damage":-1},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":-5,"damage":-1},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":1},"output":{"id":-183},"type":"smelting"},{"block":"furnace","input":{"id":4,"damage":-1},"output":{"id":1},"type":"smelting"},{"block":"furnace","input":{"id":12,"damage":-1},"output":{"id":20},"type":"smelting"},{"block":"furnace","input":{"id":14,"damage":-1},"output":{"id":266},"type":"smelting"},{"block":"blast_furnace","input":{"id":14,"damage":-1},"output":{"id":266},"type":"smelting"},{"block":"furnace","input":{"id":15,"damage":-1},"output":{"id":265},"type":"smelting"},{"block":"blast_furnace","input":{"id":15,"damage":-1},"output":{"id":265},"type":"smelting"},{"block":"furnace","input":{"id":16,"damage":-1},"output":{"id":263},"type":"smelting"},{"block":"blast_furnace","input":{"id":16,"damage":-1},"output":{"id":263},"type":"smelting"},{"block":"furnace","input":{"id":17},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":17,"damage":1},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":17,"damage":2},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":17,"damage":3},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":19,"damage":1},"output":{"id":19},"type":"smelting"},{"block":"furnace","input":{"id":21,"damage":-1},"output":{"id":351,"damage":4},"type":"smelting"},{"block":"blast_furnace","input":{"id":21,"damage":-1},"output":{"id":351,"damage":4},"type":"smelting"},{"block":"furnace","input":{"id":24,"damage":-1},"output":{"id":24,"damage":3},"type":"smelting"},{"block":"furnace","input":{"id":56,"damage":-1},"output":{"id":264},"type":"smelting"},{"block":"blast_furnace","input":{"id":56,"damage":-1},"output":{"id":264},"type":"smelting"},{"block":"furnace","input":{"id":73,"damage":-1},"output":{"id":331},"type":"smelting"},{"block":"blast_furnace","input":{"id":73,"damage":-1},"output":{"id":331},"type":"smelting"},{"block":"furnace","input":{"id":81,"damage":-1},"output":{"id":351,"damage":2},"type":"smelting"},{"block":"furnace","input":{"id":82,"damage":-1},"output":{"id":172},"type":"smelting"},{"block":"furnace","input":{"id":87,"damage":-1},"output":{"id":405},"type":"smelting"},{"block":"furnace","input":{"id":98},"output":{"id":98,"damage":2},"type":"smelting"},{"block":"furnace","input":{"id":129,"damage":-1},"output":{"id":388},"type":"smelting"},{"block":"blast_furnace","input":{"id":129,"damage":-1},"output":{"id":388},"type":"smelting"},{"block":"furnace","input":{"id":153,"damage":-1},"output":{"id":406},"type":"smelting"},{"block":"blast_furnace","input":{"id":153,"damage":-1},"output":{"id":406},"type":"smelting"},{"block":"furnace","input":{"id":155,"damage":-1},"output":{"id":155,"damage":3},"type":"smelting"},{"block":"furnace","input":{"id":159},"output":{"id":220},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":1},"output":{"id":221},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":2},"output":{"id":222},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":3},"output":{"id":223},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":4},"output":{"id":224},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":5},"output":{"id":225},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":6},"output":{"id":226},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":7},"output":{"id":227},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":8},"output":{"id":228},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":9},"output":{"id":229},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":10},"output":{"id":219},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":11},"output":{"id":231},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":12},"output":{"id":232},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":13},"output":{"id":233},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":14},"output":{"id":234},"type":"smelting"},{"block":"furnace","input":{"id":159,"damage":15},"output":{"id":235},"type":"smelting"},{"block":"furnace","input":{"id":162},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":162,"damage":1},"output":{"id":263,"damage":1},"type":"smelting"},{"block":"furnace","input":{"id":179,"damage":-1},"output":{"id":179,"damage":3},"type":"smelting"},{"block":"furnace","input":{"id":256},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":256},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":257},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":257},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":258},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":258},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":267},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":267},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":283},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":283},"output":{"id":371},"type":"smelting"},{"block":"furnace","input":{"id":284},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":284},"output":{"id":371},"type":"smelting"},{"block":"furnace","input":{"id":285},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":285},"output":{"id":371},"type":"smelting"},{"block":"furnace","input":{"id":286},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":286},"output":{"id":371},"type":"smelting"},{"block":"furnace","input":{"id":292},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":292},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":294},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":294},"output":{"id":371},"type":"smelting"},{"block":"furnace","input":{"id":302},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":302},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":303},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":303},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":304},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":304},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":305},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":305},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":306},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":306},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":307},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":307},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":308},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":308},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":309},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":309},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":314},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":314},"output":{"id":371},"type":"smelting"},{"block":"furnace","input":{"id":315},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":315},"output":{"id":371},"type":"smelting"},{"block":"furnace","input":{"id":316},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":316},"output":{"id":371},"type":"smelting"},{"block":"furnace","input":{"id":317},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":317},"output":{"id":371},"type":"smelting"},{"block":"smoker","input":{"id":319,"damage":-1},"output":{"id":320},"type":"smelting"},{"block":"furnace","input":{"id":319,"damage":-1},"output":{"id":320},"type":"smelting"},{"block":"campfire","input":{"id":319,"damage":-1},"output":{"id":320},"type":"smelting"},{"block":"smoker","input":{"id":335,"damage":-1},"output":{"id":464},"type":"smelting"},{"block":"furnace","input":{"id":335,"damage":-1},"output":{"id":464},"type":"smelting"},{"block":"campfire","input":{"id":335,"damage":-1},"output":{"id":464},"type":"smelting"},{"block":"furnace","input":{"id":337,"damage":-1},"output":{"id":336},"type":"smelting"},{"block":"smoker","input":{"id":349,"damage":-1},"output":{"id":350},"type":"smelting"},{"block":"furnace","input":{"id":349,"damage":-1},"output":{"id":350},"type":"smelting"},{"block":"campfire","input":{"id":349,"damage":-1},"output":{"id":350},"type":"smelting"},{"block":"smoker","input":{"id":363,"damage":-1},"output":{"id":364},"type":"smelting"},{"block":"furnace","input":{"id":363,"damage":-1},"output":{"id":364},"type":"smelting"},{"block":"campfire","input":{"id":363,"damage":-1},"output":{"id":364},"type":"smelting"},{"block":"smoker","input":{"id":365,"damage":-1},"output":{"id":366},"type":"smelting"},{"block":"furnace","input":{"id":365,"damage":-1},"output":{"id":366},"type":"smelting"},{"block":"campfire","input":{"id":365,"damage":-1},"output":{"id":366},"type":"smelting"},{"block":"smoker","input":{"id":392,"damage":-1},"output":{"id":393},"type":"smelting"},{"block":"furnace","input":{"id":392,"damage":-1},"output":{"id":393},"type":"smelting"},{"block":"campfire","input":{"id":392,"damage":-1},"output":{"id":393},"type":"smelting"},{"block":"smoker","input":{"id":411,"damage":-1},"output":{"id":412},"type":"smelting"},{"block":"furnace","input":{"id":411,"damage":-1},"output":{"id":412},"type":"smelting"},{"block":"campfire","input":{"id":411,"damage":-1},"output":{"id":412},"type":"smelting"},{"block":"furnace","input":{"id":417,"damage":-1},"output":{"id":452},"type":"smelting"},{"block":"blast_furnace","input":{"id":417,"damage":-1},"output":{"id":452},"type":"smelting"},{"block":"furnace","input":{"id":418,"damage":-1},"output":{"id":371},"type":"smelting"},{"block":"blast_furnace","input":{"id":418,"damage":-1},"output":{"id":371},"type":"smelting"},{"block":"smoker","input":{"id":423,"damage":-1},"output":{"id":424},"type":"smelting"},{"block":"furnace","input":{"id":423,"damage":-1},"output":{"id":424},"type":"smelting"},{"block":"campfire","input":{"id":423,"damage":-1},"output":{"id":424},"type":"smelting"},{"block":"furnace","input":{"id":432,"damage":-1},"output":{"id":433},"type":"smelting"},{"block":"smoker","input":{"id":460,"damage":-1},"output":{"id":463},"type":"smelting"},{"block":"furnace","input":{"id":460,"damage":-1},"output":{"id":463},"type":"smelting"},{"block":"campfire","input":{"id":460,"damage":-1},"output":{"id":463},"type":"smelting"},{"ingredient":{"id":331},"input_potion_id":14,"output_potion_id":15,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":9,"output_potion_id":17,"type":"potion_type"},{"ingredient":{"id":470},"input_potion_id":4,"output_potion_id":40,"type":"potion_type"},{"ingredient":{"id":382},"input_potion_id":0,"output_potion_id":1,"type":"potion_type"},{"ingredient":{"id":375},"input_potion_id":0,"output_potion_id":1,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":7,"output_potion_id":8,"type":"potion_type"},{"ingredient":{"id":414},"input_potion_id":0,"output_potion_id":1,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":4,"output_potion_id":34,"type":"potion_type"},{"ingredient":{"id":396},"input_potion_id":4,"output_potion_id":5,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":27,"output_potion_id":23,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":40,"output_potion_id":41,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":33,"output_potion_id":34,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":19,"output_potion_id":20,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":0,"output_potion_id":34,"type":"potion_type"},{"ingredient":{"id":378},"input_potion_id":0,"output_potion_id":1,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":37,"output_potion_id":38,"type":"potion_type"},{"ingredient":{"id":377},"input_potion_id":0,"output_potion_id":1,"type":"potion_type"},{"ingredient":{"id":353},"input_potion_id":4,"output_potion_id":14,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":28,"output_potion_id":29,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":0,"output_potion_id":1,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":9,"output_potion_id":10,"type":"potion_type"},{"ingredient":{"id":348},"input_potion_id":23,"output_potion_id":24,"type":"potion_type"},{"ingredient":{"id":348},"input_potion_id":37,"output_potion_id":39,"type":"potion_type"},{"ingredient":{"id":370},"input_potion_id":0,"output_potion_id":1,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":34,"output_potion_id":35,"type":"potion_type"},{"ingredient":{"id":348},"input_potion_id":31,"output_potion_id":33,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":26,"output_potion_id":23,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":15,"output_potion_id":18,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":22,"output_potion_id":24,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":25,"output_potion_id":23,"type":"potion_type"},{"ingredient":{"id":377},"input_potion_id":4,"output_potion_id":31,"type":"potion_type"},{"ingredient":{"id":469},"input_potion_id":4,"output_potion_id":37,"type":"potion_type"},{"ingredient":{"id":348},"input_potion_id":21,"output_potion_id":22,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":21,"output_potion_id":23,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":5,"output_potion_id":6,"type":"potion_type"},{"ingredient":{"id":353},"input_potion_id":0,"output_potion_id":1,"type":"potion_type"},{"ingredient":{"id":372},"input_potion_id":0,"output_potion_id":4,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":3,"output_potion_id":34,"type":"potion_type"},{"ingredient":{"id":462},"input_potion_id":4,"output_potion_id":19,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":1,"output_potion_id":34,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":25,"output_potion_id":26,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":17,"output_potion_id":18,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":10,"output_potion_id":18,"type":"potion_type"},{"ingredient":{"id":348},"input_potion_id":0,"output_potion_id":3,"type":"potion_type"},{"ingredient":{"id":348},"input_potion_id":25,"output_potion_id":27,"type":"potion_type"},{"ingredient":{"id":375},"input_potion_id":4,"output_potion_id":25,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":14,"output_potion_id":17,"type":"potion_type"},{"ingredient":{"id":414},"input_potion_id":4,"output_potion_id":9,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":12,"output_potion_id":13,"type":"potion_type"},{"ingredient":{"id":382},"input_potion_id":4,"output_potion_id":21,"type":"potion_type"},{"ingredient":{"id":370},"input_potion_id":4,"output_potion_id":28,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":31,"output_potion_id":34,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":32,"output_potion_id":35,"type":"potion_type"},{"ingredient":{"id":348},"input_potion_id":14,"output_potion_id":16,"type":"potion_type"},{"ingredient":{"id":348},"input_potion_id":9,"output_potion_id":11,"type":"potion_type"},{"ingredient":{"id":348},"input_potion_id":28,"output_potion_id":30,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":5,"output_potion_id":7,"type":"potion_type"},{"ingredient":{"id":378},"input_potion_id":4,"output_potion_id":12,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":6,"output_potion_id":8,"type":"potion_type"},{"ingredient":{"id":376},"input_potion_id":2,"output_potion_id":35,"type":"potion_type"},{"ingredient":{"id":331},"input_potion_id":31,"output_potion_id":32,"type":"potion_type"},{"ingredient":{"id":289},"input_item_id":373,"output_item_id":438,"type":"potion_container_change"},{"ingredient":{"id":437},"input_item_id":438,"output_item_id":441,"type":"potion_container_change"}]<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use function array_map;
use function array_values;
use function count;
use function implode;
use function strlen;
use function strpos;

class ShapedRecipe implements CraftingRecipe{
	/** @var string[] */
	private $shape = [];
	/** @var Item[] char => Item map */
	private $ingredientList = [];
	/** @var Item[] */
	private $results = [];

	/** @var int */
	private $height;
	/** @var int */
	private $width;

	/**
	 * Constructs a ShapedRecipe instance.
	 *
	 * @param string[] $shape <br>
	 *     Array of 1, 2, or 3 strings representing the rows of the recipe.
	 *     This accepts an array of 1, 2 or 3 strings. Each string should be of the same length and must be at most 3
	 *     characters long. Each character represents a unique type of ingredient. Spaces are interpreted as air.
	 * @param Item[]   $ingredients <br>
	 *     Char => Item map of items to be set into the shape.
	 *     This accepts an array of Items, indexed by character. Every unique character (except space) in the shape
	 *     array MUST have a corresponding item in this list. Space character is automatically treated as air.
	 * @param Item[]   $results List of items that this recipe produces when crafted.
	 *
	 * Note: Recipes **do not** need to be square. Do NOT add padding for empty rows/columns.
	 */
	public function __construct(array $shape, array $ingredients, array $results){
		$this->height = count($shape);
		if($this->height > 3 or $this->height <= 0){
			throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 rows, not $this->height");
		}

		$shape = array_values($shape);

		$this->width = strlen($shape[0]);
		if($this->width > 3 or $this->width <= 0){
			throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 columns, not $this->width");
		}

		foreach($shape as $y => $row){
			if(strlen($row) !== $this->width){
				throw new \InvalidArgumentException("Shaped recipe rows must all have the same length (expected $this->width, got " . strlen($row) . ")");
			}

			for($x = 0; $x < $this->width; ++$x){
				if($row[$x] !== ' ' and !isset($ingredients[$row[$x]])){
					throw new \InvalidArgumentException("No item specified for symbol '" . $row[$x] . "'");
				}
			}
		}

		$this->shape = $shape;

		foreach($ingredients as $char => $i){
			$this->setIngredient($char, $i);
		}

		$this->results = array_map(function(Item $item) : Item{ return clone $item; }, $results);
	}

	public function getWidth() : int{
		return $this->width;
	}

	public function getHeight() : int{
		return $this->height;
	}

	/**
	 * @return Item[]
	 */
	public function getResults() : array{
		return array_map(function(Item $item) : Item{ return clone $item; }, $this->results);
	}

	/**
	 * @return Item[]
	 */
	public function getResultsFor(CraftingGrid $grid) : array{
		return $this->getResults();
	}

	/**
	 * @return $this
	 * @throws \InvalidArgumentException
	 */
	public function setIngredient(string $key, Item $item){
		if(strpos(implode($this->shape), $key) === false){
			throw new \InvalidArgumentException("Symbol '$key' does not appear in the recipe shape");
		}

		$this->ingredientList[$key] = clone $item;

		return $this;
	}

	/**
	 * @return Item[][]
	 */
	public function getIngredientMap() : array{
		$ingredients = [];

		for($y = 0; $y < $this->height; ++$y){
			for($x = 0; $x < $this->width; ++$x){
				$ingredients[$y][$x] = $this->getIngredient($x, $y);
			}
		}

		return $ingredients;
	}

	/**
	 * @return Item[]
	 */
	public function getIngredientList() : array{
		$ingredients = [];

		for($y = 0; $y < $this->height; ++$y){
			for($x = 0; $x < $this->width; ++$x){
				$ingredient = $this->getIngredient($x, $y);
				if(!$ingredient->isNull()){
					$ingredients[] = $ingredient;
				}
			}
		}

		return $ingredients;
	}

	public function getIngredient(int $x, int $y) : Item{
		$exists = $this->ingredientList[$this->shape[$y]{$x}] ?? null;
		return $exists !== null ? clone $exists : ItemFactory::get(Item::AIR, 0, 0);
	}

	/**
	 * Returns an array of strings containing characters representing the recipe's shape.
	 * @return string[]
	 */
	public function getShape() : array{
		return $this->shape;
	}

	public function registerToCraftingManager(CraftingManager $manager) : void{
		$manager->registerShapedRecipe($this);
	}

	private function matchInputMap(CraftingGrid $grid, bool $reverse) : bool{
		for($y = 0; $y < $this->height; ++$y){
			for($x = 0; $x < $this->width; ++$x){

				$given = $grid->getIngredient($reverse ? $this->width - $x - 1 : $x, $y);
				$required = $this->getIngredient($x, $y);
				if(!$required->equals($given, !$required->hasAnyDamageValue(), $required->hasCompoundTag()) or $required->getCount() > $given->getCount()){
					return false;
				}
			}
		}

		return true;
	}

	public function matchesCraftingGrid(CraftingGrid $grid) : bool{
		if($this->width !== $grid->getRecipeWidth() or $this->height !== $grid->getRecipeHeight()){
			return false;
		}

		return $this->matchInputMap($grid, false) or $this->matchInputMap($grid, true);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\item\Item;

interface CraftingRecipe extends Recipe{
	/**
	 * Returns a list of items needed to craft this recipe. This MUST NOT include Air items or items with a zero count.
	 *
	 * @return Item[]
	 */
	public function getIngredientList() : array;

	/**
	 * Returns a list of results this recipe will produce when the inputs in the given crafting grid are consumed.
	 *
	 * @return Item[]
	 */
	public function getResultsFor(CraftingGrid $grid) : array;

	/**
	 * Returns whether the given crafting grid meets the requirements to craft this recipe.
	 */
	public function matchesCraftingGrid(CraftingGrid $grid) : bool;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

interface Recipe{

	public function registerToCraftingManager(CraftingManager $manager) : void;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\item\Item;
use function array_map;
use function count;

class ShapelessRecipe implements CraftingRecipe{
	/** @var Item[] */
	private $ingredients = [];
	/** @var Item[] */
	private $results;

	/**
	 * @param Item[] $ingredients No more than 9 total. This applies to sum of item stack counts, not count of array.
	 * @param Item[] $results List of result items created by this recipe.
	 */
	public function __construct(array $ingredients, array $results){
		foreach($ingredients as $item){
			//Ensure they get split up properly
			$this->addIngredient($item);
		}

		$this->results = array_map(function(Item $item) : Item{ return clone $item; }, $results);
	}

	/**
	 * @return Item[]
	 */
	public function getResults() : array{
		return array_map(function(Item $item) : Item{ return clone $item; }, $this->results);
	}

	public function getResultsFor(CraftingGrid $grid) : array{
		return $this->getResults();
	}

	/**
	 * @throws \InvalidArgumentException
	 */
	public function addIngredient(Item $item) : ShapelessRecipe{
		if(count($this->ingredients) + $item->getCount() > 9){
			throw new \InvalidArgumentException("Shapeless recipes cannot have more than 9 ingredients");
		}

		while($item->getCount() > 0){
			$this->ingredients[] = $item->pop();
		}

		return $this;
	}

	/**
	 * @return $this
	 */
	public function removeIngredient(Item $item){
		foreach($this->ingredients as $index => $ingredient){
			if($item->getCount() <= 0){
				break;
			}
			if($ingredient->equals($item, !$item->hasAnyDamageValue(), $item->hasCompoundTag())){
				unset($this->ingredients[$index]);
				$item->pop();
			}
		}

		return $this;
	}

	/**
	 * @return Item[]
	 */
	public function getIngredientList() : array{
		return array_map(function(Item $item) : Item{ return clone $item; }, $this->ingredients);
	}

	public function getIngredientCount() : int{
		$count = 0;
		foreach($this->ingredients as $ingredient){
			$count += $ingredient->getCount();
		}

		return $count;
	}

	public function registerToCraftingManager(CraftingManager $manager) : void{
		$manager->registerShapelessRecipe($this);
	}

	public function matchesCraftingGrid(CraftingGrid $grid) : bool{
		//don't pack the ingredients - shapeless recipes require that each ingredient be in a separate slot
		$input = $grid->getContents();

		foreach($this->ingredients as $needItem){
			foreach($input as $j => $haveItem){
				if($haveItem->equals($needItem, !$needItem->hasAnyDamageValue(), $needItem->hasCompoundTag()) and $haveItem->getCount() >= $needItem->getCount()){
					unset($input[$j]);
					continue 2;
				}
			}

			return false; //failed to match the needed item to a given item
		}

		return count($input) === 0; //crafting grid should be empty apart from the given ingredient stacks
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\item\Item;

class FurnaceRecipe implements Recipe{

	/** @var Item */
	private $output;

	/** @var Item */
	private $ingredient;

	public function __construct(Item $result, Item $ingredient){
		$this->output = clone $result;
		$this->ingredient = clone $ingredient;
	}

	/**
	 * @return void
	 */
	public function setInput(Item $item){
		$this->ingredient = clone $item;
	}

	public function getInput() : Item{
		return clone $this->ingredient;
	}

	public function getResult() : Item{
		return clone $this->output;
	}

	public function registerToCraftingManager(CraftingManager $manager) : void{
		$manager->registerFurnaceRecipe($this);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Methods for working with binary strings
 */
namespace pocketmine\utils;

use InvalidArgumentException;
use function chr;
use function define;
use function defined;
use function ord;
use function pack;
use function preg_replace;
use function round;
use function sprintf;
use function substr;
use function unpack;
use const PHP_INT_MAX;

if(!defined("ENDIANNESS")){
	define("ENDIANNESS", (pack("s", 1) === "\0\1" ? Binary::BIG_ENDIAN : Binary::LITTLE_ENDIAN));
}

class Binary{
	public const BIG_ENDIAN = 0x00;
	public const LITTLE_ENDIAN = 0x01;

	public static function signByte(int $value) : int{
		return $value << 56 >> 56;
	}

	public static function unsignByte(int $value) : int{
		return $value & 0xff;
	}

	public static function signShort(int $value) : int{
		return $value << 48 >> 48;
	}

	public static function unsignShort(int $value) : int{
		return $value & 0xffff;
	}

	public static function signInt(int $value) : int{
		return $value << 32 >> 32;
	}

	public static function unsignInt(int $value) : int{
		return $value & 0xffffffff;
	}


	public static function flipShortEndianness(int $value) : int{
		return self::readLShort(self::writeShort($value));
	}

	public static function flipIntEndianness(int $value) : int{
		return self::readLInt(self::writeInt($value));
	}

	public static function flipLongEndianness(int $value) : int{
		return self::readLLong(self::writeLong($value));
	}

	/**
	 * Reads a byte boolean
	 *
	 * @param string $b
	 *
	 * @return bool
	 */
	public static function readBool(string $b) : bool{
		return $b !== "\x00";
	}

	/**
	 * Writes a byte boolean
	 *
	 * @param bool $b
	 *
	 * @return string
	 */
	public static function writeBool(bool $b) : string{
		return $b ? "\x01" : "\x00";
	}

	/**
	 * Reads an unsigned byte (0 - 255)
	 *
	 * @param string $c
	 *
	 * @return int
	 */
	public static function readByte(string $c) : int{
		return ord($c[0]);
	}

	/**
	 * Reads a signed byte (-128 - 127)
	 *
	 * @param string $c
	 *
	 * @return int
	 */
	public static function readSignedByte(string $c) : int{
		return self::signByte(ord($c[0]));
	}

	/**
	 * Writes an unsigned/signed byte
	 *
	 * @param int $c
	 *
	 * @return string
	 */
	public static function writeByte(int $c) : string{
		return chr($c);
	}

	/**
	 * Reads a 16-bit unsigned big-endian number
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readShort(string $str) : int{
		return unpack("n", $str)[1];
	}

	/**
	 * Reads a 16-bit signed big-endian number
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readSignedShort(string $str) : int{
		return self::signShort(unpack("n", $str)[1]);
	}

	/**
	 * Writes a 16-bit signed/unsigned big-endian number
	 *
	 * @param int $value
	 *
	 * @return string
	 */
	public static function writeShort(int $value) : string{
		return pack("n", $value);
	}

	/**
	 * Reads a 16-bit unsigned little-endian number
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readLShort(string $str) : int{
		return unpack("v", $str)[1];
	}

	/**
	 * Reads a 16-bit signed little-endian number
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readSignedLShort(string $str) : int{
		return self::signShort(unpack("v", $str)[1]);
	}

	/**
	 * Writes a 16-bit signed/unsigned little-endian number
	 *
	 * @param int $value
	 *
	 * @return string
	 */
	public static function writeLShort(int $value) : string{
		return pack("v", $value);
	}

	/**
	 * Reads a 3-byte big-endian number
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readTriad(string $str) : int{
		return unpack("N", "\x00" . $str)[1];
	}

	/**
	 * Writes a 3-byte big-endian number
	 *
	 * @param int $value
	 *
	 * @return string
	 */
	public static function writeTriad(int $value) : string{
		return substr(pack("N", $value), 1);
	}

	/**
	 * Reads a 3-byte little-endian number
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readLTriad(string $str) : int{
		return unpack("V", $str . "\x00")[1];
	}

	/**
	 * Writes a 3-byte little-endian number
	 *
	 * @param int $value
	 *
	 * @return string
	 */
	public static function writeLTriad(int $value) : string{
		return substr(pack("V", $value), 0, -1);
	}

	/**
	 * Reads a 4-byte signed integer
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readInt(string $str) : int{
		return self::signInt(unpack("N", $str)[1]);
	}

	/**
	 * Writes a 4-byte integer
	 *
	 * @param int $value
	 *
	 * @return string
	 */
	public static function writeInt(int $value) : string{
		return pack("N", $value);
	}

	/**
	 * Reads a 4-byte signed little-endian integer
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readLInt(string $str) : int{
		return self::signInt(unpack("V", $str)[1]);
	}

	/**
	 * Writes a 4-byte signed little-endian integer
	 *
	 * @param int $value
	 *
	 * @return string
	 */
	public static function writeLInt(int $value) : string{
		return pack("V", $value);
	}

	/**
	 * Reads a 4-byte floating-point number
	 *
	 * @param string $str
	 *
	 * @return float
	 */
	public static function readFloat(string $str) : float{
		return unpack("G", $str)[1];
	}

	/**
	 * Reads a 4-byte floating-point number, rounded to the specified number of decimal places.
	 *
	 * @param string $str
	 * @param int    $accuracy
	 *
	 * @return float
	 */
	public static function readRoundedFloat(string $str, int $accuracy) : float{
		return round(self::readFloat($str), $accuracy);
	}

	/**
	 * Writes a 4-byte floating-point number.
	 *
	 * @param float $value
	 *
	 * @return string
	 */
	public static function writeFloat(float $value) : string{
		return pack("G", $value);
	}

	/**
	 * Reads a 4-byte little-endian floating-point number.
	 *
	 * @param string $str
	 *
	 * @return float
	 */
	public static function readLFloat(string $str) : float{
		return unpack("g", $str)[1];
	}

	/**
	 * Reads a 4-byte little-endian floating-point number rounded to the specified number of decimal places.
	 *
	 * @param string $str
	 * @param int    $accuracy
	 *
	 * @return float
	 */
	public static function readRoundedLFloat(string $str, int $accuracy) : float{
		return round(self::readLFloat($str), $accuracy);
	}

	/**
	 * Writes a 4-byte little-endian floating-point number.
	 *
	 * @param float $value
	 *
	 * @return string
	 */
	public static function writeLFloat(float $value) : string{
		return pack("g", $value);
	}

	/**
	 * Returns a printable floating-point number.
	 *
	 * @param float $value
	 *
	 * @return string
	 */
	public static function printFloat(float $value) : string{
		return preg_replace("/(\\.\\d+?)0+$/", "$1", sprintf("%F", $value));
	}

	/**
	 * Reads an 8-byte floating-point number.
	 *
	 * @param string $str
	 *
	 * @return float
	 */
	public static function readDouble(string $str) : float{
		return unpack("E", $str)[1];
	}

	/**
	 * Writes an 8-byte floating-point number.
	 *
	 * @param float $value
	 *
	 * @return string
	 */
	public static function writeDouble(float $value) : string{
		return pack("E", $value);
	}

	/**
	 * Reads an 8-byte little-endian floating-point number.
	 *
	 * @param string $str
	 *
	 * @return float
	 */
	public static function readLDouble(string $str) : float{
		return unpack("e", $str)[1];
	}

	/**
	 * Writes an 8-byte floating-point little-endian number.
	 *
	 * @param float $value
	 *
	 * @return string
	 */
	public static function writeLDouble(float $value) : string{
		return pack("e", $value);
	}

	/**
	 * Reads an 8-byte integer.
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readLong(string $str) : int{
		return unpack("J", $str)[1];
	}

	/**
	 * Writes an 8-byte integer.
	 *
	 * @param int $value
	 *
	 * @return string
	 */
	public static function writeLong(int $value) : string{
		return pack("J", $value);
	}

	/**
	 * Reads an 8-byte little-endian integer.
	 *
	 * @param string $str
	 *
	 * @return int
	 */
	public static function readLLong(string $str) : int{
		return unpack("P", $str)[1];
	}

	/**
	 * Writes an 8-byte little-endian integer.
	 *
	 * @param int $value
	 *
	 * @return string
	 */
	public static function writeLLong(int $value) : string{
		return pack("P", $value);
	}


	/**
	 * Reads a 32-bit zigzag-encoded variable-length integer.
	 *
	 * @param string $buffer
	 * @param int    $offset reference parameter
	 *
	 * @return int
	 */
	public static function readVarInt(string $buffer, int &$offset) : int{
		$raw = self::readUnsignedVarInt($buffer, $offset);
		$temp = ((($raw << 63) >> 63) ^ $raw) >> 1;
		return $temp ^ ($raw & (1 << 63));
	}

	/**
	 * Reads a 32-bit variable-length unsigned integer.
	 *
	 * @param string $buffer
	 * @param int    $offset reference parameter
	 *
	 * @return int
	 *
	 * @throws BinaryDataException if the var-int did not end after 5 bytes or there were not enough bytes
	 */
	public static function readUnsignedVarInt(string $buffer, int &$offset) : int{
		$value = 0;
		for($i = 0; $i <= 28; $i += 7){
			if(!isset($buffer[$offset])){
				throw new BinaryDataException("No bytes left in buffer");
			}
			$b = ord($buffer[$offset++]);
			$value |= (($b & 0x7f) << $i);

			if(($b & 0x80) === 0){
				return $value;
			}
		}

		throw new BinaryDataException("VarInt did not terminate after 5 bytes!");
	}

	/**
	 * Writes a 32-bit integer as a zigzag-encoded variable-length integer.
	 *
	 * @param int $v
	 *
	 * @return string
	 */
	public static function writeVarInt(int $v) : string{
		$v = ($v << 32 >> 32);
		return self::writeUnsignedVarInt(($v << 1) ^ ($v >> 31));
	}

	/**
	 * Writes a 32-bit unsigned integer as a variable-length integer.
	 *
	 * @param int $value
	 *
	 * @return string up to 5 bytes
	 */
	public static function writeUnsignedVarInt(int $value) : string{
		$buf = "";
		$value &= 0xffffffff;
		for($i = 0; $i < 5; ++$i){
			if(($value >> 7) !== 0){
				$buf .= chr($value | 0x80);
			}else{
				$buf .= chr($value & 0x7f);
				return $buf;
			}

			$value = (($value >> 7) & (PHP_INT_MAX >> 6)); //PHP really needs a logical right-shift operator
		}

		throw new InvalidArgumentException("Value too large to be encoded as a VarInt");
	}


	/**
	 * Reads a 64-bit zigzag-encoded variable-length integer.
	 *
	 * @param string $buffer
	 * @param int    $offset reference parameter
	 *
	 * @return int
	 */
	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 a 64-bit unsigned variable-length integer.
	 *
	 * @param string $buffer
	 * @param int    $offset reference parameter
	 *
	 * @return int
	 *
	 * @throws BinaryDataException if the var-int did not end after 10 bytes or there were not enough bytes
	 */
	public static function readUnsignedVarLong(string $buffer, int &$offset) : int{
		$value = 0;
		for($i = 0; $i <= 63; $i += 7){
			if(!isset($buffer[$offset])){
				throw new BinaryDataException("No bytes left in buffer");
			}
			$b = ord($buffer[$offset++]);
			$value |= (($b & 0x7f) << $i);

			if(($b & 0x80) === 0){
				return $value;
			}
		}

		throw new BinaryDataException("VarLong did not terminate after 10 bytes!");
	}

	/**
	 * Writes a 64-bit integer as a zigzag-encoded variable-length long.
	 *
	 * @param int $v
	 *
	 * @return string
	 */
	public static function writeVarLong(int $v) : string{
		return self::writeUnsignedVarLong(($v << 1) ^ ($v >> 63));
	}

	/**
	 * Writes a 64-bit unsigned integer as a variable-length long.
	 *
	 * @param int $value
	 *
	 * @return string
	 */
	public static function writeUnsignedVarLong(int $value) : string{
		$buf = "";
		for($i = 0; $i < 10; ++$i){
			if(($value >> 7) !== 0){
				$buf .= chr($value | 0x80); //Let chr() take the last byte of this, it's faster than adding another & 0x7f.
			}else{
				$buf .= chr($value & 0x7f);
				return $buf;
			}

			$value = (($value >> 7) & (PHP_INT_MAX >> 6)); //PHP really needs a logical right-shift operator
		}

		throw new InvalidArgumentException("Value too large to be encoded as a VarLong");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt;

use function count;
use function strlen;

use pocketmine\utils\Binary;

class NetworkLittleEndianNBTStream extends LittleEndianNBTStream{

	public function getInt() : int{
		return Binary::readVarInt($this->buffer, $this->offset);
	}

	public function putInt(int $v) : void{
		($this->buffer .= Binary::writeVarInt($v));
	}

	public function getLong() : int{
		return Binary::readVarLong($this->buffer, $this->offset);
	}

	public function putLong(int $v) : void{
		($this->buffer .= Binary::writeVarLong($v));
	}

	public function getString() : string{
		return $this->get(self::checkReadStringLength(Binary::readUnsignedVarInt($this->buffer, $this->offset)));
	}

	public function putString(string $v) : void{
		($this->buffer .= Binary::writeUnsignedVarInt(self::checkWriteStringLength(strlen($v))) . $v);
	}

	public function getIntArray() : array{
		$len = $this->getInt(); //varint
		$ret = [];
		for($i = 0; $i < $len; ++$i){
			$ret[] = $this->getInt(); //varint
		}

		return $ret;
	}

	public function putIntArray(array $array) : void{
		$this->putInt(count($array)); //varint
		foreach($array as $v){
			$this->putInt($v); //varint
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol;

use pocketmine\utils\Binary;


use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use function assert;
use function get_class;
use function strlen;
use function zlib_decode;
use function zlib_encode;

class BatchPacket extends DataPacket{
	public const NETWORK_ID = 0xfe;

	/** @var string */
	public $payload = "";
	/** @var int */
	protected $compressionLevel = 7;

	public function canBeBatched() : bool{
		return false;
	}

	public function canBeSentBeforeLogin() : bool{
		return true;
	}

	protected function decodeHeader(){
		$pid = (\ord($this->get(1)));
		assert($pid === static::NETWORK_ID);
	}

	protected function decodePayload(){
		$data = $this->getRemaining();
		try{
			$this->payload = zlib_decode($data, 1024 * 1024 * 2); //Max 2MB
		}catch(\ErrorException $e){ //zlib decode error
			$this->payload = "";
		}
	}

	protected function encodeHeader(){
		($this->buffer .= \chr(static::NETWORK_ID));
	}

	protected function encodePayload(){
		($this->buffer .= zlib_encode($this->payload, ZLIB_ENCODING_DEFLATE, $this->compressionLevel));
	}

	/**
	 * @return void
	 */
	public function addPacket(DataPacket $packet){
		if(!$packet->canBeBatched()){
			throw new \InvalidArgumentException(get_class($packet) . " cannot be put inside a BatchPacket");
		}
		if(!$packet->isEncoded){
			$packet->encode();
		}

		$this->payload .= Binary::writeUnsignedVarInt(strlen($packet->buffer)) . $packet->buffer;
	}

	/**
	 * @return \Generator
	 * @phpstan-return \Generator<int, string, void, void>
	 */
	public function getPackets(){
		$stream = new NetworkBinaryStream($this->payload);
		$count = 0;
		while(!$stream->feof()){
			if($count++ >= 500){
				throw new \UnexpectedValueException("Too many packets in a single batch");
			}
			yield $stream->getString();
		}
	}

	public function getCompressionLevel() : int{
		return $this->compressionLevel;
	}

	/**
	 * @return void
	 */
	public function setCompressionLevel(int $level){
		$this->compressionLevel = $level;
	}

	public function handle(NetworkSession $session) : bool{
		if($this->payload === ""){
			return false;
		}

		foreach($this->getPackets() as $buf){
			$pk = PacketPool::getPacket($buf);

			if(!$pk->canBeBatched()){
				throw new \UnexpectedValueException("Received invalid " . get_class($pk) . " inside BatchPacket");
			}

			$session->handleDataPacket($pk);
		}

		return true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\resourcepacks;

use pocketmine\utils\Config;
use function array_keys;
use function copy;
use function count;
use function file_exists;
use function gettype;
use function is_array;
use function is_dir;
use function mkdir;
use function strtolower;
use const DIRECTORY_SEPARATOR;

class ResourcePackManager{

	/** @var string */
	private $path;

	/** @var bool */
	private $serverForceResources = false;

	/** @var ResourcePack[] */
	private $resourcePacks = [];

	/** @var ResourcePack[] */
	private $uuidList = [];

	/**
	 * @param string  $path Path to resource-packs directory.
	 */
	public function __construct(string $path, \Logger $logger){
		$this->path = $path;

		if(!file_exists($this->path)){
			$logger->debug("Resource packs path $path does not exist, creating directory");
			mkdir($this->path);
		}elseif(!is_dir($this->path)){
			throw new \InvalidArgumentException("Resource packs path $path exists and is not a directory");
		}

		if(!file_exists($this->path . "resource_packs.yml")){
			copy(\pocketmine\RESOURCE_PATH . "resource_packs.yml", $this->path . "resource_packs.yml");
		}

		$resourcePacksConfig = new Config($this->path . "resource_packs.yml", Config::YAML, []);

		$this->serverForceResources = (bool) $resourcePacksConfig->get("force_resources", false);

		$logger->info("Loading resource packs...");

		$resourceStack = $resourcePacksConfig->get("resource_stack", []);
		if(!is_array($resourceStack)){
			throw new \InvalidArgumentException("\"resource_stack\" key should contain a list of pack names");
		}

		foreach($resourceStack as $pos => $pack){
			try{
				$pack = (string) $pack;
			}catch(\ErrorException $e){
				$logger->critical("Found invalid entry in resource pack list at offset $pos of type " . gettype($pack));
				continue;
			}
			try{
				/** @var string $pack */
				$packPath = $this->path . DIRECTORY_SEPARATOR . $pack;
				if(!file_exists($packPath)){
					throw new ResourcePackException("File or directory not found");
				}
				if(is_dir($packPath)){
					throw new ResourcePackException("Directory resource packs are unsupported");
				}

				$newPack = null;
				//Detect the type of resource pack.
				$info = new \SplFileInfo($packPath);
				switch($info->getExtension()){
					case "zip":
					case "mcpack":
						$newPack = new ZippedResourcePack($packPath);
						break;
				}

				if($newPack instanceof ResourcePack){
					$this->resourcePacks[] = $newPack;
					$this->uuidList[strtolower($newPack->getPackId())] = $newPack;
				}else{
					throw new ResourcePackException("Format not recognized");
				}
			}catch(ResourcePackException $e){
				$logger->critical("Could not load resource pack \"$pack\": " . $e->getMessage());
			}
		}

		$logger->debug("Successfully loaded " . count($this->resourcePacks) . " resource packs");
	}

	/**
	 * Returns the directory which resource packs are loaded from.
	 */
	public function getPath() : string{
		return $this->path;
	}

	/**
	 * Returns whether players must accept resource packs in order to join.
	 */
	public function resourcePacksRequired() : bool{
		return $this->serverForceResources;
	}

	/**
	 * Returns an array of resource packs in use, sorted in order of priority.
	 * @return ResourcePack[]
	 */
	public function getResourceStack() : array{
		return $this->resourcePacks;
	}

	/**
	 * Returns the resource pack matching the specified UUID string, or null if the ID was not recognized.
	 *
	 * @return ResourcePack|null
	 */
	public function getPackById(string $id){
		return $this->uuidList[strtolower($id)] ?? null;
	}

	/**
	 * Returns an array of pack IDs for packs currently in use.
	 * @return string[]
	 */
	public function getPackIdList() : array{
		return array_keys($this->uuidList);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\plugin;

use pocketmine\command\PluginCommand;
use pocketmine\command\SimpleCommandMap;
use pocketmine\event\Event;
use pocketmine\event\EventPriority;
use pocketmine\event\HandlerList;
use pocketmine\event\Listener;
use pocketmine\event\plugin\PluginDisableEvent;
use pocketmine\event\plugin\PluginEnableEvent;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\permission\Permissible;
use pocketmine\permission\Permission;
use pocketmine\permission\PermissionManager;
use pocketmine\Server;
use pocketmine\timings\TimingsHandler;
use pocketmine\utils\Utils;
use function array_intersect;
use function array_map;
use function array_merge;
use function array_pad;
use function class_exists;
use function count;
use function dirname;
use function explode;
use function file_exists;
use function get_class;
use function gettype;
use function implode;
use function is_a;
use function is_array;
use function is_bool;
use function is_dir;
use function is_string;
use function is_subclass_of;
use function iterator_to_array;
use function mkdir;
use function shuffle;
use function stripos;
use function strpos;
use function strtolower;
use function strtoupper;
use const DIRECTORY_SEPARATOR;

/**
 * Manages all the plugins
 */
class PluginManager{

	/** @var Server */
	private $server;

	/** @var SimpleCommandMap */
	private $commandMap;

	/** @var Plugin[] */
	protected $plugins = [];

	/** @var Plugin[] */
	protected $enabledPlugins = [];

	/**
	 * @var PluginLoader[]
	 * @phpstan-var array<class-string<PluginLoader>, PluginLoader>
	 */
	protected $fileAssociations = [];

	/** @var string|null */
	private $pluginDataDirectory;

	public function __construct(Server $server, SimpleCommandMap $commandMap, ?string $pluginDataDirectory){
		$this->server = $server;
		$this->commandMap = $commandMap;
		$this->pluginDataDirectory = $pluginDataDirectory;
		if($this->pluginDataDirectory !== null){
			if(!file_exists($this->pluginDataDirectory)){
				@mkdir($this->pluginDataDirectory, 0777, true);
			}elseif(!is_dir($this->pluginDataDirectory)){
				throw new \RuntimeException("Plugin data path $this->pluginDataDirectory exists and is not a directory");
			}
		}
	}

	/**
	 * @return null|Plugin
	 */
	public function getPlugin(string $name){
		if(isset($this->plugins[$name])){
			return $this->plugins[$name];
		}

		return null;
	}

	public function registerInterface(PluginLoader $loader) : void{
		$this->fileAssociations[get_class($loader)] = $loader;
	}

	/**
	 * @return Plugin[]
	 */
	public function getPlugins() : array{
		return $this->plugins;
	}

	private function getDataDirectory(string $pluginPath, string $pluginName) : string{
		if($this->pluginDataDirectory !== null){
			return $this->pluginDataDirectory . $pluginName;
		}
		return dirname($pluginPath) . DIRECTORY_SEPARATOR . $pluginName;
	}

	/**
	 * @param PluginLoader[] $loaders
	 */
	public function loadPlugin(string $path, array $loaders = null) : ?Plugin{
		foreach($loaders ?? $this->fileAssociations as $loader){
			if($loader->canLoadPlugin($path)){
				$description = $loader->getPluginDescription($path);
				if($description instanceof PluginDescription){
					$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.load", [$description->getFullName()]));
					try{
						$description->checkRequiredExtensions();
					}catch(PluginException $ex){
						$this->server->getLogger()->error($ex->getMessage());
						return null;
					}

					$dataFolder = $this->getDataDirectory($path, $description->getName());
					if(file_exists($dataFolder) and !is_dir($dataFolder)){
						$this->server->getLogger()->error("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory");
						return null;
					}
					if(!file_exists($dataFolder)){
						mkdir($dataFolder, 0777, true);
					}

					$prefixed = $loader->getAccessProtocol() . $path;
					$loader->loadPlugin($prefixed);

					$mainClass = $description->getMain();
					if(!class_exists($mainClass, true)){
						$this->server->getLogger()->error("Main class for plugin " . $description->getName() . " not found");
						return null;
					}
					if(!is_a($mainClass, Plugin::class, true)){
						$this->server->getLogger()->error("Main class for plugin " . $description->getName() . " is not an instance of " . Plugin::class);
						return null;
					}

					try{
						/**
						 * @var Plugin $plugin
						 * @see Plugin::__construct()
						 */
						$plugin = new $mainClass($loader, $this->server, $description, $dataFolder, $prefixed);
						$plugin->onLoad();
						$this->plugins[$plugin->getDescription()->getName()] = $plugin;

						$pluginCommands = $this->parseYamlCommands($plugin);

						if(count($pluginCommands) > 0){
							$this->commandMap->registerAll($plugin->getDescription()->getName(), $pluginCommands);
						}

						return $plugin;
					}catch(\Throwable $e){
						$this->server->getLogger()->logException($e);
						return null;
					}
				}
			}
		}

		return null;
	}

	/**
	 * @param string[]|null $newLoaders
	 * @phpstan-param list<class-string<PluginLoader>> $newLoaders
	 *
	 * @return Plugin[]
	 */
	public function loadPlugins(string $directory, array $newLoaders = null){
		if(!is_dir($directory)){
			return [];
		}

		$plugins = [];
		$loadedPlugins = [];
		$dependencies = [];
		$softDependencies = [];
		if(is_array($newLoaders)){
			$loaders = [];
			foreach($newLoaders as $key){
				if(isset($this->fileAssociations[$key])){
					$loaders[$key] = $this->fileAssociations[$key];
				}
			}
		}else{
			$loaders = $this->fileAssociations;
		}

		$files = iterator_to_array(new \FilesystemIterator($directory, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
		shuffle($files); //this prevents plugins implicitly relying on the filesystem name order when they should be using dependency properties
		foreach($loaders as $loader){
			foreach($files as $file){
				if(!$loader->canLoadPlugin($file)){
					continue;
				}
				try{
					$description = $loader->getPluginDescription($file);
					if($description === null){
						continue;
					}

					$name = $description->getName();
					if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){
						$this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.restrictedName"]));
						continue;
					}elseif(strpos($name, " ") !== false){
						$this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.plugin.spacesDiscouraged", [$name]));
					}

					if(isset($plugins[$name]) or $this->getPlugin($name) instanceof Plugin){
						$this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.duplicateError", [$name]));
						continue;
					}

					if(!$this->isCompatibleApi(...$description->getCompatibleApis())){
						$this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [
							$name,
							$this->server->getLanguage()->translateString("%pocketmine.plugin.incompatibleAPI", [implode(", ", $description->getCompatibleApis())])
						]));
						continue;
					}

					if(count($pluginMcpeProtocols = $description->getCompatibleMcpeProtocols()) > 0){
						$serverMcpeProtocols = [ProtocolInfo::CURRENT_PROTOCOL];
						if(count(array_intersect($pluginMcpeProtocols, $serverMcpeProtocols)) === 0){
							$this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [
								$name,
								$this->server->getLanguage()->translateString("%pocketmine.plugin.incompatibleProtocol", [implode(", ", $pluginMcpeProtocols)])
							]));
							continue;
						}
					}

					$plugins[$name] = $file;

					$softDependencies[$name] = array_merge($softDependencies[$name] ?? [], $description->getSoftDepend());
					$dependencies[$name] = $description->getDepend();

					foreach($description->getLoadBefore() as $before){
						if(isset($softDependencies[$before])){
							$softDependencies[$before][] = $name;
						}else{
							$softDependencies[$before] = [$name];
						}
					}
				}catch(\Throwable $e){
					$this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.fileError", [$file, $directory, $e->getMessage()]));
					$this->server->getLogger()->logException($e);
				}
			}
		}

		while(count($plugins) > 0){
			$loadedThisLoop = 0;
			foreach($plugins as $name => $file){
				if(isset($dependencies[$name])){
					foreach($dependencies[$name] as $key => $dependency){
						if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){
							unset($dependencies[$name][$key]);
						}elseif(!isset($plugins[$dependency])){
							$this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [
								$name,
								$this->server->getLanguage()->translateString("%pocketmine.plugin.unknownDependency", [$dependency])
							]));
							unset($plugins[$name]);
							continue 2;
						}
					}

					if(count($dependencies[$name]) === 0){
						unset($dependencies[$name]);
					}
				}

				if(isset($softDependencies[$name])){
					foreach($softDependencies[$name] as $key => $dependency){
						if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){
							$this->server->getLogger()->debug("Successfully resolved soft dependency \"$dependency\" for plugin \"$name\"");
							unset($softDependencies[$name][$key]);
						}elseif(!isset($plugins[$dependency])){
							//this dependency is never going to be resolved, so don't bother trying
							$this->server->getLogger()->debug("Skipping resolution of missing soft dependency \"$dependency\" for plugin \"$name\"");
							unset($softDependencies[$name][$key]);
						}else{
							$this->server->getLogger()->debug("Deferring resolution of soft dependency \"$dependency\" for plugin \"$name\" (found but not loaded yet)");
						}
					}

					if(count($softDependencies[$name]) === 0){
						unset($softDependencies[$name]);
					}
				}

				if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){
					unset($plugins[$name]);
					$loadedThisLoop++;
					if(($plugin = $this->loadPlugin($file, $loaders)) instanceof Plugin){
						$loadedPlugins[$name] = $plugin;
					}else{
						$this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.genericLoadError", [$name]));
					}
				}
			}

			if($loadedThisLoop === 0){
				//No plugins loaded :(
				foreach($plugins as $name => $file){
					$this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.circularDependency"]));
				}
				$plugins = [];
			}
		}

		return $loadedPlugins;
	}

	/**
	 * Returns whether a specified API version string is considered compatible with the server's API version.
	 *
	 * @param string ...$versions
	 */
	public function isCompatibleApi(string ...$versions) : bool{
		$serverString = $this->server->getApiVersion();
		$serverApi = array_pad(explode("-", $serverString, 2), 2, "");
		$serverNumbers = array_map("\intval", explode(".", $serverApi[0]));

		foreach($versions as $version){
			//Format: majorVersion.minorVersion.patch (3.0.0)
			//    or: majorVersion.minorVersion.patch-devBuild (3.0.0-alpha1)
			if($version !== $serverString){
				$pluginApi = array_pad(explode("-", $version, 2), 2, ""); //0 = version, 1 = suffix (optional)

				if(strtoupper($pluginApi[1]) !== strtoupper($serverApi[1])){ //Different release phase (alpha vs. beta) or phase build (alpha.1 vs alpha.2)
					continue;
				}

				$pluginNumbers = array_map("\intval", array_pad(explode(".", $pluginApi[0]), 3, "0")); //plugins might specify API like "3.0" or "3"

				if($pluginNumbers[0] !== $serverNumbers[0]){ //Completely different API version
					continue;
				}

				if($pluginNumbers[1] > $serverNumbers[1]){ //If the plugin requires new API features, being backwards compatible
					continue;
				}

				if($pluginNumbers[1] === $serverNumbers[1] and $pluginNumbers[2] > $serverNumbers[2]){ //If the plugin requires bug fixes in patches, being backwards compatible
					continue;
				}
			}

			return true;
		}

		return false;
	}

	/**
	 * @deprecated
	 * @see PermissionManager::getPermission()
	 *
	 * @return null|Permission
	 */
	public function getPermission(string $name){
		return PermissionManager::getInstance()->getPermission($name);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::addPermission()
	 */
	public function addPermission(Permission $permission) : bool{
		return PermissionManager::getInstance()->addPermission($permission);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::removePermission()
	 *
	 * @param string|Permission $permission
	 *
	 * @return void
	 */
	public function removePermission($permission){
		PermissionManager::getInstance()->removePermission($permission);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::getDefaultPermissions()
	 *
	 * @return Permission[]
	 */
	public function getDefaultPermissions(bool $op) : array{
		return PermissionManager::getInstance()->getDefaultPermissions($op);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::recalculatePermissionDefaults()
	 *
	 * @return void
	 */
	public function recalculatePermissionDefaults(Permission $permission){
		PermissionManager::getInstance()->recalculatePermissionDefaults($permission);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::subscribeToPermission()
	 *
	 * @return void
	 */
	public function subscribeToPermission(string $permission, Permissible $permissible){
		PermissionManager::getInstance()->subscribeToPermission($permission, $permissible);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::unsubscribeFromPermission()
	 *
	 * @return void
	 */
	public function unsubscribeFromPermission(string $permission, Permissible $permissible){
		PermissionManager::getInstance()->unsubscribeFromPermission($permission, $permissible);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::unsubscribeFromAllPermissions()
	 */
	public function unsubscribeFromAllPermissions(Permissible $permissible) : void{
		PermissionManager::getInstance()->unsubscribeFromAllPermissions($permissible);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::getPermissionSubscriptions()
	 *
	 * @return array|Permissible[]
	 */
	public function getPermissionSubscriptions(string $permission) : array{
		return PermissionManager::getInstance()->getPermissionSubscriptions($permission);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::subscribeToDefaultPerms()
	 *
	 * @return void
	 */
	public function subscribeToDefaultPerms(bool $op, Permissible $permissible){
		PermissionManager::getInstance()->subscribeToDefaultPerms($op, $permissible);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::unsubscribeFromDefaultPerms()
	 *
	 * @return void
	 */
	public function unsubscribeFromDefaultPerms(bool $op, Permissible $permissible){
		PermissionManager::getInstance()->unsubscribeFromDefaultPerms($op, $permissible);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::getDefaultPermSubscriptions()
	 *
	 * @return Permissible[]
	 */
	public function getDefaultPermSubscriptions(bool $op) : array{
		return PermissionManager::getInstance()->getDefaultPermSubscriptions($op);
	}

	/**
	 * @deprecated
	 * @see PermissionManager::getPermissions()
	 *
	 * @return Permission[]
	 */
	public function getPermissions() : array{
		return PermissionManager::getInstance()->getPermissions();
	}

	public function isPluginEnabled(Plugin $plugin) : bool{
		return isset($this->plugins[$plugin->getDescription()->getName()]) and $plugin->isEnabled();
	}

	/**
	 * @return void
	 */
	public function enablePlugin(Plugin $plugin){
		if(!$plugin->isEnabled()){
			try{
				$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.enable", [$plugin->getDescription()->getFullName()]));

				$permManager = PermissionManager::getInstance();
				foreach($plugin->getDescription()->getPermissions() as $perm){
					$permManager->addPermission($perm);
				}
				$plugin->getScheduler()->setEnabled(true);
				$plugin->setEnabled(true);

				$this->enabledPlugins[$plugin->getDescription()->getName()] = $plugin;

				(new PluginEnableEvent($plugin))->call();
			}catch(\Throwable $e){
				$this->server->getLogger()->logException($e);
				$this->disablePlugin($plugin);
			}
		}
	}

	/**
	 * @return PluginCommand[]
	 */
	protected function parseYamlCommands(Plugin $plugin) : array{
		$pluginCmds = [];

		foreach($plugin->getDescription()->getCommands() as $key => $data){
			if(strpos($key, ":") !== false){
				$this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.commandError", [$key, $plugin->getDescription()->getFullName()]));
				continue;
			}
			if(is_array($data)){
				$newCmd = new PluginCommand($key, $plugin);
				if(isset($data["description"])){
					$newCmd->setDescription($data["description"]);
				}

				if(isset($data["usage"])){
					$newCmd->setUsage($data["usage"]);
				}

				if(isset($data["aliases"]) and is_array($data["aliases"])){
					$aliasList = [];
					foreach($data["aliases"] as $alias){
						if(strpos($alias, ":") !== false){
							$this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.aliasError", [$alias, $plugin->getDescription()->getFullName()]));
							continue;
						}
						$aliasList[] = $alias;
					}

					$newCmd->setAliases($aliasList);
				}

				if(isset($data["permission"])){
					if(is_bool($data["permission"])){
						$newCmd->setPermission($data["permission"] ? "true" : "false");
					}elseif(is_string($data["permission"])){
						$newCmd->setPermission($data["permission"]);
					}else{
						throw new \InvalidArgumentException("Permission must be a string or boolean, " . gettype($data["permission"]) . " given");
					}
				}

				if(isset($data["permission-message"])){
					$newCmd->setPermissionMessage($data["permission-message"]);
				}

				$pluginCmds[] = $newCmd;
			}
		}

		return $pluginCmds;
	}

	/**
	 * @return void
	 */
	public function disablePlugins(){
		foreach($this->getPlugins() as $plugin){
			$this->disablePlugin($plugin);
		}
	}

	/**
	 * @return void
	 */
	public function disablePlugin(Plugin $plugin){
		if($plugin->isEnabled()){
			$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.disable", [$plugin->getDescription()->getFullName()]));
			(new PluginDisableEvent($plugin))->call();

			unset($this->enabledPlugins[$plugin->getDescription()->getName()]);

			try{
				$plugin->setEnabled(false);
			}catch(\Throwable $e){
				$this->server->getLogger()->logException($e);
			}
			$plugin->getScheduler()->shutdown();
			HandlerList::unregisterAll($plugin);
			$permManager = PermissionManager::getInstance();
			foreach($plugin->getDescription()->getPermissions() as $perm){
				$permManager->removePermission($perm);
			}
		}
	}

	public function tickSchedulers(int $currentTick) : void{
		foreach($this->enabledPlugins as $p){
			$p->getScheduler()->mainThreadHeartbeat($currentTick);
		}
	}

	/**
	 * @return void
	 */
	public function clearPlugins(){
		$this->disablePlugins();
		$this->plugins = [];
		$this->enabledPlugins = [];
		$this->fileAssociations = [];
	}

	/**
	 * Calls an event
	 *
	 * @deprecated
	 * @see Event::call()
	 *
	 * @return void
	 */
	public function callEvent(Event $event){
		$event->call();
	}

	/**
	 * Registers all the events in the given Listener class
	 *
	 * @throws PluginException
	 */
	public function registerEvents(Listener $listener, Plugin $plugin) : void{
		if(!$plugin->isEnabled()){
			throw new PluginException("Plugin attempted to register " . get_class($listener) . " while not enabled");
		}

		$reflection = new \ReflectionClass(get_class($listener));
		foreach($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method){
			if(!$method->isStatic() and $method->getDeclaringClass()->implementsInterface(Listener::class)){
				$tags = Utils::parseDocComment((string) $method->getDocComment());
				if(isset($tags["notHandler"])){
					continue;
				}

				$parameters = $method->getParameters();
				if(count($parameters) !== 1){
					continue;
				}

				$handlerClosure = $method->getClosure($listener);

				try{
					$eventClass = $parameters[0]->getClass();
				}catch(\ReflectionException $e){ //class doesn't exist
					if(isset($tags["softDepend"]) && !isset($this->plugins[$tags["softDepend"]])){
						$this->server->getLogger()->debug("Not registering @softDepend listener " . Utils::getNiceClosureName($handlerClosure) . "() because plugin \"" . $tags["softDepend"] . "\" not found");
						continue;
					}

					throw $e;
				}
				if($eventClass === null or !$eventClass->isSubclassOf(Event::class)){
					continue;
				}

				try{
					$priority = isset($tags["priority"]) ? EventPriority::fromString($tags["priority"]) : EventPriority::NORMAL;
				}catch(\InvalidArgumentException $e){
					throw new PluginException("Event handler " . Utils::getNiceClosureName($handlerClosure) . "() declares invalid/unknown priority \"" . $tags["priority"] . "\"");
				}

				$ignoreCancelled = false;
				if(isset($tags["ignoreCancelled"])){
					switch(strtolower($tags["ignoreCancelled"])){
						case "true":
						case "":
							$ignoreCancelled = true;
							break;
						case "false":
							$ignoreCancelled = false;
							break;
						default:
							throw new PluginException("Event handler " . Utils::getNiceClosureName($handlerClosure) . "() declares invalid @ignoreCancelled value \"" . $tags["ignoreCancelled"] . "\"");
					}
				}

				$this->registerEvent($eventClass->getName(), $listener, $priority, new MethodEventExecutor($method->getName()), $plugin, $ignoreCancelled);
			}
		}
	}

	/**
	 * @param string $event Class name that extends Event
	 * @phpstan-param class-string<Event> $event
	 *
	 * @throws PluginException
	 */
	public function registerEvent(string $event, Listener $listener, int $priority, EventExecutor $executor, Plugin $plugin, bool $ignoreCancelled = false) : void{
		if(!is_subclass_of($event, Event::class)){
			throw new PluginException($event . " is not an Event");
		}

		$tags = Utils::parseDocComment((string) (new \ReflectionClass($event))->getDocComment());
		if(isset($tags["deprecated"]) and $this->server->getProperty("settings.deprecated-verbose", true)){
			$this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.plugin.deprecatedEvent", [
				$plugin->getName(),
				$event,
				get_class($listener) . "->" . ($executor instanceof MethodEventExecutor ? $executor->getMethod() : "<unknown>")
			]));
		}

		if(!$plugin->isEnabled()){
			throw new PluginException("Plugin attempted to register " . $event . " while not enabled");
		}

		$timings = new TimingsHandler("Plugin: " . $plugin->getDescription()->getFullName() . " Event: " . get_class($listener) . "::" . ($executor instanceof MethodEventExecutor ? $executor->getMethod() : "???") . "(" . (new \ReflectionClass($event))->getShortName() . ")");

		$this->getEventListeners($event)->register(new RegisteredListener($listener, $executor, $priority, $plugin, $ignoreCancelled, $timings));
	}

	private function getEventListeners(string $event) : HandlerList{
		$list = HandlerList::getHandlerListFor($event);
		if($list === null){
			throw new PluginException("Abstract events not declaring @allowHandle cannot be handled (tried to register listener for $event)");
		}
		return $list;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\plugin;

use function is_file;
use function strlen;
use function substr;

/**
 * Handles different types of plugins
 */
class PharPluginLoader implements PluginLoader{

	/** @var \ClassLoader */
	private $loader;

	public function __construct(\ClassLoader $loader){
		$this->loader = $loader;
	}

	public function canLoadPlugin(string $path) : bool{
		$ext = ".phar";
		return is_file($path) and substr($path, -strlen($ext)) === $ext;
	}

	/**
	 * Loads the plugin contained in $file
	 */
	public function loadPlugin(string $file) : void{
		$this->loader->addPath("$file/src");
	}

	/**
	 * Gets the PluginDescription from the file
	 */
	public function getPluginDescription(string $file) : ?PluginDescription{
		$phar = new \Phar($file);
		if(isset($phar["plugin.yml"])){
			return new PluginDescription($phar["plugin.yml"]->getContent());
		}

		return null;
	}

	public function getAccessProtocol() : string{
		return "phar://";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\plugin;

/**
 * Handles different types of plugins
 */
interface PluginLoader{

	/**
	 * Returns whether this PluginLoader can load the plugin in the given path.
	 */
	public function canLoadPlugin(string $path) : bool;

	/**
	 * Loads the plugin contained in $file
	 */
	public function loadPlugin(string $file) : void;

	/**
	 * Gets the PluginDescription from the file
	 */
	public function getPluginDescription(string $file) : ?PluginDescription;

	/**
	 * Returns the protocol prefix used to access files in this plugin, e.g. file://, phar://
	 */
	public function getAccessProtocol() : string;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\plugin;

use function file;
use function is_file;
use function preg_match;
use function strlen;
use function strpos;
use function substr;
use function trim;
use const FILE_IGNORE_NEW_LINES;
use const FILE_SKIP_EMPTY_LINES;

/**
 * Simple script loader, not for plugin development
 * For an example see https://gist.github.com/shoghicp/516105d470cf7d140757
 */
class ScriptPluginLoader implements PluginLoader{

	public function canLoadPlugin(string $path) : bool{
		$ext = ".php";
		return is_file($path) and substr($path, -strlen($ext)) === $ext;
	}

	/**
	 * Loads the plugin contained in $file
	 */
	public function loadPlugin(string $file) : void{
		include_once $file;
	}

	/**
	 * Gets the PluginDescription from the file
	 */
	public function getPluginDescription(string $file) : ?PluginDescription{
		$content = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

		$data = [];

		$insideHeader = false;
		foreach($content as $line){
			if(!$insideHeader and strpos($line, "/**") !== false){
				$insideHeader = true;
			}

			if(preg_match("/^[ \t]+\\*[ \t]+@([a-zA-Z]+)([ \t]+(.*))?$/", $line, $matches) > 0){
				$key = $matches[1];
				$content = trim($matches[3] ?? "");

				if($key === "notscript"){
					return null;
				}

				$data[$key] = $content;
			}

			if($insideHeader and strpos($line, "*/") !== false){
				break;
			}
		}
		if($insideHeader){
			return new PluginDescription($data);
		}

		return null;
	}

	public function getAccessProtocol() : string{
		return "";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\server;

use pocketmine\Player;
use pocketmine\plugin\Plugin;
use pocketmine\Server;
use pocketmine\utils\Binary;
use function chr;
use function count;
use function str_replace;
use function substr;

class QueryRegenerateEvent extends ServerEvent{
	public const GAME_ID = "MINECRAFTPE";

	/** @var string */
	private $serverName;
	/** @var bool */
	private $listPlugins;
	/** @var Plugin[] */
	private $plugins;
	/** @var Player[] */
	private $players;

	/** @var string */
	private $gametype;
	/** @var string */
	private $version;
	/** @var string */
	private $server_engine;
	/** @var string */
	private $map;
	/** @var int */
	private $numPlayers;
	/** @var int */
	private $maxPlayers;
	/** @var string */
	private $whitelist;
	/** @var int */
	private $port;
	/** @var string */
	private $ip;

	/**
	 * @var string[]
	 * @phpstan-var array<string, string>
	 */
	private $extraData = [];

	/** @var string|null */
	private $longQueryCache = null;
	/** @var string|null */
	private $shortQueryCache = null;

	public function __construct(Server $server){
		$this->serverName = $server->getMotd();
		$this->listPlugins = $server->getProperty("settings.query-plugins", true);
		$this->plugins = $server->getPluginManager()->getPlugins();
		$this->players = [];
		foreach($server->getOnlinePlayers() as $player){
			if($player->isOnline()){
				$this->players[] = $player;
			}
		}

		$this->gametype = ($server->getGamemode() & 0x01) === 0 ? "SMP" : "CMP";
		$this->version = $server->getVersion();
		$this->server_engine = $server->getName() . " " . $server->getPocketMineVersion();
		$this->map = $server->getDefaultLevel() === null ? "unknown" : $server->getDefaultLevel()->getName();
		$this->numPlayers = count($this->players);
		$this->maxPlayers = $server->getMaxPlayers();
		$this->whitelist = $server->hasWhitelist() ? "on" : "off";
		$this->port = $server->getPort();
		$this->ip = $server->getIp();

	}

	/**
	 * @deprecated
	 */
	public function getTimeout() : int{
		return 0;
	}

	/**
	 * @deprecated
	 */
	public function setTimeout(int $timeout) : void{

	}

	private function destroyCache() : void{
		$this->longQueryCache = null;
		$this->shortQueryCache = null;
	}

	public function getServerName() : string{
		return $this->serverName;
	}

	public function setServerName(string $serverName) : void{
		$this->serverName = $serverName;
		$this->destroyCache();
	}

	public function canListPlugins() : bool{
		return $this->listPlugins;
	}

	public function setListPlugins(bool $value) : void{
		$this->listPlugins = $value;
		$this->destroyCache();
	}

	/**
	 * @return Plugin[]
	 */
	public function getPlugins() : array{
		return $this->plugins;
	}

	/**
	 * @param Plugin[] $plugins
	 */
	public function setPlugins(array $plugins) : void{
		$this->plugins = $plugins;
		$this->destroyCache();
	}

	/**
	 * @return Player[]
	 */
	public function getPlayerList() : array{
		return $this->players;
	}

	/**
	 * @param Player[] $players
	 */
	public function setPlayerList(array $players) : void{
		$this->players = $players;
		$this->destroyCache();
	}

	public function getPlayerCount() : int{
		return $this->numPlayers;
	}

	public function setPlayerCount(int $count) : void{
		$this->numPlayers = $count;
		$this->destroyCache();
	}

	public function getMaxPlayerCount() : int{
		return $this->maxPlayers;
	}

	public function setMaxPlayerCount(int $count) : void{
		$this->maxPlayers = $count;
		$this->destroyCache();
	}

	public function getWorld() : string{
		return $this->map;
	}

	public function setWorld(string $world) : void{
		$this->map = $world;
		$this->destroyCache();
	}

	/**
	 * Returns the extra Query data in key => value form
	 *
	 * @return string[]
	 * @phpstan-return array<string, string>
	 */
	public function getExtraData() : array{
		return $this->extraData;
	}

	/**
	 * @param string[] $extraData
	 * @phpstan-param array<string, string> $extraData
	 */
	public function setExtraData(array $extraData) : void{
		$this->extraData = $extraData;
		$this->destroyCache();
	}

	public function getLongQuery() : string{
		if($this->longQueryCache !== null){
			return $this->longQueryCache;
		}
		$query = "";

		$plist = $this->server_engine;
		if(count($this->plugins) > 0 and $this->listPlugins){
			$plist .= ":";
			foreach($this->plugins as $p){
				$d = $p->getDescription();
				$plist .= " " . str_replace([";", ":", " "], ["", "", "_"], $d->getName()) . " " . str_replace([";", ":", " "], ["", "", "_"], $d->getVersion()) . ";";
			}
			$plist = substr($plist, 0, -1);
		}

		$KVdata = [
			"splitnum" => chr(128),
			"hostname" => $this->serverName,
			"gametype" => $this->gametype,
			"game_id" => self::GAME_ID,
			"version" => $this->version,
			"server_engine" => $this->server_engine,
			"plugins" => $plist,
			"map" => $this->map,
			"numplayers" => $this->numPlayers,
			"maxplayers" => $this->maxPlayers,
			"whitelist" => $this->whitelist,
			"hostip" => $this->ip,
			"hostport" => $this->port
		];

		foreach($KVdata as $key => $value){
			$query .= $key . "\x00" . $value . "\x00";
		}

		foreach($this->extraData as $key => $value){
			$query .= $key . "\x00" . $value . "\x00";
		}

		$query .= "\x00\x01player_\x00\x00";
		foreach($this->players as $player){
			$query .= $player->getName() . "\x00";
		}
		$query .= "\x00";

		return $this->longQueryCache = $query;
	}

	public function getShortQuery() : string{
		return $this->shortQueryCache ?? ($this->shortQueryCache = $this->serverName . "\x00" . $this->gametype . "\x00" . $this->map . "\x00" . $this->numPlayers . "\x00" . $this->maxPlayers . "\x00" . (\pack("v", $this->port)) . $this->ip . "\x00");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Events related to the server core, like networking, stop, console commands
 */
namespace pocketmine\event\server;

use pocketmine\event\Event;

abstract class ServerEvent extends Event{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\updater;

use pocketmine\event\server\UpdateNotifyEvent;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\utils\TextFormat;
use pocketmine\utils\VersionString;
use function date;
use function sprintf;
use function str_repeat;
use function strlen;
use function strtolower;
use function ucfirst;

class AutoUpdater{

	/** @var Server */
	protected $server;
	/** @var string */
	protected $endpoint;
	/**
	 * @var mixed[]|null
	 * @phpstan-var array<string, mixed>|null
	 */
	protected $updateInfo = null;
	/** @var VersionString|null */
	protected $newVersion;

	public function __construct(Server $server, string $endpoint){
		$this->server = $server;
		$this->endpoint = "http://$endpoint/api/";

		if((bool) $server->getProperty("auto-updater.enabled", true)){
			$this->doCheck();
		}
	}

	/**
	 * Callback used at the end of the update checking task
	 *
	 * @param mixed[] $updateInfo
	 * @phpstan-param array<string, mixed> $updateInfo
	 *
	 * @return void
	 */
	public function checkUpdateCallback(array $updateInfo){
		$this->updateInfo = $updateInfo;
		$this->checkUpdate();
		if($this->hasUpdate()){
			(new UpdateNotifyEvent($this))->call();
			if((bool) $this->server->getProperty("auto-updater.on-update.warn-console", true)){
				$this->showConsoleUpdate();
			}
		}else{
			if(!\pocketmine\IS_DEVELOPMENT_BUILD and $this->getChannel() !== "stable"){
				$this->showChannelSuggestionStable();
			}elseif(\pocketmine\IS_DEVELOPMENT_BUILD and $this->getChannel() === "stable"){
				$this->showChannelSuggestionBeta();
			}
		}
	}

	/**
	 * Returns whether there is an update available.
	 */
	public function hasUpdate() : bool{
		return $this->newVersion !== null;
	}

	/**
	 * Posts a warning to the console to tell the user there is an update available
	 *
	 * @return void
	 */
	public function showConsoleUpdate(){
		$messages = [
			"Your version of " . $this->server->getName() . " is out of date. Version " . $this->newVersion->getFullVersion(true) . " was released on " . date("D M j h:i:s Y", $this->updateInfo["date"])
		];
		if($this->updateInfo["details_url"] !== null){
			$messages[] = "Details: " . $this->updateInfo["details_url"];
		}
		$messages[] = "Download: " . $this->updateInfo["download_url"];

		$this->printConsoleMessage($messages, \LogLevel::WARNING);
	}

	/**
	 * Shows a warning to a player to tell them there is an update available
	 *
	 * @return void
	 */
	public function showPlayerUpdate(Player $player){
		$player->sendMessage(TextFormat::DARK_PURPLE . "The version of " . $this->server->getName() . " that this server is running is out of date. Please consider updating to the latest version.");
		$player->sendMessage(TextFormat::DARK_PURPLE . "Check the console for more details.");
	}

	/**
	 * @return void
	 */
	protected function showChannelSuggestionStable(){
		$this->printConsoleMessage([
			"It appears you're running a Stable build, when you've specified that you prefer to run " . ucfirst($this->getChannel()) . " builds.",
			"If you would like to be kept informed about new Stable builds only, it is recommended that you change 'preferred-channel' in your pocketmine.yml to 'stable'."
		]);
	}

	/**
	 * @return void
	 */
	protected function showChannelSuggestionBeta(){
		$this->printConsoleMessage([
			"It appears you're running a Beta build, when you've specified that you prefer to run Stable builds.",
			"If you would like to be kept informed about new Beta or Development builds, it is recommended that you change 'preferred-channel' in your pocketmine.yml to 'beta' or 'development'."
		]);
	}

	/**
	 * @param string[] $lines
	 *
	 * @return void
	 */
	protected function printConsoleMessage(array $lines, string $logLevel = \LogLevel::INFO){
		$logger = $this->server->getLogger();

		$title = $this->server->getName() . ' Auto Updater';
		$logger->log($logLevel, sprintf('----- %s -----', $title));
		foreach($lines as $line){
			$logger->log($logLevel, $line);
		}
		$logger->log($logLevel, sprintf('----- %s -----', str_repeat('-', strlen($title))));
	}

	/**
	 * Returns the last retrieved update data.
	 *
	 * @return mixed[]|null
	 * @phpstan-return array<string, mixed>|null
	 */
	public function getUpdateInfo(){
		return $this->updateInfo;
	}

	/**
	 * Schedules an AsyncTask to check for an update.
	 *
	 * @return void
	 */
	public function doCheck(){
		$this->server->getAsyncPool()->submitTask(new UpdateCheckTask($this->endpoint, $this->getChannel()));
	}

	/**
	 * Checks the update information against the current server version to decide if there's an update
	 *
	 * @return void
	 */
	protected function checkUpdate(){
		if($this->updateInfo === null){
			return;
		}
		$currentVersion = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
		try{
			$newVersion = new VersionString($this->updateInfo["base_version"], $this->updateInfo["is_dev"], $this->updateInfo["build"]);
		}catch(\InvalidArgumentException $e){
			//Invalid version returned from API, assume there's no update
			$this->server->getLogger()->debug("[AutoUpdater] Assuming no update because \"" . $e->getMessage() . "\"");
			return;
		}

		if($currentVersion->compare($newVersion) > 0 and ($currentVersion->getFullVersion() !== $newVersion->getFullVersion() or $currentVersion->getBuild() > 0)){
			$this->newVersion = $newVersion;
		}
	}

	/**
	 * Returns the channel used for update checking (stable, beta, dev)
	 */
	public function getChannel() : string{
		$channel = strtolower($this->server->getProperty("auto-updater.preferred-channel", "stable"));
		if($channel !== "stable" and $channel !== "beta" and $channel !== "alpha" and $channel !== "development"){
			$channel = "stable";
		}

		return $channel;
	}

	/**
	 * Returns the host used for update checks.
	 */
	public function getEndpoint() : string{
		return $this->endpoint;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\updater;

use pocketmine\scheduler\AsyncTask;
use pocketmine\Server;
use pocketmine\utils\Internet;
use function is_array;
use function json_decode;

class UpdateCheckTask extends AsyncTask{

	/** @var string */
	private $endpoint;
	/** @var string */
	private $channel;
	/** @var string */
	private $error = "Unknown error";

	public function __construct(string $endpoint, string $channel){
		$this->endpoint = $endpoint;
		$this->channel = $channel;
	}

	public function onRun(){
		$error = "";
		$response = Internet::getURL($this->endpoint . "?channel=" . $this->channel, 4, [], $error);
		$this->error = $error;

		if($response !== false){
			$response = json_decode($response, true);
			if(is_array($response)){
				if(
					isset($response["base_version"]) and
					isset($response["is_dev"]) and
					isset($response["build"]) and
					isset($response["date"]) and
					isset($response["download_url"])
				){
					$response["details_url"] = $response["details_url"] ?? null;
					$this->setResult($response);
				}elseif(isset($response["error"])){
					$this->error = $response["error"];
				}else{
					$this->error = "Invalid response data";
				}
			}else{
				$this->error = "Invalid response data";
			}
		}
	}

	public function onCompletion(Server $server){
		if($this->error !== ""){
			$server->getLogger()->debug("[AutoUpdater] Async update check failed due to \"$this->error\"");
		}else{
			$updateInfo = $this->getResult();
			if(is_array($updateInfo)){
				$server->getUpdater()->checkUpdateCallback($updateInfo);
			}else{
				$server->getLogger()->debug("[AutoUpdater] Update info error");
			}

		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\scheduler;

use pocketmine\Collectable;
use pocketmine\Server;
use function is_scalar;
use function serialize;
use function unserialize;

/**
 * Class used to run async tasks in other threads.
 *
 * An AsyncTask does not have its own thread. It is queued into an AsyncPool and executed if there is an async worker
 * with no AsyncTask running. Therefore, an AsyncTask SHOULD NOT execute for more than a few seconds. For tasks that
 * run for a long time or infinitely, start another thread instead.
 *
 * WARNING: Any non-Threaded objects WILL BE SERIALIZED when assigned to members of AsyncTasks or other Threaded object.
 * If later accessed from said Threaded object, you will be operating on a COPY OF THE OBJECT, NOT THE ORIGINAL OBJECT.
 * If you want to store non-serializable objects to access when the task completes, store them using
 * {@link AsyncTask::storeLocal}.
 *
 * WARNING: As of pthreads v3.1.6, arrays are converted to Volatile objects when assigned as members of Threaded objects.
 * Keep this in mind when using arrays stored as members of your AsyncTask.
 *
 * WARNING: Do not call PocketMine-MP API methods from other Threads!!
 */
abstract class AsyncTask extends Collectable{
	/**
	 * @var \SplObjectStorage|null
	 * Used to store objects on the main thread which should not be serialized.
	 */
	private static $localObjectStorage;

	/** @var AsyncWorker|null $worker */
	public $worker = null;

	/** @var \Threaded */
	public $progressUpdates;

	/** @var scalar|null */
	private $result = null;
	/** @var bool */
	private $serialized = false;
	/** @var bool */
	private $cancelRun = false;
	/** @var int|null */
	private $taskId = null;

	/** @var bool */
	private $crashed = false;

	/**
	 * @return void
	 */
	public function run(){
		$this->result = null;

		if(!$this->cancelRun){
			try{
				$this->onRun();
			}catch(\Throwable $e){
				$this->crashed = true;
				$this->worker->handleException($e);
			}
		}

		$this->setGarbage();
	}

	public function isCrashed() : bool{
		return $this->crashed or $this->isTerminated();
	}

	/**
	 * @return mixed
	 */
	public function getResult(){
		return $this->serialized ? unserialize($this->result) : $this->result;
	}

	/**
	 * @return void
	 */
	public function cancelRun(){
		$this->cancelRun = true;
	}

	public function hasCancelledRun() : bool{
		return $this->cancelRun;
	}

	public function hasResult() : bool{
		return $this->result !== null;
	}

	/**
	 * @param mixed $result
	 *
	 * @return void
	 */
	public function setResult($result){
		$this->result = ($this->serialized = !is_scalar($result)) ? serialize($result) : $result;
	}

	/**
	 * @return void
	 */
	public function setTaskId(int $taskId){
		$this->taskId = $taskId;
	}

	/**
	 * @return int|null
	 */
	public function getTaskId(){
		return $this->taskId;
	}

	/**
	 * @see AsyncWorker::getFromThreadStore()
	 *
	 * @return mixed
	 */
	public function getFromThreadStore(string $identifier){
		if($this->worker === null or $this->isGarbage()){
			throw new \BadMethodCallException("Objects stored in AsyncWorker thread-local storage can only be retrieved during task execution");
		}
		return $this->worker->getFromThreadStore($identifier);
	}

	/**
	 * @see AsyncWorker::saveToThreadStore()
	 *
	 * @param mixed  $value
	 *
	 * @return void
	 */
	public function saveToThreadStore(string $identifier, $value){
		if($this->worker === null or $this->isGarbage()){
			throw new \BadMethodCallException("Objects can only be added to AsyncWorker thread-local storage during task execution");
		}
		$this->worker->saveToThreadStore($identifier, $value);
	}

	/**
	 * @see AsyncWorker::removeFromThreadStore()
	 */
	public function removeFromThreadStore(string $identifier) : void{
		if($this->worker === null or $this->isGarbage()){
			throw new \BadMethodCallException("Objects can only be removed from AsyncWorker thread-local storage during task execution");
		}
		$this->worker->removeFromThreadStore($identifier);
	}

	/**
	 * Actions to execute when run
	 *
	 * @return void
	 */
	abstract public function onRun();

	/**
	 * Actions to execute when completed (on main thread)
	 * Implement this if you want to handle the data in your AsyncTask after it has been processed
	 *
	 * @return void
	 */
	public function onCompletion(Server $server){

	}

	/**
	 * Call this method from {@link AsyncTask::onRun} (AsyncTask execution thread) to schedule a call to
	 * {@link AsyncTask::onProgressUpdate} from the main thread with the given progress parameter.
	 *
	 * @param mixed $progress A value that can be safely serialize()'ed.
	 *
	 * @return void
	 */
	public function publishProgress($progress){
		$this->progressUpdates[] = serialize($progress);
	}

	/**
	 * @internal Only call from AsyncPool.php on the main thread
	 *
	 * @return void
	 */
	public function checkProgressUpdates(Server $server){
		while($this->progressUpdates->count() !== 0){
			$progress = $this->progressUpdates->shift();
			$this->onProgressUpdate($server, unserialize($progress));
		}
	}

	/**
	 * Called from the main thread after {@link AsyncTask::publishProgress} is called.
	 * All {@link AsyncTask::publishProgress} calls should result in {@link AsyncTask::onProgressUpdate} calls before
	 * {@link AsyncTask::onCompletion} is called.
	 *
	 * @param mixed  $progress The parameter passed to {@link AsyncTask::publishProgress}. It is serialize()'ed
	 *                         and then unserialize()'ed, as if it has been cloned.
	 *
	 * @return void
	 */
	public function onProgressUpdate(Server $server, $progress){

	}

	/**
	 * Saves mixed data in thread-local storage on the parent thread. You may use this to retain references to objects
	 * or arrays which you need to access in {@link AsyncTask::onCompletion} which cannot be stored as a property of
	 * your task (due to them becoming serialized).
	 *
	 * Scalar types can be stored directly in class properties instead of using this storage.
	 *
	 * Objects stored in this storage MUST be retrieved through {@link AsyncTask::fetchLocal} when {@link AsyncTask::onCompletion} is called.
	 * Otherwise, a NOTICE level message will be raised and the reference will be removed after onCompletion exits.
	 *
	 * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD!
	 *
	 * @param mixed $complexData the data to store
	 *
	 * @return void
	 * @throws \BadMethodCallException if called from any thread except the main thread
	 */
	protected function storeLocal($complexData){
		if($this->worker !== null and $this->worker === \Thread::getCurrentThread()){
			throw new \BadMethodCallException("Objects can only be stored from the parent thread");
		}

		if(self::$localObjectStorage === null){
			self::$localObjectStorage = new \SplObjectStorage(); //lazy init
		}

		if(isset(self::$localObjectStorage[$this])){
			throw new \InvalidStateException("Already storing complex data for this async task");
		}
		self::$localObjectStorage[$this] = $complexData;
	}

	/**
	 * Returns and removes mixed data in thread-local storage on the parent thread. Call this method from
	 * {@link AsyncTask::onCompletion} to fetch the data stored in the object store, if any.
	 *
	 * If no data was stored in the local store, or if the data was already retrieved by a previous call to fetchLocal,
	 * do NOT call this method, or an exception will be thrown.
	 *
	 * Do not call this method from {@link AsyncTask::onProgressUpdate}, because this method deletes stored data, which
	 * means that you will not be able to retrieve it again afterwards. Use {@link AsyncTask::peekLocal} instead to
	 * retrieve stored data without removing it from the store.
	 *
	 * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD!
	 *
	 * @return mixed
	 *
	 * @throws \RuntimeException if no data were stored by this AsyncTask instance.
	 * @throws \BadMethodCallException if called from any thread except the main thread
	 */
	protected function fetchLocal(){
		try{
			return $this->peekLocal();
		}finally{
			if(self::$localObjectStorage !== null){
				unset(self::$localObjectStorage[$this]);
			}
		}
	}

	/**
	 * Returns mixed data in thread-local storage on the parent thread **without clearing** it. Call this method from
	 * {@link AsyncTask::onProgressUpdate} to fetch the data stored if you need to be able to access the data later on,
	 * such as in another progress update.
	 *
	 * Use {@link AsyncTask::fetchLocal} instead from {@link AsyncTask::onCompletion}, because this method does not delete
	 * the data, and not clearing the data will result in a warning for memory leak after {@link AsyncTask::onCompletion}
	 * finished executing.
	 *
	 * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD!
	 *
	 * @return mixed
	 *
	 * @throws \RuntimeException if no data were stored by this AsyncTask instance
	 * @throws \BadMethodCallException if called from any thread except the main thread
	 */
	protected function peekLocal(){
		if($this->worker !== null and $this->worker === \Thread::getCurrentThread()){
			throw new \BadMethodCallException("Objects can only be retrieved from the parent thread");
		}

		if(self::$localObjectStorage === null or !isset(self::$localObjectStorage[$this])){
			throw new \InvalidStateException("No complex data stored for this async task");
		}

		return self::$localObjectStorage[$this];
	}

	/**
	 * @internal Called by the AsyncPool to destroy any leftover stored objects that this task failed to retrieve.
	 */
	public function removeDanglingStoredObjects() : bool{
		if(self::$localObjectStorage !== null and isset(self::$localObjectStorage[$this])){
			unset(self::$localObjectStorage[$this]);
			return true;
		}

		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine;

abstract class Collectable extends \Threaded{

	/** @var bool */
	private $isGarbage = false;

	public function isGarbage() : bool{
		return $this->isGarbage;
	}

	/**
	 * @return void
	 */
	public function setGarbage(){
		$this->isGarbage = true;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\scheduler;

use pocketmine\utils\MainLogger;
use pocketmine\utils\Utils;
use pocketmine\Worker;
use function error_reporting;
use function gc_enable;
use function ini_set;
use function set_error_handler;

class AsyncWorker extends Worker{
	/** @var mixed[] */
	private static $store = [];

	/** @var \ThreadedLogger */
	private $logger;
	/** @var int */
	private $id;

	/** @var int */
	private $memoryLimit;

	public function __construct(\ThreadedLogger $logger, int $id, int $memoryLimit){
		$this->logger = $logger;
		$this->id = $id;
		$this->memoryLimit = $memoryLimit;
	}

	/**
	 * @return void
	 */
	public function run(){
		error_reporting(-1);

		$this->registerClassLoader();

		//set this after the autoloader is registered
		set_error_handler([Utils::class, 'errorExceptionHandler']);

		if($this->logger instanceof MainLogger){
			$this->logger->registerStatic();
		}

		gc_enable();

		if($this->memoryLimit > 0){
			ini_set('memory_limit', $this->memoryLimit . 'M');
			$this->logger->debug("Set memory limit to " . $this->memoryLimit . " MB");
		}else{
			ini_set('memory_limit', '-1');
			$this->logger->debug("No memory limit set");
		}
	}

	public function getLogger() : \ThreadedLogger{
		return $this->logger;
	}

	/**
	 * @return void
	 */
	public function handleException(\Throwable $e){
		$this->logger->logException($e);
	}

	public function getThreadName() : string{
		return "Asynchronous Worker #" . $this->id;
	}

	public function getAsyncWorkerId() : int{
		return $this->id;
	}

	/**
	 * Saves mixed data into the worker's thread-local object store. This can be used to store objects which you
	 * want to use on this worker thread from multiple AsyncTasks.
	 *
	 * @param mixed  $value
	 */
	public function saveToThreadStore(string $identifier, $value) : void{
		self::$store[$identifier] = $value;
	}

	/**
	 * Retrieves mixed data from the worker's thread-local object store.
	 *
	 * Note that the thread-local object store could be cleared and your data might not exist, so your code should
	 * account for the possibility that what you're trying to retrieve might not exist.
	 *
	 * Objects stored in this storage may ONLY be retrieved while the task is running.
	 *
	 * @return mixed
	 */
	public function getFromThreadStore(string $identifier){
		return self::$store[$identifier] ?? null;
	}

	/**
	 * Removes previously-stored mixed data from the worker's thread-local object store.
	 */
	public function removeFromThreadStore(string $identifier) : void{
		unset(self::$store[$identifier]);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine;

/**
 * This class must be extended by all custom threading classes
 */
abstract class Worker extends \Worker{

	/** @var \ClassLoader|null */
	protected $classLoader;
	/** @var string|null */
	protected $composerAutoloaderPath;

	/** @var bool */
	protected $isKilled = false;

	/**
	 * @return \ClassLoader|null
	 */
	public function getClassLoader(){
		return $this->classLoader;
	}

	/**
	 * @return void
	 */
	public function setClassLoader(\ClassLoader $loader = null){
		$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;

		if($loader === null){
			$loader = Server::getInstance()->getLoader();
		}
		$this->classLoader = $loader;
	}

	/**
	 * Registers the class loader for this thread.
	 *
	 * WARNING: This method MUST be called from any descendent threads' run() method to make autoloading usable.
	 * If you do not do this, you will not be able to use new classes that were not loaded when the thread was started
	 * (unless you are using a custom autoloader).
	 *
	 * @return void
	 */
	public function registerClassLoader(){
		if($this->composerAutoloaderPath !== null){
			require $this->composerAutoloaderPath;
		}
		if($this->classLoader !== null){
			$this->classLoader->register(false);
		}
	}

	/**
	 * @param int|null $options TODO: pthreads bug
	 *
	 * @return bool
	 */
	public function start(?int $options = \PTHREADS_INHERIT_ALL){
		ThreadManager::getInstance()->add($this);

		if($this->getClassLoader() === null){
			$this->setClassLoader();
		}
		return parent::start($options);
	}

	/**
	 * Stops the thread using the best way possible. Try to stop it yourself before calling this.
	 *
	 * @return void
	 */
	public function quit(){
		$this->isKilled = true;

		if($this->isRunning()){
			while($this->unstack() !== null);
			$this->notify();
			$this->shutdown();
		}

		ThreadManager::getInstance()->remove($this);
	}

	public function getThreadName() : string{
		return (new \ReflectionClass($this))->getShortName();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\plugin;

abstract class PluginLoadOrder{
	/*
	 * The plugin will be loaded at startup
	 */
	public const STARTUP = 0;

	/*
	 * The plugin will be loaded after the first world has been loaded/created.
	 */
	public const POSTWORLD = 1;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe;

use pocketmine\event\player\PlayerCreationEvent;
use pocketmine\network\AdvancedSourceInterface;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\Network;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\snooze\SleeperNotifier;
use raklib\protocol\EncapsulatedPacket;
use raklib\protocol\PacketReliability;
use raklib\RakLib;
use raklib\server\RakLibServer;
use raklib\server\ServerHandler;
use raklib\server\ServerInstance;
use raklib\utils\InternetAddress;
use function addcslashes;
use function base64_encode;
use function get_class;
use function implode;
use function rtrim;
use function spl_object_hash;
use function unserialize;
use const PTHREADS_INHERIT_CONSTANTS;

class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
	/**
	 * Sometimes this gets changed when the MCPE-layer protocol gets broken to the point where old and new can't
	 * communicate. It's important that we check this to avoid catastrophes.
	 */
	private const MCPE_RAKNET_PROTOCOL_VERSION = 9;

	/** @var Server */
	private $server;

	/** @var Network */
	private $network;

	/** @var RakLibServer */
	private $rakLib;

	/** @var Player[] */
	private $players = [];

	/** @var string[] */
	private $identifiers = [];

	/** @var int[] */
	private $identifiersACK = [];

	/** @var ServerHandler */
	private $interface;

	/** @var SleeperNotifier */
	private $sleeper;

	public function __construct(Server $server){
		$this->server = $server;

		$this->sleeper = new SleeperNotifier();
		$this->rakLib = new RakLibServer(
			$this->server->getLogger(),
			\pocketmine\COMPOSER_AUTOLOADER_PATH,
			new InternetAddress($this->server->getIp(), $this->server->getPort(), 4),
			(int) $this->server->getProperty("network.max-mtu-size", 1492),
			self::MCPE_RAKNET_PROTOCOL_VERSION,
			$this->sleeper
		);
		$this->interface = new ServerHandler($this->rakLib, $this);
	}

	public function start(){
		$this->server->getTickSleeper()->addNotifier($this->sleeper, function() : void{
			$this->process();
		});
		$this->rakLib->start(PTHREADS_INHERIT_CONSTANTS); //HACK: MainLogger needs constants for exception logging
	}

	public function setNetwork(Network $network){
		$this->network = $network;
	}

	public function process() : void{
		while($this->interface->handlePacket()){}

		if(!$this->rakLib->isRunning() and !$this->rakLib->isShutdown()){
			throw new \Exception("RakLib Thread crashed");
		}
	}

	public function closeSession(string $identifier, string $reason) : void{
		if(isset($this->players[$identifier])){
			$player = $this->players[$identifier];
			unset($this->identifiers[spl_object_hash($player)]);
			unset($this->players[$identifier]);
			unset($this->identifiersACK[$identifier]);
			$player->close($player->getLeaveMessage(), $reason);
		}
	}

	public function close(Player $player, string $reason = "unknown reason"){
		if(isset($this->identifiers[$h = spl_object_hash($player)])){
			unset($this->players[$this->identifiers[$h]]);
			unset($this->identifiersACK[$this->identifiers[$h]]);
			$this->interface->closeSession($this->identifiers[$h], $reason);
			unset($this->identifiers[$h]);
		}
	}

	public function shutdown(){
		$this->server->getTickSleeper()->removeNotifier($this->sleeper);
		$this->interface->shutdown();
	}

	public function emergencyShutdown(){
		$this->server->getTickSleeper()->removeNotifier($this->sleeper);
		$this->interface->emergencyShutdown();
	}

	public function openSession(string $identifier, string $address, int $port, int $clientID) : void{
		$ev = new PlayerCreationEvent($this, Player::class, Player::class, $address, $port);
		$ev->call();
		$class = $ev->getPlayerClass();

		/**
		 * @var Player $player
		 * @see Player::__construct()
		 */
		$player = new $class($this, $ev->getAddress(), $ev->getPort());
		$this->players[$identifier] = $player;
		$this->identifiersACK[$identifier] = 0;
		$this->identifiers[spl_object_hash($player)] = $identifier;
		$this->server->addPlayer($player);
	}

	public function handleEncapsulated(string $identifier, EncapsulatedPacket $packet, int $flags) : void{
		if(isset($this->players[$identifier])){
			//get this now for blocking in case the player was closed before the exception was raised
			$player = $this->players[$identifier];
			$address = $player->getAddress();
			try{
				if($packet->buffer !== ""){
					$pk = new BatchPacket($packet->buffer);
					$player->handleDataPacket($pk);
				}
			}catch(\Throwable $e){
				$logger = $this->server->getLogger();
				$logger->debug("Packet " . (isset($pk) ? get_class($pk) : "unknown") . ": " . base64_encode($packet->buffer));
				$logger->logException($e);

				$player->close($player->getLeaveMessage(), "Internal server error");
				$this->interface->blockAddress($address, 5);
			}
		}
	}

	public function blockAddress(string $address, int $timeout = 300){
		$this->interface->blockAddress($address, $timeout);
	}

	public function unblockAddress(string $address){
		$this->interface->unblockAddress($address);
	}

	public function handleRaw(string $address, int $port, string $payload) : void{
		$this->server->handlePacket($this, $address, $port, $payload);
	}

	public function sendRawPacket(string $address, int $port, string $payload){
		$this->interface->sendRaw($address, $port, $payload);
	}

	public function notifyACK(string $identifier, int $identifierACK) : void{

	}

	public function setName(string $name){
		$info = $this->server->getQueryInformation();

		$this->interface->sendOption("name", implode(";",
			[
				"MCPE",
				rtrim(addcslashes($name, ";"), '\\'),
				ProtocolInfo::CURRENT_PROTOCOL,
				ProtocolInfo::MINECRAFT_VERSION_NETWORK,
				$info->getPlayerCount(),
				$info->getMaxPlayerCount(),
				$this->rakLib->getServerId(),
				$this->server->getName(),
				Server::getGamemodeName($this->server->getGamemode())
			]) . ";"
		);
	}

	/**
	 * @param bool $name
	 *
	 * @return void
	 */
	public function setPortCheck($name){
		$this->interface->sendOption("portChecking", $name);
	}

	public function handleOption(string $option, string $value) : void{
		if($option === "bandwidth"){
			$v = unserialize($value);
			$this->network->addStatistics($v["up"], $v["down"]);
		}
	}

	public function putPacket(Player $player, DataPacket $packet, bool $needACK = false, bool $immediate = true){
		if(isset($this->identifiers[$h = spl_object_hash($player)])){
			$identifier = $this->identifiers[$h];
			if(!$packet->isEncoded){
				$packet->encode();
			}

			if($packet instanceof BatchPacket){
				if($needACK){
					$pk = new EncapsulatedPacket();
					$pk->identifierACK = $this->identifiersACK[$identifier]++;
					$pk->buffer = $packet->buffer;
					$pk->reliability = PacketReliability::RELIABLE_ORDERED;
					$pk->orderChannel = 0;
				}else{
					if(!isset($packet->__encapsulatedPacket)){
						$packet->__encapsulatedPacket = new CachedEncapsulatedPacket;
						$packet->__encapsulatedPacket->identifierACK = null;
						$packet->__encapsulatedPacket->buffer = $packet->buffer;
						$packet->__encapsulatedPacket->reliability = PacketReliability::RELIABLE_ORDERED;
						$packet->__encapsulatedPacket->orderChannel = 0;
					}
					$pk = $packet->__encapsulatedPacket;
				}

				$this->interface->sendEncapsulated($identifier, $pk, ($needACK ? RakLib::FLAG_NEED_ACK : 0) | ($immediate ? RakLib::PRIORITY_IMMEDIATE : RakLib::PRIORITY_NORMAL));
				return $pk->identifierACK;
			}else{
				$this->server->batchPackets([$player], [$packet], true, $immediate);
				return null;
			}
		}

		return null;
	}

	public function updatePing(string $identifier, int $pingMS) : void{
		if(isset($this->players[$identifier])){
			$this->players[$identifier]->updatePing($pingMS);
		}
	}
}
<?php

/*
 * RakLib network library
 *
 *
 * This project is not affiliated with Jenkins Software LLC nor RakNet.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 */

declare(strict_types=1);

namespace raklib\server;

use raklib\protocol\EncapsulatedPacket;

interface ServerInstance{

	/**
	 * @param string $identifier
	 * @param string $address
	 * @param int    $port
	 * @param int    $clientID
	 */
	public function openSession(string $identifier, string $address, int $port, int $clientID) : void;

	/**
	 * @param string $identifier
	 * @param string $reason
	 */
	public function closeSession(string $identifier, string $reason) : void;

	/**
	 * @param string             $identifier
	 * @param EncapsulatedPacket $packet
	 * @param int                $flags
	 */
	public function handleEncapsulated(string $identifier, EncapsulatedPacket $packet, int $flags) : void;

	/**
	 * @param string $address
	 * @param int    $port
	 * @param string $payload
	 */
	public function handleRaw(string $address, int $port, string $payload) : void;

	/**
	 * @param string $identifier
	 * @param int    $identifierACK
	 */
	public function notifyACK(string $identifier, int $identifierACK) : void;

	/**
	 * @param string $option
	 * @param string $value
	 */
	public function handleOption(string $option, string $value) : void;

	/**
	 * @param string $identifier
	 * @param int    $pingMS
	 */
	public function updatePing(string $identifier, int $pingMS) : void;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Network-related classes
 */
namespace pocketmine\network;

/**
 * Advanced network interfaces have some additional capabilities, such as being able to ban addresses and process raw
 * packets.
 */
interface AdvancedSourceInterface extends SourceInterface{

	/**
	 * Prevents packets received from the IP address getting processed for the given timeout.
	 *
	 * @param int    $timeout Seconds
	 *
	 * @return void
	 */
	public function blockAddress(string $address, int $timeout = 300);

	/**
	 * Unblocks a previously-blocked address.
	 *
	 * @return void
	 */
	public function unblockAddress(string $address);

	/**
	 * @return void
	 */
	public function setNetwork(Network $network);

	/**
	 * Sends a raw payload to the network interface, bypassing any sessions.
	 *
	 * @return void
	 */
	public function sendRawPacket(string $address, int $port, string $payload);

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Network-related classes
 */
namespace pocketmine\network;

use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\Player;

/**
 * Network interfaces are transport layers which can be used to transmit packets between the server and clients.
 */
interface SourceInterface{

	/**
	 * Performs actions needed to start the interface after it is registered.
	 *
	 * @return void
	 */
	public function start();

	/**
	 * Sends a DataPacket to the interface, returns an unique identifier for the packet if $needACK is true
	 *
	 * @return int|null
	 */
	public function putPacket(Player $player, DataPacket $packet, bool $needACK = false, bool $immediate = true);

	/**
	 * Terminates the connection
	 *
	 * @return void
	 */
	public function close(Player $player, string $reason = "unknown reason");

	/**
	 * @return void
	 */
	public function setName(string $name);

	/**
	 * Called every tick to process events on the interface.
	 */
	public function process() : void;

	/**
	 * Gracefully shuts down the network interface.
	 *
	 * @return void
	 */
	public function shutdown();

	/**
	 * @deprecated
	 * Shuts down the network interface in an emergency situation, such as due to a crash.
	 *
	 * @return void
	 */
	public function emergencyShutdown();

}
<?php

/*
 * RakLib network library
 *
 *
 * This project is not affiliated with Jenkins Software LLC nor RakNet.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 */

declare(strict_types=1);

namespace raklib\server;

use function error_get_last;
use pocketmine\snooze\SleeperNotifier;
use raklib\RakLib;
use raklib\utils\InternetAddress;
use function array_reverse;
use function error_reporting;
use function function_exists;
use function gc_enable;
use function get_class;
use function getcwd;
use function gettype;
use function ini_set;
use function is_object;
use function method_exists;
use function mt_rand;
use function preg_replace;
use function realpath;
use function register_shutdown_function;
use function set_error_handler;
use function str_replace;
use function strval;
use function substr;
use function trim;
use function xdebug_get_function_stack;
use const DIRECTORY_SEPARATOR;
use const E_ALL;
use const E_COMPILE_ERROR;
use const E_COMPILE_WARNING;
use const E_CORE_ERROR;
use const E_CORE_WARNING;
use const E_DEPRECATED;
use const E_ERROR;
use const E_NOTICE;
use const E_PARSE;
use const E_RECOVERABLE_ERROR;
use const E_STRICT;
use const E_USER_DEPRECATED;
use const E_USER_ERROR;
use const E_USER_NOTICE;
use const E_USER_WARNING;
use const E_WARNING;
use const PHP_INT_MAX;

class RakLibServer extends \Thread{
	/** @var InternetAddress */
	private $address;

	/** @var \ThreadedLogger */
	protected $logger;

	/** @var string */
	protected $loaderPath;

	/** @var bool */
	protected $shutdown = false;

	/** @var \Threaded */
	protected $externalQueue;
	/** @var \Threaded */
	protected $internalQueue;

	/** @var string */
	protected $mainPath;

	/** @var int */
	protected $serverId = 0;
	/** @var int */
	protected $maxMtuSize;
	/** @var int */
	private $protocolVersion;

	/** @var SleeperNotifier */
	protected $mainThreadNotifier;

	/**
	 * @param \ThreadedLogger      $logger
	 * @param string               $autoloaderPath Path to Composer autoloader
	 * @param InternetAddress      $address
	 * @param int                  $maxMtuSize
	 * @param int|null             $overrideProtocolVersion Optional custom protocol version to use, defaults to current RakLib's protocol
	 * @param SleeperNotifier|null $sleeper
	 */
	public function __construct(\ThreadedLogger $logger, string $autoloaderPath, InternetAddress $address, int $maxMtuSize = 1492, ?int $overrideProtocolVersion = null, ?SleeperNotifier $sleeper = null){
		$this->address = $address;

		$this->serverId = mt_rand(0, PHP_INT_MAX);
		$this->maxMtuSize = $maxMtuSize;

		$this->logger = $logger;
		$this->loaderPath = $autoloaderPath;

		$this->externalQueue = new \Threaded;
		$this->internalQueue = new \Threaded;

		if(\Phar::running(true) !== ""){
			$this->mainPath = \Phar::running(true);
		}else{
			$this->mainPath = realpath(getcwd()) . DIRECTORY_SEPARATOR;
		}

		$this->protocolVersion = $overrideProtocolVersion ?? RakLib::DEFAULT_PROTOCOL_VERSION;

		$this->mainThreadNotifier = $sleeper;
	}

	public function isShutdown() : bool{
		return $this->shutdown === true;
	}

	public function shutdown() : void{
		$this->shutdown = true;
	}

	/**
	 * Returns the RakNet server ID
	 * @return int
	 */
	public function getServerId() : int{
		return $this->serverId;
	}

	public function getProtocolVersion() : int{
		return $this->protocolVersion;
	}

	/**
	 * @return \ThreadedLogger
	 */
	public function getLogger() : \ThreadedLogger{
		return $this->logger;
	}

	/**
	 * @return \Threaded
	 */
	public function getExternalQueue() : \Threaded{
		return $this->externalQueue;
	}

	/**
	 * @return \Threaded
	 */
	public function getInternalQueue() : \Threaded{
		return $this->internalQueue;
	}

	public function pushMainToThreadPacket(string $str) : void{
		$this->internalQueue[] = $str;
	}

	public function readMainToThreadPacket() : ?string{
		return $this->internalQueue->shift();
	}

	public function pushThreadToMainPacket(string $str) : void{
		$this->externalQueue[] = $str;
		if($this->mainThreadNotifier !== null){
			$this->mainThreadNotifier->wakeupSleeper();
		}
	}

	public function readThreadToMainPacket() : ?string{
		return $this->externalQueue->shift();
	}

	/**
	 * @return void
	 */
	public function shutdownHandler(){
		if($this->shutdown !== true){
			$error = error_get_last();
			if($error !== null){
				$this->logger->emergency("Fatal error: " . $error["message"] . " in " . $error["file"] . " on line " . $error["line"]);
			}else{
				$this->logger->emergency("RakLib shutdown unexpectedly");
			}
		}
	}

	public function errorHandler($errno, $errstr, $errfile, $errline){
		if(error_reporting() === 0){
			return false;
		}

		$errorConversion = [
			E_ERROR => "E_ERROR",
			E_WARNING => "E_WARNING",
			E_PARSE => "E_PARSE",
			E_NOTICE => "E_NOTICE",
			E_CORE_ERROR => "E_CORE_ERROR",
			E_CORE_WARNING => "E_CORE_WARNING",
			E_COMPILE_ERROR => "E_COMPILE_ERROR",
			E_COMPILE_WARNING => "E_COMPILE_WARNING",
			E_USER_ERROR => "E_USER_ERROR",
			E_USER_WARNING => "E_USER_WARNING",
			E_USER_NOTICE => "E_USER_NOTICE",
			E_STRICT => "E_STRICT",
			E_RECOVERABLE_ERROR => "E_RECOVERABLE_ERROR",
			E_DEPRECATED => "E_DEPRECATED",
			E_USER_DEPRECATED => "E_USER_DEPRECATED"
		];

		$errno = $errorConversion[$errno] ?? $errno;

		$errstr = preg_replace('/\s+/', ' ', trim($errstr));
		$errfile = $this->cleanPath($errfile);

		$this->getLogger()->debug("An $errno error happened: \"$errstr\" in \"$errfile\" at line $errline");

		foreach($this->getTrace(2) as $i => $line){
			$this->getLogger()->debug($line);
		}

		return true;
	}

	public function getTrace($start = 0, $trace = null){
		if($trace === null){
			if(function_exists("xdebug_get_function_stack")){
				$trace = array_reverse(xdebug_get_function_stack());
			}else{
				$e = new \Exception();
				$trace = $e->getTrace();
			}
		}

		$messages = [];
		$j = 0;
		for($i = (int) $start; isset($trace[$i]); ++$i, ++$j){
			$params = "";
			if(isset($trace[$i]["args"]) or isset($trace[$i]["params"])){
				if(isset($trace[$i]["args"])){
					$args = $trace[$i]["args"];
				}else{
					$args = $trace[$i]["params"];
				}
				foreach($args as $name => $value){
					$params .= (is_object($value) ? get_class($value) . " " . (method_exists($value, "__toString") ? $value->__toString() : "object") : gettype($value) . " " . @strval($value)) . ", ";
				}
			}
			$messages[] = "#$j " . (isset($trace[$i]["file"]) ? $this->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"] . "(" . substr($params, 0, -2) . ")";
		}

		return $messages;
	}

	public function cleanPath($path){
		return str_replace(["\\", ".php", "phar://", str_replace(["\\", "phar://"], ["/", ""], $this->mainPath)], ["/", "", "", ""], $path);
	}

	public function run() : void{
		try{
			require $this->loaderPath;

			gc_enable();
			error_reporting(-1);
			ini_set("display_errors", '1');
			ini_set("display_startup_errors", '1');

			set_error_handler([$this, "errorHandler"], E_ALL);
			register_shutdown_function([$this, "shutdownHandler"]);


			$socket = new UDPServerSocket($this->address);
			new SessionManager($this, $socket, $this->maxMtuSize);
		}catch(\Throwable $e){
			$this->logger->logException($e);
		}
	}

}
<?php

/*
 * RakLib network library
 *
 *
 * This project is not affiliated with Jenkins Software LLC nor RakNet.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 */

declare(strict_types=1);

namespace raklib\utils;

class InternetAddress{

	/**
	 * @var string
	 */
	public $ip;
	/**
	 * @var int
	 */
	public $port;
	/**
	 * @var int
	 */
	public $version;

	public function __construct(string $address, int $port, int $version){
		$this->ip = $address;
		if($port < 0 or $port > 65535){
			throw new \InvalidArgumentException("Invalid port range");
		}
		$this->port = $port;
		$this->version = $version;
	}

	/**
	 * @return string
	 */
	public function getIp() : string{
		return $this->ip;
	}

	/**
	 * @return int
	 */
	public function getPort() : int{
		return $this->port;
	}

	/**
	 * @return int
	 */
	public function getVersion() : int{
		return $this->version;
	}

	public function __toString(){
		return $this->ip . " " . $this->port;
	}

	public function toString() : string{
		return $this->__toString();
	}

	public function equals(InternetAddress $address) : bool{
		return $this->ip === $address->ip and $this->port === $address->port and $this->version === $address->version;
	}
}
<?php

/*
 * RakLib network library
 *
 *
 * This project is not affiliated with Jenkins Software LLC nor RakNet.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 */

declare(strict_types=1);

namespace raklib\server;

use pocketmine\utils\Binary;
use raklib\protocol\EncapsulatedPacket;
use raklib\RakLib;
use function chr;
use function ord;
use function strlen;
use function substr;

class ServerHandler{

	/** @var RakLibServer */
	protected $server;
	/** @var ServerInstance */
	protected $instance;

	public function __construct(RakLibServer $server, ServerInstance $instance){
		$this->server = $server;
		$this->instance = $instance;
	}

	public function sendEncapsulated(string $identifier, EncapsulatedPacket $packet, int $flags = RakLib::PRIORITY_NORMAL) : void{
		$buffer = chr(RakLib::PACKET_ENCAPSULATED) . chr(strlen($identifier)) . $identifier . chr($flags) . $packet->toInternalBinary();
		$this->server->pushMainToThreadPacket($buffer);
	}

	public function sendRaw(string $address, int $port, string $payload) : void{
		$buffer = chr(RakLib::PACKET_RAW) . chr(strlen($address)) . $address . (\pack("n", $port)) . $payload;
		$this->server->pushMainToThreadPacket($buffer);
	}

	public function closeSession(string $identifier, string $reason) : void{
		$buffer = chr(RakLib::PACKET_CLOSE_SESSION) . chr(strlen($identifier)) . $identifier . chr(strlen($reason)) . $reason;
		$this->server->pushMainToThreadPacket($buffer);
	}

	/**
	 * @param string $name
	 * @param mixed  $value Must be castable to string
	 */
	public function sendOption(string $name, $value) : void{
		$buffer = chr(RakLib::PACKET_SET_OPTION) . chr(strlen($name)) . $name . $value;
		$this->server->pushMainToThreadPacket($buffer);
	}

	public function blockAddress(string $address, int $timeout) : void{
		$buffer = chr(RakLib::PACKET_BLOCK_ADDRESS) . chr(strlen($address)) . $address . (\pack("N", $timeout));
		$this->server->pushMainToThreadPacket($buffer);
	}

	public function unblockAddress(string $address) : void{
		$buffer = chr(RakLib::PACKET_UNBLOCK_ADDRESS) . chr(strlen($address)) . $address;
		$this->server->pushMainToThreadPacket($buffer);
	}

	public function shutdown() : void{
		$buffer = chr(RakLib::PACKET_SHUTDOWN);
		$this->server->pushMainToThreadPacket($buffer);
		$this->server->shutdown();
		$this->server->join();
	}

	public function emergencyShutdown() : void{
		$this->server->shutdown();
		$this->server->pushMainToThreadPacket(chr(RakLib::PACKET_EMERGENCY_SHUTDOWN));
	}

	/**
	 * @return bool
	 */
	public function handlePacket() : bool{
		if(($packet = $this->server->readThreadToMainPacket()) !== null){
			$id = ord($packet[0]);
			$offset = 1;
			if($id === RakLib::PACKET_ENCAPSULATED){
				$len = ord($packet[$offset++]);
				$identifier = substr($packet, $offset, $len);
				$offset += $len;
				$flags = ord($packet[$offset++]);
				$buffer = substr($packet, $offset);
				$this->instance->handleEncapsulated($identifier, EncapsulatedPacket::fromInternalBinary($buffer), $flags);
			}elseif($id === RakLib::PACKET_RAW){
				$len = ord($packet[$offset++]);
				$address = substr($packet, $offset, $len);
				$offset += $len;
				$port = (\unpack("n", substr($packet, $offset, 2))[1]);
				$offset += 2;
				$payload = substr($packet, $offset);
				$this->instance->handleRaw($address, $port, $payload);
			}elseif($id === RakLib::PACKET_SET_OPTION){
				$len = ord($packet[$offset++]);
				$name = substr($packet, $offset, $len);
				$offset += $len;
				$value = substr($packet, $offset);
				$this->instance->handleOption($name, $value);
			}elseif($id === RakLib::PACKET_OPEN_SESSION){
				$len = ord($packet[$offset++]);
				$identifier = substr($packet, $offset, $len);
				$offset += $len;
				$len = ord($packet[$offset++]);
				$address = substr($packet, $offset, $len);
				$offset += $len;
				$port = (\unpack("n", substr($packet, $offset, 2))[1]);
				$offset += 2;
				$clientID = Binary::readLong(substr($packet, $offset, 8));
				$this->instance->openSession($identifier, $address, $port, $clientID);
			}elseif($id === RakLib::PACKET_CLOSE_SESSION){
				$len = ord($packet[$offset++]);
				$identifier = substr($packet, $offset, $len);
				$offset += $len;
				$len = ord($packet[$offset++]);
				$reason = substr($packet, $offset, $len);
				$this->instance->closeSession($identifier, $reason);
			}elseif($id === RakLib::PACKET_INVALID_SESSION){
				$len = ord($packet[$offset++]);
				$identifier = substr($packet, $offset, $len);
				$this->instance->closeSession($identifier, "Invalid session");
			}elseif($id === RakLib::PACKET_ACK_NOTIFICATION){
				$len = ord($packet[$offset++]);
				$identifier = substr($packet, $offset, $len);
				$offset += $len;
				$identifierACK = (\unpack("N", substr($packet, $offset, 4))[1] << 32 >> 32);
				$this->instance->notifyACK($identifier, $identifierACK);
			}elseif($id === RakLib::PACKET_REPORT_PING){
				$len = ord($packet[$offset++]);
				$identifier = substr($packet, $offset, $len);
				$offset += $len;
				$pingMS = (\unpack("N", substr($packet, $offset, 4))[1] << 32 >> 32);
				$this->instance->updatePing($identifier, $pingMS);
			}

			return true;
		}

		return false;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\server;

use pocketmine\event\Cancellable;

/**
 * Called when a network interface is registered into the network, for example the RakLib interface.
 */
class NetworkInterfaceRegisterEvent extends NetworkInterfaceEvent implements Cancellable{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\server;

use pocketmine\network\SourceInterface;

class NetworkInterfaceEvent extends ServerEvent{
	/** @var SourceInterface */
	protected $interface;

	public function __construct(SourceInterface $interface){
		$this->interface = $interface;
	}

	public function getInterface() : SourceInterface{
		return $this->interface;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event;

use pocketmine\plugin\Plugin;
use pocketmine\plugin\RegisteredListener;
use pocketmine\utils\Utils;
use function array_fill_keys;
use function in_array;
use function spl_object_hash;

class HandlerList{
	/** @var HandlerList[] classname => HandlerList */
	private static $allLists = [];

	/**
	 * Unregisters all the listeners
	 * If a Plugin or Listener is passed, all the listeners with that object will be removed
	 *
	 * @param Plugin|Listener|null $object
	 */
	public static function unregisterAll($object = null) : void{
		if($object instanceof Listener or $object instanceof Plugin){
			foreach(self::$allLists as $h){
				$h->unregister($object);
			}
		}else{
			foreach(self::$allLists as $h){
				foreach($h->handlerSlots as $key => $list){
					$h->handlerSlots[$key] = [];
				}
			}
		}
	}

	/**
	 * Returns the HandlerList for listeners that explicitly handle this event.
	 *
	 * Calling this method also lazily initializes the $classMap inheritance tree of handler lists.
	 *
	 * @throws \ReflectionException
	 */
	public static function getHandlerListFor(string $event) : ?HandlerList{
		if(isset(self::$allLists[$event])){
			return self::$allLists[$event];
		}

		$class = new \ReflectionClass($event);
		$tags = Utils::parseDocComment((string) $class->getDocComment());

		if($class->isAbstract() && !isset($tags["allowHandle"])){
			return null;
		}

		$super = $class;
		$parentList = null;
		while($parentList === null && ($super = $super->getParentClass()) !== false){
			// skip $noHandle events in the inheritance tree to go to the nearest ancestor
			// while loop to allow skipping $noHandle events in the inheritance tree
			$parentList = self::getHandlerListFor($super->getName());
		}

		return new HandlerList($event, $parentList);
	}

	/**
	 * @return HandlerList[]
	 */
	public static function getHandlerLists() : array{
		return self::$allLists;
	}

	/** @var string */
	private $class;
	/** @var RegisteredListener[][] */
	private $handlerSlots = [];
	/** @var HandlerList|null */
	private $parentList;

	public function __construct(string $class, ?HandlerList $parentList){
		$this->class = $class;
		$this->handlerSlots = array_fill_keys(EventPriority::ALL, []);
		$this->parentList = $parentList;
		self::$allLists[$this->class] = $this;
	}

	/**
	 * @throws \Exception
	 */
	public function register(RegisteredListener $listener) : void{
		if(!in_array($listener->getPriority(), EventPriority::ALL, true)){
			return;
		}
		if(isset($this->handlerSlots[$listener->getPriority()][spl_object_hash($listener)])){
			throw new \InvalidStateException("This listener is already registered to priority {$listener->getPriority()} of event {$this->class}");
		}
		$this->handlerSlots[$listener->getPriority()][spl_object_hash($listener)] = $listener;
	}

	/**
	 * @param RegisteredListener[] $listeners
	 */
	public function registerAll(array $listeners) : void{
		foreach($listeners as $listener){
			$this->register($listener);
		}
	}

	/**
	 * @param RegisteredListener|Listener|Plugin $object
	 */
	public function unregister($object) : void{
		if($object instanceof Plugin or $object instanceof Listener){
			foreach($this->handlerSlots as $priority => $list){
				foreach($list as $hash => $listener){
					if(($object instanceof Plugin and $listener->getPlugin() === $object)
						or ($object instanceof Listener and $listener->getListener() === $object)
					){
						unset($this->handlerSlots[$priority][$hash]);
					}
				}
			}
		}elseif($object instanceof RegisteredListener){
			if(isset($this->handlerSlots[$object->getPriority()][spl_object_hash($object)])){
				unset($this->handlerSlots[$object->getPriority()][spl_object_hash($object)]);
			}
		}
	}

	/**
	 * @return RegisteredListener[]
	 */
	public function getListenersByPriority(int $priority) : array{
		return $this->handlerSlots[$priority];
	}

	public function getParent() : ?HandlerList{
		return $this->parentList;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event;

use function constant;
use function defined;
use function strtoupper;

/**
 * List of event priorities
 *
 * Events will be called in this order:
 * LOWEST -> LOW -> NORMAL -> HIGH -> HIGHEST -> MONITOR
 *
 * MONITOR events should not change the event outcome or contents
 */
abstract class EventPriority{
	public const ALL = [
		self::LOWEST,
		self::LOW,
		self::NORMAL,
		self::HIGH,
		self::HIGHEST,
		self::MONITOR
	];

	/**
	 * Event call is of very low importance and should be ran first, to allow
	 * other plugins to further customise the outcome
	 */
	public const LOWEST = 5;
	/**
	 * Event call is of low importance
	 */
	public const LOW = 4;
	/**
	 * Event call is neither important or unimportant, and may be ran normally.
	 * This is the default priority.
	 */
	public const NORMAL = 3;
	/**
	 * Event call is of high importance
	 */
	public const HIGH = 2;
	/**
	 * Event call is critical and must have the final say in what happens
	 * to the event
	 */
	public const HIGHEST = 1;
	/**
	 * Event is listened to purely for monitoring the outcome of an event.
	 *
	 * No modifications to the event should be made under this priority
	 */
	public const MONITOR = 0;

	/**
	 * @throws \InvalidArgumentException
	 */
	public static function fromString(string $name) : int{
		$name = strtoupper($name);
		$const = self::class . "::" . $name;
		if($name !== "ALL" and defined($const)){
			return constant($const);
		}

		throw new \InvalidArgumentException("Unable to resolve priority \"$name\"");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine;

use pocketmine\block\Bed;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\block\UnknownBlock;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\entity\Effect;
use pocketmine\entity\EffectInstance;
use pocketmine\entity\Entity;
use pocketmine\entity\Human;
use pocketmine\entity\object\ItemEntity;
use pocketmine\entity\projectile\Arrow;
use pocketmine\entity\Skin;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\inventory\InventoryCloseEvent;
use pocketmine\event\player\cheat\PlayerIllegalMoveEvent;
use pocketmine\event\player\PlayerAchievementAwardedEvent;
use pocketmine\event\player\PlayerAnimationEvent;
use pocketmine\event\player\PlayerBedEnterEvent;
use pocketmine\event\player\PlayerBedLeaveEvent;
use pocketmine\event\player\PlayerBlockPickEvent;
use pocketmine\event\player\PlayerChangeSkinEvent;
use pocketmine\event\player\PlayerChatEvent;
use pocketmine\event\player\PlayerCommandPreprocessEvent;
use pocketmine\event\player\PlayerDeathEvent;
use pocketmine\event\player\PlayerEditBookEvent;
use pocketmine\event\player\PlayerExhaustEvent;
use pocketmine\event\player\PlayerGameModeChangeEvent;
use pocketmine\event\player\PlayerInteractEvent;
use pocketmine\event\player\PlayerItemConsumeEvent;
use pocketmine\event\player\PlayerJoinEvent;
use pocketmine\event\player\PlayerJumpEvent;
use pocketmine\event\player\PlayerKickEvent;
use pocketmine\event\player\PlayerLoginEvent;
use pocketmine\event\player\PlayerMoveEvent;
use pocketmine\event\player\PlayerPreLoginEvent;
use pocketmine\event\player\PlayerQuitEvent;
use pocketmine\event\player\PlayerRespawnEvent;
use pocketmine\event\player\PlayerToggleFlightEvent;
use pocketmine\event\player\PlayerToggleSneakEvent;
use pocketmine\event\player\PlayerToggleSprintEvent;
use pocketmine\event\player\PlayerTransferEvent;
use pocketmine\event\server\DataPacketSendEvent;
use pocketmine\form\Form;
use pocketmine\form\FormValidationException;
use pocketmine\inventory\CraftingGrid;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\PlayerCursorInventory;
use pocketmine\inventory\transaction\action\InventoryAction;
use pocketmine\inventory\transaction\CraftingTransaction;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\inventory\transaction\TransactionValidationException;
use pocketmine\item\Consumable;
use pocketmine\item\Durable;
use pocketmine\item\enchantment\EnchantmentInstance;
use pocketmine\item\enchantment\MeleeWeaponEnchantment;
use pocketmine\item\Item;
use pocketmine\item\MaybeConsumable;
use pocketmine\item\WritableBook;
use pocketmine\item\WrittenBook;
use pocketmine\lang\TextContainer;
use pocketmine\lang\TranslationContainer;
use pocketmine\level\ChunkLoader;
use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\level\Location;
use pocketmine\level\Position;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\PlayerNetworkSessionAdapter;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket;
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
use pocketmine\network\mcpe\protocol\BookEditPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\InteractPacket;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\LoginPacket;
use pocketmine\network\mcpe\protocol\MobEffectPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
use pocketmine\network\mcpe\protocol\PlayerActionPacket;
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\ResourcePackChunkDataPacket;
use pocketmine\network\mcpe\protocol\ResourcePackChunkRequestPacket;
use pocketmine\network\mcpe\protocol\ResourcePackClientResponsePacket;
use pocketmine\network\mcpe\protocol\ResourcePackDataInfoPacket;
use pocketmine\network\mcpe\protocol\ResourcePacksInfoPacket;
use pocketmine\network\mcpe\protocol\ResourcePackStackPacket;
use pocketmine\network\mcpe\protocol\RespawnPacket;
use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket;
use pocketmine\network\mcpe\protocol\SetTitlePacket;
use pocketmine\network\mcpe\protocol\StartGamePacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\TransferPacket;
use pocketmine\network\mcpe\protocol\types\CommandData;
use pocketmine\network\mcpe\protocol\types\CommandEnum;
use pocketmine\network\mcpe\protocol\types\CommandParameter;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\DimensionIds;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\SkinImage;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
use pocketmine\network\mcpe\VerifyLoginTask;
use pocketmine\network\SourceInterface;
use pocketmine\permission\PermissibleBase;
use pocketmine\permission\PermissionAttachment;
use pocketmine\permission\PermissionAttachmentInfo;
use pocketmine\permission\PermissionManager;
use pocketmine\plugin\Plugin;
use pocketmine\resourcepacks\ResourcePack;
use pocketmine\tile\ItemFrame;
use pocketmine\tile\Spawnable;
use pocketmine\tile\Tile;
use pocketmine\timings\Timings;
use pocketmine\utils\TextFormat;
use pocketmine\utils\UUID;
use function abs;
use function array_merge;
use function assert;
use function base64_decode;
use function ceil;
use function count;
use function explode;
use function floor;
use function fmod;
use function get_class;
use function gettype;
use function implode;
use function in_array;
use function is_int;
use function is_object;
use function is_string;
use function json_encode;
use function json_last_error_msg;
use function lcg_value;
use function max;
use function microtime;
use function min;
use function preg_match;
use function round;
use function spl_object_hash;
use function sqrt;
use function strlen;
use function strpos;
use function strtolower;
use function substr;
use function trim;
use function ucfirst;
use const M_PI;
use const M_SQRT3;
use const PHP_INT_MAX;

/**
 * Main class that handles networking, recovery, and packet sending to the server part
 */
class Player extends Human implements CommandSender, ChunkLoader, IPlayer{

	public const SURVIVAL = 0;
	public const CREATIVE = 1;
	public const ADVENTURE = 2;
	public const SPECTATOR = 3;
	public const VIEW = Player::SPECTATOR;

	/**
	 * Validates the given username.
	 */
	public static function isValidUserName(?string $name) : bool{
		if($name === null){
			return false;
		}

		$lname = strtolower($name);
		$len = strlen($name);
		return $lname !== "rcon" and $lname !== "console" and $len >= 1 and $len <= 16 and preg_match("/[^A-Za-z0-9_ ]/", $name) === 0;
	}

	/** @var SourceInterface */
	protected $interface;

	/**
	 * @var PlayerNetworkSessionAdapter
	 * TODO: remove this once player and network are divorced properly
	 */
	protected $sessionAdapter;

	/** @var string */
	protected $ip;
	/** @var int */
	protected $port;

	/** @var bool[] */
	private $needACK = [];

	/** @var DataPacket[] */
	private $batchedPackets = [];

	/**
	 * @var int
	 * Last measurement of player's latency in milliseconds.
	 */
	protected $lastPingMeasure = 1;

	/** @var float */
	public $creationTime = 0;

	/** @var bool */
	public $loggedIn = false;

	/** @var bool */
	private $resourcePacksDone = false;

	/** @var bool */
	public $spawned = false;

	/** @var string */
	protected $username = "";
	/** @var string */
	protected $iusername = "";
	/** @var string */
	protected $displayName = "";
	/** @var int */
	protected $randomClientId;
	/** @var string */
	protected $xuid = "";

	/** @var int */
	protected $windowCnt = 2;
	/** @var int[] */
	protected $windows = [];
	/** @var Inventory[] */
	protected $windowIndex = [];
	/** @var bool[] */
	protected $permanentWindows = [];
	/** @var PlayerCursorInventory */
	protected $cursorInventory;
	/** @var CraftingGrid */
	protected $craftingGrid;
	/** @var CraftingTransaction|null */
	protected $craftingTransaction = null;

	/** @var int */
	protected $messageCounter = 2;
	/** @var bool */
	protected $removeFormat = true;

	/** @var bool[] name of achievement => bool */
	protected $achievements = [];
	/** @var bool */
	protected $playedBefore;
	/** @var int */
	protected $gamemode;

	/** @var int */
	private $loaderId = 0;
	/** @var bool[] chunkHash => bool (true = sent, false = needs sending) */
	public $usedChunks = [];
	/** @var bool[] chunkHash => dummy */
	protected $loadQueue = [];
	/** @var int */
	protected $nextChunkOrderRun = 5;

	/** @var int */
	protected $viewDistance = -1;
	/** @var int */
	protected $spawnThreshold;
	/** @var int */
	protected $spawnChunkLoadCount = 0;
	/** @var int */
	protected $chunksPerTick;

	/** @var bool[] map: raw UUID (string) => bool */
	protected $hiddenPlayers = [];

	/** @var Vector3|null */
	protected $newPosition;
	/** @var bool */
	protected $isTeleporting = false;
	/** @var int */
	protected $inAirTicks = 0;
	/** @var float */
	protected $stepHeight = 0.6;
	/** @var bool */
	protected $allowMovementCheats = false;

	/** @var Vector3|null */
	protected $sleeping = null;
	/** @var Position|null */
	private $spawnPosition = null;

	//TODO: Abilities
	/** @var bool */
	protected $autoJump = true;
	/** @var bool */
	protected $allowFlight = false;
	/** @var bool */
	protected $flying = false;

	/** @var PermissibleBase */
	private $perm;

	/** @var int|null */
	protected $lineHeight = null;
	/** @var string */
	protected $locale = "en_US";

	/** @var int */
	protected $startAction = -1;
	/** @var int[] ID => ticks map */
	protected $usedItemsCooldown = [];

	/** @var int */
	protected $formIdCounter = 0;
	/** @var Form[] */
	protected $forms = [];

	/** @var float */
	protected $lastRightClickTime = 0.0;
	/** @var Vector3|null */
	protected $lastRightClickPos = null;

	/**
	 * @return TranslationContainer|string
	 */
	public function getLeaveMessage(){
		if($this->spawned){
			return new TranslationContainer(TextFormat::YELLOW . "%multiplayer.player.left", [
				$this->getDisplayName()
			]);
		}

		return "";
	}

	/**
	 * This might disappear in the future. Please use getUniqueId() instead.
	 * @deprecated
	 *
	 * @return int
	 */
	public function getClientId(){
		return $this->randomClientId;
	}

	public function isBanned() : bool{
		return $this->server->getNameBans()->isBanned($this->username);
	}

	public function setBanned(bool $value){
		if($value){
			$this->server->getNameBans()->addBan($this->getName(), null, null, null);
			$this->kick("You have been banned");
		}else{
			$this->server->getNameBans()->remove($this->getName());
		}
	}

	public function isWhitelisted() : bool{
		return $this->server->isWhitelisted($this->username);
	}

	public function setWhitelisted(bool $value){
		if($value){
			$this->server->addWhitelist($this->username);
		}else{
			$this->server->removeWhitelist($this->username);
		}
	}

	public function isAuthenticated() : bool{
		return $this->xuid !== "";
	}

	/**
	 * If the player is logged into Xbox Live, returns their Xbox user ID (XUID) as a string. Returns an empty string if
	 * the player is not logged into Xbox Live.
	 */
	public function getXuid() : string{
		return $this->xuid;
	}

	/**
	 * Returns the player's UUID. This should be preferred over their Xbox user ID (XUID) because UUID is a standard
	 * format which will never change, and all players will have one regardless of whether they are logged into Xbox
	 * Live.
	 *
	 * The UUID is comprised of:
	 * - when logged into XBL: a hash of their XUID (and as such will not change for the lifetime of the XBL account)
	 * - when NOT logged into XBL: a hash of their name + clientID + secret device ID.
	 *
	 * WARNING: UUIDs of players **not logged into Xbox Live** CAN BE FAKED and SHOULD NOT be trusted!
	 *
	 * (In the olden days this method used to return a fake UUID computed by the server, which was used by plugins such
	 * as SimpleAuth for authentication. This is NOT SAFE anymore as this UUID is now what was given by the client, NOT
	 * a server-computed UUID.)
	 */
	public function getUniqueId() : ?UUID{
		return parent::getUniqueId();
	}

	public function getPlayer(){
		return $this;
	}

	public function getFirstPlayed(){
		return $this->namedtag->getLong("firstPlayed", 0, true);
	}

	public function getLastPlayed(){
		return $this->namedtag->getLong("lastPlayed", 0, true);
	}

	public function hasPlayedBefore() : bool{
		return $this->playedBefore;
	}

	/**
	 * @return void
	 */
	public function setAllowFlight(bool $value){
		$this->allowFlight = $value;
		$this->sendSettings();
	}

	public function getAllowFlight() : bool{
		return $this->allowFlight;
	}

	/**
	 * @return void
	 */
	public function setFlying(bool $value){
		if($this->flying !== $value){
			$this->flying = $value;
			$this->resetFallDistance();
			$this->sendSettings();
		}
	}

	public function isFlying() : bool{
		return $this->flying;
	}

	/**
	 * @return void
	 */
	public function setAutoJump(bool $value){
		$this->autoJump = $value;
		$this->sendSettings();
	}

	public function hasAutoJump() : bool{
		return $this->autoJump;
	}

	public function allowMovementCheats() : bool{
		return $this->allowMovementCheats;
	}

	/**
	 * @return void
	 */
	public function setAllowMovementCheats(bool $value = true){
		$this->allowMovementCheats = $value;
	}

	public function spawnTo(Player $player) : void{
		if($this->spawned and $player->spawned and $this->isAlive() and $player->isAlive() and $player->getLevel() === $this->level and $player->canSee($this) and !$this->isSpectator()){
			parent::spawnTo($player);
		}
	}

	/**
	 * @return Server
	 */
	public function getServer(){
		return $this->server;
	}

	public function getRemoveFormat() : bool{
		return $this->removeFormat;
	}

	/**
	 * @return void
	 */
	public function setRemoveFormat(bool $remove = true){
		$this->removeFormat = $remove;
	}

	public function getScreenLineHeight() : int{
		return $this->lineHeight ?? 7;
	}

	public function setScreenLineHeight(int $height = null){
		if($height !== null and $height < 1){
			throw new \InvalidArgumentException("Line height must be at least 1");
		}
		$this->lineHeight = $height;
	}

	public function canSee(Player $player) : bool{
		return !isset($this->hiddenPlayers[$player->getRawUniqueId()]);
	}

	/**
	 * @return void
	 */
	public function hidePlayer(Player $player){
		if($player === $this){
			return;
		}
		$this->hiddenPlayers[$player->getRawUniqueId()] = true;
		$player->despawnFrom($this);
	}

	/**
	 * @return void
	 */
	public function showPlayer(Player $player){
		if($player === $this){
			return;
		}
		unset($this->hiddenPlayers[$player->getRawUniqueId()]);
		if($player->isOnline()){
			$player->spawnTo($this);
		}
	}

	public function canCollideWith(Entity $entity) : bool{
		return false;
	}

	public function canBeCollidedWith() : bool{
		return !$this->isSpectator() and parent::canBeCollidedWith();
	}

	public function resetFallDistance() : void{
		parent::resetFallDistance();
		$this->inAirTicks = 0;
	}

	public function getViewDistance() : int{
		return $this->viewDistance;
	}

	/**
	 * @return void
	 */
	public function setViewDistance(int $distance){
		$this->viewDistance = $this->server->getAllowedViewDistance($distance);

		$this->spawnThreshold = (int) (min($this->viewDistance, $this->server->getProperty("chunk-sending.spawn-radius", 4)) ** 2 * M_PI);

		$this->nextChunkOrderRun = 0;

		$pk = new ChunkRadiusUpdatedPacket();
		$pk->radius = $this->viewDistance;
		$this->dataPacket($pk);

		$this->server->getLogger()->debug("Setting view distance for " . $this->getName() . " to " . $this->viewDistance . " (requested " . $distance . ")");
	}

	public function isOnline() : bool{
		return $this->isConnected() and $this->loggedIn;
	}

	public function isOp() : bool{
		return $this->server->isOp($this->getName());
	}

	/**
	 * @return void
	 */
	public function setOp(bool $value){
		if($value === $this->isOp()){
			return;
		}

		if($value){
			$this->server->addOp($this->getName());
		}else{
			$this->server->removeOp($this->getName());
		}

		$this->sendSettings();
	}

	/**
	 * @param permission\Permission|string $name
	 */
	public function isPermissionSet($name) : bool{
		return $this->perm->isPermissionSet($name);
	}

	/**
	 * @param permission\Permission|string $name
	 *
	 * @throws \InvalidStateException if the player is closed
	 */
	public function hasPermission($name) : bool{
		if($this->closed){
			throw new \InvalidStateException("Trying to get permissions of closed player");
		}
		return $this->perm->hasPermission($name);
	}

	public function addAttachment(Plugin $plugin, string $name = null, bool $value = null) : PermissionAttachment{
		return $this->perm->addAttachment($plugin, $name, $value);
	}

	/**
	 * @return void
	 */
	public function removeAttachment(PermissionAttachment $attachment){
		$this->perm->removeAttachment($attachment);
	}

	public function recalculatePermissions(){
		$permManager = PermissionManager::getInstance();
		$permManager->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this);
		$permManager->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);

		if($this->perm === null){
			return;
		}

		$this->perm->recalculatePermissions();

		if($this->spawned){
			if($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)){
				$permManager->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this);
			}
			if($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)){
				$permManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);
			}

			$this->sendCommandData();
		}
	}

	/**
	 * @return PermissionAttachmentInfo[]
	 */
	public function getEffectivePermissions() : array{
		return $this->perm->getEffectivePermissions();
	}

	/**
	 * @return void
	 */
	public function sendCommandData(){
		$pk = new AvailableCommandsPacket();
		foreach($this->server->getCommandMap()->getCommands() as $name => $command){
			if(isset($pk->commandData[$command->getName()]) or $command->getName() === "help" or !$command->testPermissionSilent($this)){
				continue;
			}

			$data = new CommandData();
			//TODO: commands containing uppercase letters in the name crash 1.9.0 client
			$data->commandName = strtolower($command->getName());
			$data->commandDescription = $this->server->getLanguage()->translateString($command->getDescription());
			$data->flags = 0;
			$data->permission = 0;

			$parameter = new CommandParameter();
			$parameter->paramName = "args";
			$parameter->paramType = AvailableCommandsPacket::ARG_FLAG_VALID | AvailableCommandsPacket::ARG_TYPE_RAWTEXT;
			$parameter->isOptional = true;
			$data->overloads[0][0] = $parameter;

			$aliases = $command->getAliases();
			if(count($aliases) > 0){
				if(!in_array($data->commandName, $aliases, true)){
					//work around a client bug which makes the original name not show when aliases are used
					$aliases[] = $data->commandName;
				}
				$data->aliases = new CommandEnum();
				$data->aliases->enumName = ucfirst($command->getName()) . "Aliases";
				$data->aliases->enumValues = $aliases;
			}

			$pk->commandData[$command->getName()] = $data;
		}

		$this->dataPacket($pk);

	}

	public function __construct(SourceInterface $interface, string $ip, int $port){
		$this->interface = $interface;
		$this->perm = new PermissibleBase($this);
		$this->namedtag = new CompoundTag();
		$this->server = Server::getInstance();
		$this->ip = $ip;
		$this->port = $port;
		$this->loaderId = Level::generateChunkLoaderId($this);
		$this->chunksPerTick = (int) $this->server->getProperty("chunk-sending.per-tick", 4);
		$this->spawnThreshold = (int) (($this->server->getProperty("chunk-sending.spawn-radius", 4) ** 2) * M_PI);
		$this->gamemode = $this->server->getGamemode();
		$this->setLevel($this->server->getDefaultLevel());
		$this->boundingBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0);

		$this->creationTime = microtime(true);

		$this->allowMovementCheats = (bool) $this->server->getProperty("player.anti-cheat.allow-movement-cheats", false);

		$this->sessionAdapter = new PlayerNetworkSessionAdapter($this->server, $this);
	}

	public function isConnected() : bool{
		return $this->sessionAdapter !== null;
	}

	/**
	 * Gets the username
	 */
	public function getName() : string{
		return $this->username;
	}

	public function getLowerCaseName() : string{
		return $this->iusername;
	}

	/**
	 * Returns the "friendly" display name of this player to use in the chat.
	 */
	public function getDisplayName() : string{
		return $this->displayName;
	}

	/**
	 * @return void
	 */
	public function setDisplayName(string $name){
		$this->displayName = $name;
		if($this->spawned){
			$this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getDisplayName(), $this->getSkin(), $this->getXuid());
		}
	}

	/**
	 * Returns the player's locale, e.g. en_US.
	 */
	public function getLocale() : string{
		return $this->locale;
	}

	/**
	 * Called when a player changes their skin.
	 * Plugin developers should not use this, use setSkin() and sendSkin() instead.
	 */
	public function changeSkin(Skin $skin, string $newSkinName, string $oldSkinName) : bool{
		if(!$skin->isValid()){
			return false;
		}

		$ev = new PlayerChangeSkinEvent($this, $this->getSkin(), $skin);
		$ev->call();

		if($ev->isCancelled()){
			$this->sendSkin([$this]);
			return true;
		}

		$this->setSkin($ev->getNewSkin());
		$this->sendSkin($this->server->getOnlinePlayers());
		return true;
	}

	/**
	 * {@inheritdoc}
	 *
	 * If null is given, will additionally send the skin to the player itself as well as its viewers.
	 */
	public function sendSkin(?array $targets = null) : void{
		parent::sendSkin($targets ?? $this->server->getOnlinePlayers());
	}

	/**
	 * Gets the player IP address
	 */
	public function getAddress() : string{
		return $this->ip;
	}

	public function getPort() : int{
		return $this->port;
	}

	/**
	 * Returns the last measured latency for this player, in milliseconds. This is measured automatically and reported
	 * back by the network interface.
	 */
	public function getPing() : int{
		return $this->lastPingMeasure;
	}

	/**
	 * Updates the player's last ping measurement.
	 *
	 * @internal Plugins should not use this method.
	 *
	 * @return void
	 */
	public function updatePing(int $pingMS){
		$this->lastPingMeasure = $pingMS;
	}

	public function getNextPosition() : Position{
		return $this->newPosition !== null ? Position::fromObject($this->newPosition, $this->level) : $this->getPosition();
	}

	public function getInAirTicks() : int{
		return $this->inAirTicks;
	}

	/**
	 * Returns whether the player is currently using an item (right-click and hold).
	 */
	public function isUsingItem() : bool{
		return $this->getGenericFlag(self::DATA_FLAG_ACTION) and $this->startAction > -1;
	}

	/**
	 * @return void
	 */
	public function setUsingItem(bool $value){
		$this->startAction = $value ? $this->server->getTick() : -1;
		$this->setGenericFlag(self::DATA_FLAG_ACTION, $value);
	}

	/**
	 * Returns how long the player has been using their currently-held item for. Used for determining arrow shoot force
	 * for bows.
	 */
	public function getItemUseDuration() : int{
		return $this->startAction === -1 ? -1 : ($this->server->getTick() - $this->startAction);
	}

	/**
	 * Returns whether the player has a cooldown period left before it can use the given item again.
	 */
	public function hasItemCooldown(Item $item) : bool{
		$this->checkItemCooldowns();
		return isset($this->usedItemsCooldown[$item->getId()]);
	}

	/**
	 * Resets the player's cooldown time for the given item back to the maximum.
	 */
	public function resetItemCooldown(Item $item) : void{
		$ticks = $item->getCooldownTicks();
		if($ticks > 0){
			$this->usedItemsCooldown[$item->getId()] = $this->server->getTick() + $ticks;
		}
	}

	protected function checkItemCooldowns() : void{
		$serverTick = $this->server->getTick();
		foreach($this->usedItemsCooldown as $itemId => $cooldownUntil){
			if($cooldownUntil <= $serverTick){
				unset($this->usedItemsCooldown[$itemId]);
			}
		}
	}

	protected function switchLevel(Level $targetLevel) : bool{
		$oldLevel = $this->level;
		if(parent::switchLevel($targetLevel)){
			if($oldLevel !== null){
				foreach($this->usedChunks as $index => $d){
					 $X = ($index >> 32);  $Z = ($index & 0xFFFFFFFF) << 32 >> 32;
					$this->unloadChunk($X, $Z, $oldLevel);
				}
			}

			$this->usedChunks = [];
			$this->loadQueue = [];
			$this->level->sendTime($this);
			$this->level->sendDifficulty($this);

			return true;
		}

		return false;
	}

	/**
	 * @return void
	 */
	protected function unloadChunk(int $x, int $z, Level $level = null){
		$level = $level ?? $this->level;
		$index = ((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF);
		if(isset($this->usedChunks[$index])){
			foreach($level->getChunkEntities($x, $z) as $entity){
				if($entity !== $this){
					$entity->despawnFrom($this);
				}
			}

			unset($this->usedChunks[$index]);
		}
		$level->unregisterChunkLoader($this, $x, $z);
		unset($this->loadQueue[$index]);
	}

	/**
	 * @return void
	 */
	public function sendChunk(int $x, int $z, BatchPacket $payload){
		if(!$this->isConnected()){
			return;
		}

		$this->usedChunks[((($x) & 0xFFFFFFFF) << 32) | (( $z) & 0xFFFFFFFF)] = true;
		$this->dataPacket($payload);

		if($this->spawned){
			foreach($this->level->getChunkEntities($x, $z) as $entity){
				if($entity !== $this and !$entity->isClosed() and $entity->isAlive()){
					$entity->spawnTo($this);
				}
			}
		}

		if($this->spawnChunkLoadCount !== -1 and ++$this->spawnChunkLoadCount >= $this->spawnThreshold){
			$this->sendPlayStatus(PlayStatusPacket::PLAYER_SPAWN);
			$this->spawnChunkLoadCount = -1;
		}
	}

	/**
	 * @return void
	 */
	protected function sendNextChunk(){
		if(!$this->isConnected()){
			return;
		}

		Timings::$playerChunkSendTimer->startTiming();

		$count = 0;
		foreach($this->loadQueue as $index => $distance){
			if($count >= $this->chunksPerTick){
				break;
			}

			$X = null;
			$Z = null;
			 $X = ($index >> 32);  $Z = ($index & 0xFFFFFFFF) << 32 >> 32;
			assert(is_int($X) and is_int($Z));

			++$count;

			$this->usedChunks[$index] = false;
			$this->level->registerChunkLoader($this, $X, $Z, false);

			if(!$this->level->populateChunk($X, $Z)){
				continue;
			}

			unset($this->loadQueue[$index]);
			$this->level->requestChunk($X, $Z, $this);
		}

		Timings::$playerChunkSendTimer->stopTiming();
	}

	/**
	 * @return void
	 */
	public function doFirstSpawn(){
		if($this->spawned){
			return; //avoid player spawning twice (this can only happen on 3.x with a custom malicious client)
		}
		$this->spawned = true;
		$this->setImmobile(false);

		if($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)){
			PermissionManager::getInstance()->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this);
		}
		if($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)){
			PermissionManager::getInstance()->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);
		}

		$ev = new PlayerJoinEvent($this,
			new TranslationContainer(TextFormat::YELLOW . "%multiplayer.player.joined", [
				$this->getDisplayName()
			])
		);
		$ev->call();
		if(strlen(trim((string) $ev->getJoinMessage())) > 0){
			$this->server->broadcastMessage($ev->getJoinMessage());
		}

		$this->noDamageTicks = 60;

		foreach($this->usedChunks as $index => $hasSent){
			if(!$hasSent){
				continue; //this will happen when the chunk is ready to send
			}
			 $chunkX = ($index >> 32);  $chunkZ = ($index & 0xFFFFFFFF) << 32 >> 32;
			foreach($this->level->getChunkEntities($chunkX, $chunkZ) as $entity){
				if($entity !== $this and !$entity->isClosed() and $entity->isAlive() and !$entity->isFlaggedForDespawn()){
					$entity->spawnTo($this);
				}
			}
		}

		$this->spawnToAll();

		if($this->server->getUpdater()->hasUpdate() and $this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE) and $this->server->getProperty("auto-updater.on-update.warn-ops", true)){
			$this->server->getUpdater()->showPlayerUpdate($this);
		}

		if($this->getHealth() <= 0){
			$this->respawn();
		}
	}

	/**
	 * @return void
	 */
	protected function sendRespawnPacket(Vector3 $pos, int $respawnState = RespawnPacket::SEARCHING_FOR_SPAWN){
		$pk = new RespawnPacket();
		$pk->position = $pos->add(0, $this->baseOffset, 0);
		$pk->respawnState = $respawnState;
		$pk->entityRuntimeId = $this->getId();

		$this->dataPacket($pk);
	}

	protected function orderChunks() : void{
		if(!$this->isConnected() or $this->viewDistance === -1){
			return;
		}

		Timings::$playerChunkOrderTimer->startTiming();

		$radius = $this->server->getAllowedViewDistance($this->viewDistance);
		$radiusSquared = $radius ** 2;

		$newOrder = [];
		$unloadChunks = $this->usedChunks;

		$centerX = $this->getFloorX() >> 4;
		$centerZ = $this->getFloorZ() >> 4;

		for($x = 0; $x < $radius; ++$x){
			for($z = 0; $z <= $x; ++$z){
				if(($x ** 2 + $z ** 2) > $radiusSquared){
					break; //skip to next band
				}

				//If the chunk is in the radius, others at the same offsets in different quadrants are also guaranteed to be.

				/* Top right quadrant */
				if(!isset($this->usedChunks[$index = ((($centerX + $x) & 0xFFFFFFFF) << 32) | (( $centerZ + $z) & 0xFFFFFFFF)]) or $this->usedChunks[$index] === false){
					$newOrder[$index] = true;
				}
				unset($unloadChunks[$index]);

				/* Top left quadrant */
				if(!isset($this->usedChunks[$index = ((($centerX - $x - 1) & 0xFFFFFFFF) << 32) | (( $centerZ + $z) & 0xFFFFFFFF)]) or $this->usedChunks[$index] === false){
					$newOrder[$index] = true;
				}
				unset($unloadChunks[$index]);

				/* Bottom right quadrant */
				if(!isset($this->usedChunks[$index = ((($centerX + $x) & 0xFFFFFFFF) << 32) | (( $centerZ - $z - 1) & 0xFFFFFFFF)]) or $this->usedChunks[$index] === false){
					$newOrder[$index] = true;
				}
				unset($unloadChunks[$index]);

				/* Bottom left quadrant */
				if(!isset($this->usedChunks[$index = ((($centerX - $x - 1) & 0xFFFFFFFF) << 32) | (( $centerZ - $z - 1) & 0xFFFFFFFF)]) or $this->usedChunks[$index] === false){
					$newOrder[$index] = true;
				}
				unset($unloadChunks[$index]);

				if($x !== $z){
					/* Top right quadrant mirror */
					if(!isset($this->usedChunks[$index = ((($centerX + $z) & 0xFFFFFFFF) << 32) | (( $centerZ + $x) & 0xFFFFFFFF)]) or $this->usedChunks[$index] === false){
						$newOrder[$index] = true;
					}
					unset($unloadChunks[$index]);

					/* Top left quadrant mirror */
					if(!isset($this->usedChunks[$index = ((($centerX - $z - 1) & 0xFFFFFFFF) << 32) | (( $centerZ + $x) & 0xFFFFFFFF)]) or $this->usedChunks[$index] === false){
						$newOrder[$index] = true;
					}
					unset($unloadChunks[$index]);

					/* Bottom right quadrant mirror */
					if(!isset($this->usedChunks[$index = ((($centerX + $z) & 0xFFFFFFFF) << 32) | (( $centerZ - $x - 1) & 0xFFFFFFFF)]) or $this->usedChunks[$index] === false){
						$newOrder[$index] = true;
					}
					unset($unloadChunks[$index]);

					/* Bottom left quadrant mirror */
					if(!isset($this->usedChunks[$index = ((($centerX - $z - 1) & 0xFFFFFFFF) << 32) | (( $centerZ - $x - 1) & 0xFFFFFFFF)]) or $this->usedChunks[$index] === false){
						$newOrder[$index] = true;
					}
					unset($unloadChunks[$index]);
				}
			}
		}

		foreach($unloadChunks as $index => $bool){
			 $X = ($index >> 32);  $Z = ($index & 0xFFFFFFFF) << 32 >> 32;
			$this->unloadChunk($X, $Z);
		}

		$this->loadQueue = $newOrder;
		if(count($this->loadQueue) > 0 or count($unloadChunks) > 0){
			$pk = new NetworkChunkPublisherUpdatePacket();
			$pk->x = $this->getFloorX();
			$pk->y = $this->getFloorY();
			$pk->z = $this->getFloorZ();
			$pk->radius = $this->viewDistance * 16; //blocks, not chunks >.>
			$this->dataPacket($pk);
		}

		Timings::$playerChunkOrderTimer->stopTiming();
	}

	/**
	 * @return Position
	 */
	public function getSpawn(){
		if($this->hasValidSpawnPosition()){
			return $this->spawnPosition;
		}else{
			$level = $this->server->getDefaultLevel();

			return $level->getSafeSpawn();
		}
	}

	public function hasValidSpawnPosition() : bool{
		return $this->spawnPosition !== null and $this->spawnPosition->isValid();
	}

	/**
	 * Sets the spawnpoint of the player (and the compass direction) to a Vector3, or set it on another world with a
	 * Position object
	 *
	 * @param Vector3|Position $pos
	 *
	 * @return void
	 */
	public function setSpawn(Vector3 $pos){
		if(!($pos instanceof Position)){
			$level = $this->level;
		}else{
			$level = $pos->getLevel();
		}
		$this->spawnPosition = new Position($pos->x, $pos->y, $pos->z, $level);
		$pk = new SetSpawnPositionPacket();
		$pk->x = $this->spawnPosition->getFloorX();
		$pk->y = $this->spawnPosition->getFloorY();
		$pk->z = $this->spawnPosition->getFloorZ();
		$pk->spawnType = SetSpawnPositionPacket::TYPE_PLAYER_SPAWN;
		$pk->spawnForced = false;
		$this->dataPacket($pk);
	}

	public function isSleeping() : bool{
		return $this->sleeping !== null;
	}

	public function sleepOn(Vector3 $pos) : bool{
		if(!$this->isOnline()){
			return false;
		}

		$pos = $pos->floor();
		$b = $this->level->getBlock($pos);

		$ev = new PlayerBedEnterEvent($this, $b);
		$ev->call();
		if($ev->isCancelled()){
			return false;
		}

		if($b instanceof Bed){
			$b->setOccupied();
		}

		$this->sleeping = clone $pos;

		$this->propertyManager->setBlockPos(self::DATA_PLAYER_BED_POSITION, $pos);
		$this->setPlayerFlag(self::DATA_PLAYER_FLAG_SLEEP, true);

		$this->setSpawn($pos);

		$this->level->setSleepTicks(60);

		return true;
	}

	/**
	 * @return void
	 */
	public function stopSleep(){
		if($this->sleeping instanceof Vector3){
			$b = $this->level->getBlock($this->sleeping);
			if($b instanceof Bed){
				$b->setOccupied(false);
			}
			(new PlayerBedLeaveEvent($this, $b))->call();

			$this->sleeping = null;
			$this->propertyManager->setBlockPos(self::DATA_PLAYER_BED_POSITION, null);
			$this->setPlayerFlag(self::DATA_PLAYER_FLAG_SLEEP, false);

			$this->level->setSleepTicks(0);

			$pk = new AnimatePacket();
			$pk->entityRuntimeId = $this->id;
			$pk->action = AnimatePacket::ACTION_STOP_SLEEP;
			$this->dataPacket($pk);
		}
	}

	public function hasAchievement(string $achievementId) : bool{
		if(!isset(Achievement::$list[$achievementId])){
			return false;
		}

		return $this->achievements[$achievementId] ?? false;
	}

	public function awardAchievement(string $achievementId) : bool{
		if(isset(Achievement::$list[$achievementId]) and !$this->hasAchievement($achievementId)){
			foreach(Achievement::$list[$achievementId]["requires"] as $requirementId){
				if(!$this->hasAchievement($requirementId)){
					return false;
				}
			}
			$ev = new PlayerAchievementAwardedEvent($this, $achievementId);
			$ev->call();
			if(!$ev->isCancelled()){
				$this->achievements[$achievementId] = true;
				Achievement::broadcast($this, $achievementId);

				return true;
			}else{
				return false;
			}
		}

		return false;
	}

	/**
	 * @return void
	 */
	public function removeAchievement(string $achievementId){
		if($this->hasAchievement($achievementId)){
			$this->achievements[$achievementId] = false;
		}
	}

	public function getGamemode() : int{
		return $this->gamemode;
	}

	/**
	 * @internal
	 *
	 * Returns a client-friendly gamemode of the specified real gamemode
	 * This function takes care of handling gamemodes known to MCPE (as of 1.1.0.3, that includes Survival, Creative and Adventure)
	 *
	 * TODO: remove this when Spectator Mode gets added properly to MCPE
	 */
	public static function getClientFriendlyGamemode(int $gamemode) : int{
		$gamemode &= 0x03;
		if($gamemode === Player::SPECTATOR){
			return Player::CREATIVE;
		}

		return $gamemode;
	}

	/**
	 * Sets the gamemode, and if needed, kicks the Player.
	 *
	 * @param bool $client if the client made this change in their GUI
	 */
	public function setGamemode(int $gm, bool $client = false) : bool{
		if($gm < 0 or $gm > 3 or $this->gamemode === $gm){
			return false;
		}

		$ev = new PlayerGameModeChangeEvent($this, $gm);
		$ev->call();
		if($ev->isCancelled()){
			if($client){ //gamemode change by client in the GUI
				$this->sendGamemode();
			}
			return false;
		}

		$this->gamemode = $gm;

		$this->allowFlight = $this->isCreative();
		if($this->isSpectator()){
			$this->setFlying(true);
			$this->keepMovement = true;
			$this->despawnFromAll();
		}else{
			$this->keepMovement = $this->allowMovementCheats;
			if($this->isSurvival()){
				$this->setFlying(false);
			}
			$this->spawnToAll();
		}

		$this->namedtag->setInt("playerGameType", $this->gamemode);
		if(!$client){ //Gamemode changed by server, do not send for client changes
			$this->sendGamemode();
		}else{
			Command::broadcastCommandMessage($this, new TranslationContainer("commands.gamemode.success.self", [Server::getGamemodeString($gm)]));
		}

		$this->sendSettings();
		$this->inventory->sendCreativeContents();

		return true;
	}

	/**
	 * @internal
	 * Sends the player's gamemode to the client.
	 *
	 * @return void
	 */
	public function sendGamemode(){
		$pk = new SetPlayerGameTypePacket();
		$pk->gamemode = Player::getClientFriendlyGamemode($this->gamemode);
		$this->dataPacket($pk);
	}

	/**
	 * Sends all the option flags
	 *
	 * @return void
	 */
	public function sendSettings(){
		$pk = new AdventureSettingsPacket();

		$pk->setFlag(AdventureSettingsPacket::WORLD_IMMUTABLE, $this->isSpectator());
		$pk->setFlag(AdventureSettingsPacket::NO_PVP, $this->isSpectator());
		$pk->setFlag(AdventureSettingsPacket::AUTO_JUMP, $this->autoJump);
		$pk->setFlag(AdventureSettingsPacket::ALLOW_FLIGHT, $this->allowFlight);
		$pk->setFlag(AdventureSettingsPacket::NO_CLIP, $this->isSpectator());
		$pk->setFlag(AdventureSettingsPacket::FLYING, $this->flying);

		$pk->commandPermission = ($this->isOp() ? AdventureSettingsPacket::PERMISSION_OPERATOR : AdventureSettingsPacket::PERMISSION_NORMAL);
		$pk->playerPermission = ($this->isOp() ? PlayerPermissions::OPERATOR : PlayerPermissions::MEMBER);
		$pk->entityUniqueId = $this->getId();

		$this->dataPacket($pk);
	}

	/**
	 * NOTE: Because Survival and Adventure Mode share some similar behaviour, this method will also return true if the player is
	 * in Adventure Mode. Supply the $literal parameter as true to force a literal Survival Mode check.
	 *
	 * @param bool $literal whether a literal check should be performed
	 */
	public function isSurvival(bool $literal = false) : bool{
		if($literal){
			return $this->gamemode === Player::SURVIVAL;
		}else{
			return ($this->gamemode & 0x01) === 0;
		}
	}

	/**
	 * NOTE: Because Creative and Spectator Mode share some similar behaviour, this method will also return true if the player is
	 * in Spectator Mode. Supply the $literal parameter as true to force a literal Creative Mode check.
	 *
	 * @param bool $literal whether a literal check should be performed
	 */
	public function isCreative(bool $literal = false) : bool{
		if($literal){
			return $this->gamemode === Player::CREATIVE;
		}else{
			return ($this->gamemode & 0x01) === 1;
		}
	}

	/**
	 * NOTE: Because Adventure and Spectator Mode share some similar behaviour, this method will also return true if the player is
	 * in Spectator Mode. Supply the $literal parameter as true to force a literal Adventure Mode check.
	 *
	 * @param bool $literal whether a literal check should be performed
	 */
	public function isAdventure(bool $literal = false) : bool{
		if($literal){
			return $this->gamemode === Player::ADVENTURE;
		}else{
			return ($this->gamemode & 0x02) > 0;
		}
	}

	public function isSpectator() : bool{
		return $this->gamemode === Player::SPECTATOR;
	}

	public function isFireProof() : bool{
		return $this->isCreative();
	}

	public function getDrops() : array{
		if(!$this->isCreative()){
			return parent::getDrops();
		}

		return [];
	}

	public function getXpDropAmount() : int{
		if(!$this->isCreative()){
			return parent::getXpDropAmount();
		}

		return 0;
	}

	protected function checkGroundState(float $movX, float $movY, float $movZ, float $dx, float $dy, float $dz) : void{
		$bb = clone $this->boundingBox;
		$bb->minY = $this->y - 0.2;
		$bb->maxY = $this->y + 0.2;

		$this->onGround = $this->isCollided = count($this->level->getCollisionBlocks($bb, true)) > 0;
	}

	public function canBeMovedByCurrents() : bool{
		return false; //currently has no server-side movement
	}

	/**
	 * @return void
	 */
	protected function checkNearEntities(){
		foreach($this->level->getNearbyEntities($this->boundingBox->expandedCopy(1, 0.5, 1), $this) as $entity){
			$entity->scheduleUpdate();

			if(!$entity->isAlive() or $entity->isFlaggedForDespawn()){
				continue;
			}

			$entity->onCollideWithPlayer($this);
		}
	}

	/**
	 * @return void
	 */
	protected function processMovement(int $tickDiff){
		if(!$this->isAlive() or !$this->spawned or $this->newPosition === null or $this->isSleeping()){
			return;
		}

		assert($this->x !== null and $this->y !== null and $this->z !== null);
		assert($this->newPosition->x !== null and $this->newPosition->y !== null and $this->newPosition->z !== null);

		$newPos = $this->newPosition;
		$distanceSquared = $newPos->distanceSquared($this);

		$revert = false;

		if(($distanceSquared / ($tickDiff ** 2)) > 100){
			/* !!! BEWARE YE WHO ENTER HERE !!!
			 *
			 * This is NOT an anti-cheat check. It is a safety check.
			 * Without it hackers can teleport with freedom on their own and cause lots of undesirable behaviour, like
			 * freezes, lag spikes and memory exhaustion due to sync chunk loading and collision checks across large distances.
			 * Not only that, but high-latency players can trigger such behaviour innocently.
			 *
			 * If you must tamper with this code, be aware that this can cause very nasty results. Do not waste our time
			 * asking for help if you suffer the consequences of messing with this.
			 */
			$this->server->getLogger()->debug($this->getName() . " moved too fast, reverting movement");
			$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition);
			$revert = true;
		}elseif(!$this->level->isInLoadedTerrain($newPos) or !$this->level->isChunkGenerated($newPos->getFloorX() >> 4, $newPos->getFloorZ() >> 4)){
			$revert = true;
			$this->nextChunkOrderRun = 0;
		}

		if(!$revert and $distanceSquared != 0){
			$dx = $newPos->x - $this->x;
			$dy = $newPos->y - $this->y;
			$dz = $newPos->z - $this->z;

			$this->move($dx, $dy, $dz);

			$diff = $this->distanceSquared($newPos) / $tickDiff ** 2;

			if($this->isSurvival() and $diff > 0.0625){
				$ev = new PlayerIllegalMoveEvent($this, $newPos, new Vector3($this->lastX, $this->lastY, $this->lastZ));
				$ev->setCancelled($this->allowMovementCheats);

				$ev->call();

				if(!$ev->isCancelled()){
					$revert = true;
					$this->server->getLogger()->debug($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidMove", [$this->getName()]));
					$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition);
				}
			}

			if($diff > 0 and !$revert){
				$this->setPosition($newPos);
			}
		}

		$from = new Location($this->lastX, $this->lastY, $this->lastZ, $this->lastYaw, $this->lastPitch, $this->level);
		$to = $this->getLocation();

		$delta = (($this->lastX - $to->x) ** 2) + (($this->lastY - $to->y) ** 2) + (($this->lastZ - $to->z) ** 2);
		$deltaAngle = abs($this->lastYaw - $to->yaw) + abs($this->lastPitch - $to->pitch);

		if(!$revert and ($delta > 0.0001 or $deltaAngle > 1.0)){
			$this->lastX = $to->x;
			$this->lastY = $to->y;
			$this->lastZ = $to->z;

			$this->lastYaw = $to->yaw;
			$this->lastPitch = $to->pitch;

			$ev = new PlayerMoveEvent($this, $from, $to);

			$ev->call();

			if(!($revert = $ev->isCancelled())){ //Yes, this is intended
				if($to->distanceSquared($ev->getTo()) > 0.01){ //If plugins modify the destination
					$this->teleport($ev->getTo());
				}else{
					//TODO: workaround 1.14.30 bug: MoveActor(Absolute|Delta)Packet don't work on players anymore :(
					$this->sendPosition($this, $this->yaw, $this->pitch, MovePlayerPacket::MODE_NORMAL, $this->hasSpawned);

					$distance = sqrt((($from->x - $to->x) ** 2) + (($from->z - $to->z) ** 2));
					//TODO: check swimming (adds 0.015 exhaustion in MCPE)
					if($this->isSprinting()){
						$this->exhaust(0.1 * $distance, PlayerExhaustEvent::CAUSE_SPRINTING);
					}else{
						$this->exhaust(0.01 * $distance, PlayerExhaustEvent::CAUSE_WALKING);
					}
				}
			}
		}

		if($revert){

			$this->lastX = $from->x;
			$this->lastY = $from->y;
			$this->lastZ = $from->z;

			$this->lastYaw = $from->yaw;
			$this->lastPitch = $from->pitch;

			$this->setPosition($from);
			$this->sendPosition($from, $from->yaw, $from->pitch, MovePlayerPacket::MODE_RESET);
		}else{
			if($distanceSquared != 0 and $this->nextChunkOrderRun > 20){
				$this->nextChunkOrderRun = 20;
			}
		}

		$this->newPosition = null;
	}

	public function fall(float $fallDistance) : void{
		if(!$this->flying){
			parent::fall($fallDistance);
		}
	}

	public function jump() : void{
		(new PlayerJumpEvent($this))->call();
		parent::jump();
	}

	public function setMotion(Vector3 $motion) : bool{
		if(parent::setMotion($motion)){
			$this->broadcastMotion();

			return true;
		}
		return false;
	}

	protected function updateMovement(bool $teleport = false) : void{

	}

	protected function tryChangeMovement() : void{

	}

	/**
	 * @return void
	 */
	public function sendAttributes(bool $sendAll = false){
		$entries = $sendAll ? $this->attributeMap->getAll() : $this->attributeMap->needSend();
		if(count($entries) > 0){
			$pk = new UpdateAttributesPacket();
			$pk->entityRuntimeId = $this->id;
			$pk->entries = $entries;
			$this->dataPacket($pk);
			foreach($entries as $entry){
				$entry->markSynchronized();
			}
		}
	}

	public function onUpdate(int $currentTick) : bool{
		if(!$this->loggedIn){
			return false;
		}

		$tickDiff = $currentTick - $this->lastUpdate;

		if($tickDiff <= 0){
			return true;
		}

		$this->messageCounter = 2;

		$this->lastUpdate = $currentTick;

		$this->sendAttributes();

		if(!$this->isAlive() and $this->spawned){
			$this->onDeathUpdate($tickDiff);
			return true;
		}

		$this->timings->startTiming();

		if($this->spawned){
			$this->processMovement($tickDiff);
			$this->motion->x = $this->motion->y = $this->motion->z = 0; //TODO: HACK! (Fixes player knockback being messed up)
			if($this->onGround){
				$this->inAirTicks = 0;
			}else{
				$this->inAirTicks += $tickDiff;
			}

			Timings::$timerEntityBaseTick->startTiming();
			$this->entityBaseTick($tickDiff);
			Timings::$timerEntityBaseTick->stopTiming();

			if(!$this->isSpectator() and $this->isAlive()){
				Timings::$playerCheckNearEntitiesTimer->startTiming();
				$this->checkNearEntities();
				Timings::$playerCheckNearEntitiesTimer->stopTiming();
			}
		}

		$this->timings->stopTiming();

		return true;
	}

	protected function doFoodTick(int $tickDiff = 1) : void{
		if($this->isSurvival()){
			parent::doFoodTick($tickDiff);
		}
	}

	public function exhaust(float $amount, int $cause = PlayerExhaustEvent::CAUSE_CUSTOM) : float{
		if($this->isSurvival()){
			return parent::exhaust($amount, $cause);
		}

		return 0.0;
	}

	public function isHungry() : bool{
		return $this->isSurvival() and parent::isHungry();
	}

	public function canBreathe() : bool{
		return $this->isCreative() or parent::canBreathe();
	}

	protected function sendEffectAdd(EffectInstance $effect, bool $replacesOldEffect) : void{
		$pk = new MobEffectPacket();
		$pk->entityRuntimeId = $this->getId();
		$pk->eventId = $replacesOldEffect ? MobEffectPacket::EVENT_MODIFY : MobEffectPacket::EVENT_ADD;
		$pk->effectId = $effect->getId();
		$pk->amplifier = $effect->getAmplifier();
		$pk->particles = $effect->isVisible();
		$pk->duration = $effect->getDuration();

		$this->dataPacket($pk);
	}

	protected function sendEffectRemove(EffectInstance $effect) : void{
		$pk = new MobEffectPacket();
		$pk->entityRuntimeId = $this->getId();
		$pk->eventId = MobEffectPacket::EVENT_REMOVE;
		$pk->effectId = $effect->getId();

		$this->dataPacket($pk);
	}

	/**
	 * @return void
	 */
	public function checkNetwork(){
		if(!$this->isOnline()){
			return;
		}

		if($this->nextChunkOrderRun !== PHP_INT_MAX and $this->nextChunkOrderRun-- <= 0){
			$this->nextChunkOrderRun = PHP_INT_MAX;
			$this->orderChunks();
		}

		if(count($this->loadQueue) > 0){
			$this->sendNextChunk();
		}

		if(count($this->batchedPackets) > 0){
			$this->server->batchPackets([$this], $this->batchedPackets, false);
			$this->batchedPackets = [];
		}
	}

	/**
	 * Returns whether the player can interact with the specified position. This checks distance and direction.
	 *
	 * @param float   $maxDiff defaults to half of the 3D diagonal width of a block
	 */
	public function canInteract(Vector3 $pos, float $maxDistance, float $maxDiff = M_SQRT3 / 2) : bool{
		$eyePos = $this->getPosition()->add(0, $this->getEyeHeight(), 0);
		if($eyePos->distanceSquared($pos) > $maxDistance ** 2){
			return false;
		}

		$dV = $this->getDirectionVector();
		$eyeDot = $dV->dot($eyePos);
		$targetDot = $dV->dot($pos);
		return ($targetDot - $eyeDot) >= -$maxDiff;
	}

	protected function initHumanData() : void{
		$this->setNameTag($this->username);
	}

	protected function initEntity() : void{
		parent::initEntity();
		$this->addDefaultWindows();
	}

	public function handleLogin(LoginPacket $packet) : bool{
		if($this->loggedIn){
			return false;
		}

		if($packet->protocol !== ProtocolInfo::CURRENT_PROTOCOL){
			if($packet->protocol < ProtocolInfo::CURRENT_PROTOCOL){
				$this->sendPlayStatus(PlayStatusPacket::LOGIN_FAILED_CLIENT, true);
			}else{
				$this->sendPlayStatus(PlayStatusPacket::LOGIN_FAILED_SERVER, true);
			}

			//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
			$this->close("", $this->server->getLanguage()->translateString("pocketmine.disconnect.incompatibleProtocol", [$packet->protocol ?? "unknown"]), false);

			return true;
		}

		if(!self::isValidUserName($packet->username)){
			$this->close("", "disconnectionScreen.invalidName");

			return true;
		}

		$this->username = TextFormat::clean($packet->username);
		$this->displayName = $this->username;
		$this->iusername = strtolower($this->username);

		if($packet->locale !== null){
			$this->locale = $packet->locale;
		}

		if(count($this->server->getOnlinePlayers()) >= $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)){
			return true;
		}

		$this->randomClientId = $packet->clientId;

		$this->uuid = UUID::fromString($packet->clientUUID);
		$this->rawUUID = $this->uuid->toBinary();

		$animations = [];
		foreach($packet->clientData["AnimatedImageData"] as $animation){
			$animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], base64_decode($animation["Image"], true)), $animation["Type"], $animation["Frames"]);
		}

		$skinData = new SkinData(
			$packet->clientData["SkinId"],
			base64_decode($packet->clientData["SkinResourcePatch"] ?? "", true),
			new SkinImage($packet->clientData["SkinImageHeight"], $packet->clientData["SkinImageWidth"], base64_decode($packet->clientData["SkinData"], true)),
			$animations,
			new SkinImage($packet->clientData["CapeImageHeight"], $packet->clientData["CapeImageWidth"], base64_decode($packet->clientData["CapeData"] ?? "", true)),
			base64_decode($packet->clientData["SkinGeometryData"] ?? "", true),
			base64_decode($packet->clientData["SkinAnimationData"] ?? "", true),
			$packet->clientData["PremiumSkin"] ?? false,
			$packet->clientData["PersonaSkin"] ?? false,
			$packet->clientData["CapeOnClassicSkin"] ?? false,
			$packet->clientData["CapeId"] ?? ""
		);

		$skin = SkinAdapterSingleton::get()->fromSkinData($skinData);

		if(!$skin->isValid()){
			$this->close("", "disconnectionScreen.invalidSkin");

			return true;
		}

		$this->setSkin($skin);

		$ev = new PlayerPreLoginEvent($this, "Plugin reason");
		$ev->call();
		if($ev->isCancelled()){
			$this->close("", $ev->getKickMessage());

			return true;
		}

		if(!$this->server->isWhitelisted($this->username) and $this->kick("Server is white-listed", false)){
			return true;
		}

		if(
			($this->isBanned() or $this->server->getIPBans()->isBanned($this->getAddress())) and
			$this->kick("You are banned", false)
		){
			return true;
		}

		if(!$packet->skipVerification){
			$this->server->getAsyncPool()->submitTask(new VerifyLoginTask($this, $packet));
		}else{
			$this->onVerifyCompleted($packet, null, true);
		}

		return true;
	}

	/**
	 * @return void
	 */
	public function sendPlayStatus(int $status, bool $immediate = false){
		$pk = new PlayStatusPacket();
		$pk->status = $status;
		$this->sendDataPacket($pk, false, $immediate);
	}

	public function onVerifyCompleted(LoginPacket $packet, ?string $error, bool $signedByMojang) : void{
		if($this->closed){
			return;
		}

		if($error !== null){
			$this->close("", $this->server->getLanguage()->translateString("pocketmine.disconnect.invalidSession", [$error]));
			return;
		}

		$xuid = $packet->xuid;

		if(!$signedByMojang and $xuid !== ""){
			$this->server->getLogger()->warning($this->getName() . " has an XUID, but their login keychain is not signed by Mojang");
			$xuid = "";
		}

		if($xuid === "" or !is_string($xuid)){
			if($signedByMojang){
				$this->server->getLogger()->error($this->getName() . " should have an XUID, but none found");
			}

			if($this->server->requiresAuthentication() and $this->kick("disconnectionScreen.notAuthenticated", false)){ //use kick to allow plugins to cancel this
				return;
			}

			$this->server->getLogger()->debug($this->getName() . " is NOT logged into Xbox Live");
		}else{
			$this->server->getLogger()->debug($this->getName() . " is logged into Xbox Live");
			$this->xuid = $xuid;
		}

		//TODO: encryption

		$this->processLogin();
	}

	/**
	 * @return void
	 */
	protected function processLogin(){
		foreach($this->server->getLoggedInPlayers() as $p){
			if($p !== $this and ($p->iusername === $this->iusername or $this->getUniqueId()->equals($p->getUniqueId()))){
				if(!$p->kick("logged in from another location")){
					$this->close($this->getLeaveMessage(), "Logged in from another location");

					return;
				}
			}
		}

		$this->namedtag = $this->server->getOfflinePlayerData($this->username);

		$this->playedBefore = ($this->getLastPlayed() - $this->getFirstPlayed()) > 1; // microtime(true) - microtime(true) may have less than one millisecond difference
		$this->namedtag->setString("NameTag", $this->username);

		$this->gamemode = $this->namedtag->getInt("playerGameType", self::SURVIVAL) & 0x03;
		if($this->server->getForceGamemode()){
			$this->gamemode = $this->server->getGamemode();
			$this->namedtag->setInt("playerGameType", $this->gamemode);
		}

		$this->allowFlight = $this->isCreative();
		$this->keepMovement = $this->isSpectator() || $this->allowMovementCheats();

		if(($level = $this->server->getLevelByName($this->namedtag->getString("Level", "", true))) === null){
			$this->setLevel($this->server->getDefaultLevel());
			$this->namedtag->setString("Level", $this->level->getFolderName());
			$spawnLocation = $this->level->getSafeSpawn();
			$this->namedtag->setTag(new ListTag("Pos", [
				new DoubleTag("", $spawnLocation->x),
				new DoubleTag("", $spawnLocation->y),
				new DoubleTag("", $spawnLocation->z)
			]));
		}else{
			$this->setLevel($level);
		}

		$this->achievements = [];

		$achievements = $this->namedtag->getCompoundTag("Achievements") ?? [];
		/** @var ByteTag $achievement */
		foreach($achievements as $achievement){
			$this->achievements[$achievement->getName()] = $achievement->getValue() !== 0;
		}

		$this->sendPlayStatus(PlayStatusPacket::LOGIN_SUCCESS);

		$this->loggedIn = true;
		$this->server->onPlayerLogin($this);

		$pk = new ResourcePacksInfoPacket();
		$manager = $this->server->getResourcePackManager();
		$pk->resourcePackEntries = $manager->getResourceStack();
		$pk->mustAccept = $manager->resourcePacksRequired();
		$this->dataPacket($pk);
	}

	public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
		if($this->resourcePacksDone){
			return false;
		}
		switch($packet->status){
			case ResourcePackClientResponsePacket::STATUS_REFUSED:
				//TODO: add lang strings for this
				$this->close("", "You must accept resource packs to join this server.", true);
				break;
			case ResourcePackClientResponsePacket::STATUS_SEND_PACKS:
				$manager = $this->server->getResourcePackManager();
				foreach($packet->packIds as $uuid){
					//dirty hack for mojang's dirty hack for versions
					$splitPos = strpos($uuid, "_");
					if($splitPos !== false){
						$uuid = substr($uuid, 0, $splitPos);
					}

					$pack = $manager->getPackById($uuid);
					if(!($pack instanceof ResourcePack)){
						//Client requested a resource pack but we don't have it available on the server
						$this->close("", "disconnectionScreen.resourcePack", true);
						$this->server->getLogger()->debug("Got a resource pack request for unknown pack with UUID " . $uuid . ", available packs: " . implode(", ", $manager->getPackIdList()));

						return false;
					}

					$pk = new ResourcePackDataInfoPacket();
					$pk->packId = $pack->getPackId();
					$pk->maxChunkSize = 1048576; //1MB
					$pk->chunkCount = (int) ceil($pack->getPackSize() / $pk->maxChunkSize);
					$pk->compressedPackSize = $pack->getPackSize();
					$pk->sha256 = $pack->getSha256();
					$this->dataPacket($pk);
				}

				break;
			case ResourcePackClientResponsePacket::STATUS_HAVE_ALL_PACKS:
				$pk = new ResourcePackStackPacket();
				$manager = $this->server->getResourcePackManager();
				$pk->resourcePackStack = $manager->getResourceStack();
				//we don't force here, because it doesn't have user-facing effects
				//but it does have an annoying side-effect when true: it makes
				//the client remove its own non-server-supplied resource packs.
				$pk->mustAccept = false;
				$this->dataPacket($pk);
				break;
			case ResourcePackClientResponsePacket::STATUS_COMPLETED:
				$this->resourcePacksDone = true;
				$this->completeLoginSequence();
				break;
			default:
				return false;
		}

		return true;
	}

	/**
	 * @return void
	 */
	protected function completeLoginSequence(){
		/** @var float[] $pos */
		$pos = $this->namedtag->getListTag("Pos")->getAllValues();
		$this->level->registerChunkLoader($this, ((int) floor($pos[0])) >> 4, ((int) floor($pos[2])) >> 4, true);
		$this->usedChunks[(((((int) floor($pos[0])) >> 4) & 0xFFFFFFFF) << 32) | (( ((int) floor($pos[2])) >> 4) & 0xFFFFFFFF)] = false;

		parent::__construct($this->level, $this->namedtag);
		$ev = new PlayerLoginEvent($this, "Plugin reason");
		$ev->call();
		if($ev->isCancelled()){
			$this->close($this->getLeaveMessage(), $ev->getKickMessage());

			return;
		}

		if(!$this->hasValidSpawnPosition()){
			if(($level = $this->server->getLevelByName($this->namedtag->getString("SpawnLevel", ""))) instanceof Level){
				$this->spawnPosition = new Position($this->namedtag->getInt("SpawnX"), $this->namedtag->getInt("SpawnY"), $this->namedtag->getInt("SpawnZ"), $level);
			}else{
				$this->spawnPosition = $this->level->getSafeSpawn();
			}
		}

		$spawnPosition = $this->getSpawn();

		$pk = new StartGamePacket();
		$pk->entityUniqueId = $this->id;
		$pk->entityRuntimeId = $this->id;
		$pk->playerGamemode = Player::getClientFriendlyGamemode($this->gamemode);

		$pk->playerPosition = $this->getOffsetPosition($this);

		$pk->pitch = $this->pitch;
		$pk->yaw = $this->yaw;
		$pk->seed = -1;
		$pk->dimension = DimensionIds::OVERWORLD; //TODO: implement this properly
		$pk->worldGamemode = Player::getClientFriendlyGamemode($this->server->getGamemode());
		$pk->difficulty = $this->level->getDifficulty();
		$pk->spawnX = $spawnPosition->getFloorX();
		$pk->spawnY = $spawnPosition->getFloorY();
		$pk->spawnZ = $spawnPosition->getFloorZ();
		$pk->hasAchievementsDisabled = true;
		$pk->time = $this->level->getTime();
		$pk->eduEditionOffer = 0;
		$pk->rainLevel = 0; //TODO: implement these properly
		$pk->lightningLevel = 0;
		$pk->commandsEnabled = true;
		$pk->levelId = "";
		$pk->worldName = $this->server->getMotd();
		$this->dataPacket($pk);

		$this->sendDataPacket(new AvailableActorIdentifiersPacket());
		$this->sendDataPacket(new BiomeDefinitionListPacket());

		$this->level->sendTime($this);

		$this->sendAttributes(true);
		$this->setNameTagVisible();
		$this->setNameTagAlwaysVisible();
		$this->setCanClimb();
		$this->setImmobile(); //disable pre-spawn movement

		$this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logIn", [
			TextFormat::AQUA . $this->username . TextFormat::WHITE,
			$this->ip,
			$this->port,
			$this->id,
			$this->level->getName(),
			round($this->x, 4),
			round($this->y, 4),
			round($this->z, 4)
		]));

		if($this->isOp()){
			$this->setRemoveFormat(false);
		}

		$this->sendCommandData();
		$this->sendSettings();
		$this->sendPotionEffects($this);
		$this->sendData($this);

		$this->sendAllInventories();
		$this->inventory->sendCreativeContents();
		$this->inventory->sendHeldItem($this);
		$this->dataPacket($this->server->getCraftingManager()->getCraftingDataPacket());

		$this->server->addOnlinePlayer($this);
		$this->server->sendFullPlayerListData($this);
	}

	/**
	 * Sends a chat message as this player. If the message begins with a / (forward-slash) it will be treated
	 * as a command.
	 */
	public function chat(string $message) : bool{
		if(!$this->spawned or !$this->isAlive()){
			return false;
		}

		$this->doCloseInventory();

		$message = TextFormat::clean($message, $this->removeFormat);
		foreach(explode("\n", $message) as $messagePart){
			if(trim($messagePart) !== "" and strlen($messagePart) <= 255 and $this->messageCounter-- > 0){
				if(strpos($messagePart, './') === 0){
					$messagePart = substr($messagePart, 1);
				}

				$ev = new PlayerCommandPreprocessEvent($this, $messagePart);
				$ev->call();

				if($ev->isCancelled()){
					break;
				}

				if(strpos($ev->getMessage(), "/") === 0){
					Timings::$playerCommandTimer->startTiming();
					$this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 1));
					Timings::$playerCommandTimer->stopTiming();
				}else{
					$ev = new PlayerChatEvent($this, $ev->getMessage());
					$ev->call();
					if(!$ev->isCancelled()){
						$this->server->broadcastMessage($this->getServer()->getLanguage()->translateString($ev->getFormat(), [$ev->getPlayer()->getDisplayName(), $ev->getMessage()]), $ev->getRecipients());
					}
				}
			}
		}

		return true;
	}

	public function handleMovePlayer(MovePlayerPacket $packet) : bool{
		$newPos = $packet->position->subtract(0, $this->baseOffset, 0);

		if($this->isTeleporting and $newPos->distanceSquared($this) > 1){  //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
			$this->sendPosition($this, null, null, MovePlayerPacket::MODE_RESET);
			$this->server->getLogger()->debug("Got outdated pre-teleport movement from " . $this->getName() . ", received " . $newPos . ", expected " . $this->asVector3());
			//Still getting movements from before teleport, ignore them
		}elseif((!$this->isAlive() or !$this->spawned) and $newPos->distanceSquared($this) > 0.01){
			$this->sendPosition($this, null, null, MovePlayerPacket::MODE_RESET);
			$this->server->getLogger()->debug("Reverted movement of " . $this->getName() . " due to not alive or not spawned, received " . $newPos . ", locked at " . $this->asVector3());
		}else{
			// Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock
			if($this->isTeleporting){
				$this->isTeleporting = false;
			}

			$packet->yaw = fmod($packet->yaw, 360);
			$packet->pitch = fmod($packet->pitch, 360);

			if($packet->yaw < 0){
				$packet->yaw += 360;
			}

			$this->setRotation($packet->yaw, $packet->pitch);
			$this->newPosition = $newPos;
		}

		return true;
	}

	public function handleLevelSoundEvent(LevelSoundEventPacket $packet) : bool{
		//TODO: add events so plugins can change this
		$this->getLevel()->broadcastPacketToViewers($this, $packet);
		return true;
	}

	public function handleEntityEvent(ActorEventPacket $packet) : bool{
		if(!$this->spawned or !$this->isAlive()){
			return true;
		}
		$this->doCloseInventory();

		switch($packet->event){
			case ActorEventPacket::EATING_ITEM:
				if($packet->data === 0){
					return false;
				}

				$this->dataPacket($packet);
				$this->server->broadcastPacket($this->getViewers(), $packet);
				break;
			default:
				return false;
		}

		return true;
	}

	/**
	 * Don't expect much from this handler. Most of it is roughly hacked and duct-taped together.
	 */
	public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
		if(!$this->spawned or !$this->isAlive()){
			return false;
		}

		if($this->isSpectator()){
			$this->sendAllInventories();
			return true;
		}

		/** @var InventoryAction[] $actions */
		$actions = [];
		foreach($packet->actions as $networkInventoryAction){
			try{
				$action = $networkInventoryAction->createInventoryAction($this);
				if($action !== null){
					$actions[] = $action;
				}
			}catch(\UnexpectedValueException $e){
				$this->server->getLogger()->debug("Unhandled inventory action from " . $this->getName() . ": " . $e->getMessage());
				$this->sendAllInventories();
				return false;
			}
		}

		if($packet->isCraftingPart){
			if($this->craftingTransaction === null){
				$this->craftingTransaction = new CraftingTransaction($this, $actions);
			}else{
				foreach($actions as $action){
					$this->craftingTransaction->addAction($action);
				}
			}

			if($packet->isFinalCraftingPart){
				//we get the actions for this in several packets, so we need to wait until we have all the pieces before
				//trying to execute it

				$ret = true;
				try{
					$this->craftingTransaction->execute();
				}catch(TransactionValidationException $e){
					$this->server->getLogger()->debug("Failed to execute crafting transaction for " . $this->getName() . ": " . $e->getMessage());
					$ret = false;
				}

				$this->craftingTransaction = null;
				return $ret;
			}

			return true;
		}elseif($this->craftingTransaction !== null){
			$this->server->getLogger()->debug("Got unexpected normal inventory action with incomplete crafting transaction from " . $this->getName() . ", refusing to execute crafting");
			$this->craftingTransaction = null;
		}

		switch($packet->transactionType){
			case InventoryTransactionPacket::TYPE_NORMAL:
				$this->setUsingItem(false);
				$transaction = new InventoryTransaction($this, $actions);

				try{
					$transaction->execute();
				}catch(TransactionValidationException $e){
					$this->server->getLogger()->debug("Failed to execute inventory transaction from " . $this->getName() . ": " . $e->getMessage());
					$this->server->getLogger()->debug("Actions: " . json_encode($packet->actions));

					return false;
				}

				//TODO: fix achievement for getting iron from furnace

				return true;
			case InventoryTransactionPacket::TYPE_MISMATCH:
				if(count($packet->actions) > 0){
					$this->server->getLogger()->debug("Expected 0 actions for mismatch, got " . count($packet->actions) . ", " . json_encode($packet->actions));
				}
				$this->setUsingItem(false);
				$this->sendAllInventories();

				return true;
			case InventoryTransactionPacket::TYPE_USE_ITEM:
				$blockVector = new Vector3($packet->trData->x, $packet->trData->y, $packet->trData->z);
				$face = $packet->trData->face;

				$type = $packet->trData->actionType;
				switch($type){
					case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_BLOCK:
						//TODO: start hack for client spam bug
						$spamBug = ($this->lastRightClickPos !== null and
							microtime(true) - $this->lastRightClickTime < 0.1 and //100ms
							$this->lastRightClickPos->distanceSquared($packet->trData->clickPos) < 0.00001 //signature spam bug has 0 distance, but allow some error
						);
						//get rid of continued spam if the player clicks and holds right-click
						$this->lastRightClickPos = clone $packet->trData->clickPos;
						$this->lastRightClickTime = microtime(true);
						if($spamBug){
							return true;
						}
						//TODO: end hack for client spam bug

						$this->setUsingItem(false);

						if(!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13) or $this->isSpectator()){
						}elseif($this->isCreative()){
							$item = $this->inventory->getItemInHand();
							if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->clickPos, $this, true)){
								return true;
							}
						}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->itemInHand)){
							$this->inventory->sendHeldItem($this);
						}else{
							$item = $this->inventory->getItemInHand();
							$oldItem = clone $item;
							if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->clickPos, $this, true)){
								if(!$item->equalsExact($oldItem)){
									$this->inventory->setItemInHand($item);
									$this->inventory->sendHeldItem($this->hasSpawned);
								}

								return true;
							}
						}

						$this->inventory->sendHeldItem($this);

						if($blockVector->distanceSquared($this) > 10000){
							return true;
						}

						$target = $this->level->getBlock($blockVector);
						$block = $target->getSide($face);

						/** @var Block[] $blocks */
						$blocks = array_merge($target->getAllSides(), $block->getAllSides()); //getAllSides() on each of these will include $target and $block because they are next to each other

						$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);

						return true;
					case InventoryTransactionPacket::USE_ITEM_ACTION_BREAK_BLOCK:
						$this->doCloseInventory();

						$item = $this->inventory->getItemInHand();
						$oldItem = clone $item;

						if($this->canInteract($blockVector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 7) and $this->level->useBreakOn($blockVector, $item, $this, true)){
							if($this->isSurvival()){
								if(!$item->equalsExact($oldItem)){
									$this->inventory->setItemInHand($item);
									$this->inventory->sendHeldItem($this->hasSpawned);
								}

								$this->exhaust(0.025, PlayerExhaustEvent::CAUSE_MINING);
							}
							return true;
						}

						$this->inventory->sendContents($this);
						$this->inventory->sendHeldItem($this);

						$target = $this->level->getBlock($blockVector);
						/** @var Block[] $blocks */
						$blocks = $target->getAllSides();
						$blocks[] = $target;

						$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);

						foreach($blocks as $b){
							$tile = $this->level->getTile($b);
							if($tile instanceof Spawnable){
								$tile->spawnTo($this);
							}
						}

						return true;
					case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_AIR:
						if($this->isUsingItem()){
							$slot = $this->inventory->getItemInHand();
							if($slot instanceof Consumable and !($slot instanceof MaybeConsumable and !$slot->canBeConsumed())){
								$ev = new PlayerItemConsumeEvent($this, $slot);
								if($this->hasItemCooldown($slot)){
									$ev->setCancelled();
								}
								$ev->call();
								if($ev->isCancelled() or !$this->consumeObject($slot)){
									$this->inventory->sendContents($this);
									return true;
								}
								$this->resetItemCooldown($slot);
								if($this->isSurvival()){
									$slot->pop();
									$this->inventory->setItemInHand($slot);
									$this->inventory->addItem($slot->getResidue());
								}
								$this->setUsingItem(false);
							}
						}
						$directionVector = $this->getDirectionVector();

						if($this->isCreative()){
							$item = $this->inventory->getItemInHand();
						}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->itemInHand)){
							$this->inventory->sendHeldItem($this);
							return true;
						}else{
							$item = $this->inventory->getItemInHand();
						}

						$ev = new PlayerInteractEvent($this, $item, null, $directionVector, $face, PlayerInteractEvent::RIGHT_CLICK_AIR);
						if($this->hasItemCooldown($item)){
							$ev->setCancelled();
						}

						$ev->call();
						if($ev->isCancelled()){
							$this->inventory->sendHeldItem($this);
							return true;
						}

						if($item->onClickAir($this, $directionVector)){
							$this->resetItemCooldown($item);
							if($this->isSurvival()){
								$this->inventory->setItemInHand($item);
							}
						}

						$this->setUsingItem(true);

						return true;
					default:
						//unknown
						break;
				}
				break;
			case InventoryTransactionPacket::TYPE_USE_ITEM_ON_ENTITY:
				$target = $this->level->getEntity($packet->trData->entityRuntimeId);
				if($target === null){
					return false;
				}

				$type = $packet->trData->actionType;

				switch($type){
					case InventoryTransactionPacket::USE_ITEM_ON_ENTITY_ACTION_INTERACT:
						break; //TODO
					case InventoryTransactionPacket::USE_ITEM_ON_ENTITY_ACTION_ATTACK:
						if(!$target->isAlive()){
							return true;
						}
						if($target instanceof ItemEntity or $target instanceof Arrow){
							$this->kick("Attempting to attack an invalid entity");
							$this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidEntity", [$this->getName()]));
							return false;
						}

						$cancelled = false;

						$heldItem = $this->inventory->getItemInHand();

						if(!$this->canInteract($target, 8)){
							$cancelled = true;
						}elseif($target instanceof Player){
							if(!$this->server->getConfigBool("pvp")){
								$cancelled = true;
							}
						}

						$ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints());

						$meleeEnchantmentDamage = 0;
						/** @var EnchantmentInstance[] $meleeEnchantments */
						$meleeEnchantments = [];
						foreach($heldItem->getEnchantments() as $enchantment){
							$type = $enchantment->getType();
							if($type instanceof MeleeWeaponEnchantment and $type->isApplicableTo($target)){
								$meleeEnchantmentDamage += $type->getDamageBonus($enchantment->getLevel());
								$meleeEnchantments[] = $enchantment;
							}
						}
						$ev->setModifier($meleeEnchantmentDamage, EntityDamageEvent::MODIFIER_WEAPON_ENCHANTMENTS);

						if($cancelled){
							$ev->setCancelled();
						}

						if(!$this->isSprinting() and !$this->isFlying() and $this->fallDistance > 0 and !$this->hasEffect(Effect::BLINDNESS) and !$this->isUnderwater()){
							$ev->setModifier($ev->getFinalDamage() / 2, EntityDamageEvent::MODIFIER_CRITICAL);
						}

						$target->attack($ev);

						if($ev->isCancelled()){
							if($heldItem instanceof Durable and $this->isSurvival()){
								$this->inventory->sendContents($this);
							}
							return true;
						}

						if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0){
							$pk = new AnimatePacket();
							$pk->action = AnimatePacket::ACTION_CRITICAL_HIT;
							$pk->entityRuntimeId = $target->getId();
							$this->server->broadcastPacket($target->getViewers(), $pk);
							if($target instanceof Player){
								$target->dataPacket($pk);
							}
						}

						foreach($meleeEnchantments as $enchantment){
							$type = $enchantment->getType();
							assert($type instanceof MeleeWeaponEnchantment);
							$type->onPostAttack($this, $target, $enchantment->getLevel());
						}

						if($this->isAlive()){
							//reactive damage like thorns might cause us to be killed by attacking another mob, which
							//would mean we'd already have dropped the inventory by the time we reached here
							if($heldItem->onAttackEntity($target) and $this->isSurvival()){ //always fire the hook, even if we are survival
								$this->inventory->setItemInHand($heldItem);
							}

							$this->exhaust(0.3, PlayerExhaustEvent::CAUSE_ATTACK);
						}

						return true;
					default:
						break; //unknown
				}

				break;
			case InventoryTransactionPacket::TYPE_RELEASE_ITEM:
				try{
					$type = $packet->trData->actionType;
					switch($type){
						case InventoryTransactionPacket::RELEASE_ITEM_ACTION_RELEASE:
							if($this->isUsingItem()){
								$item = $this->inventory->getItemInHand();
								if($this->hasItemCooldown($item)){
									$this->inventory->sendContents($this);
									return false;
								}
								if($item->onReleaseUsing($this)){
									$this->resetItemCooldown($item);
									$this->inventory->setItemInHand($item);
								}
							}else{
								break;
							}

							return true;
						default:
							break;
					}
				}finally{
					$this->setUsingItem(false);
				}

				$this->inventory->sendContents($this);
				break;
			default:
				$this->inventory->sendContents($this);
				break;

		}

		return false; //TODO
	}

	public function handleMobEquipment(MobEquipmentPacket $packet) : bool{
		if(!$this->spawned or !$this->isAlive()){
			return true;
		}

		$item = $this->inventory->getItem($packet->hotbarSlot);

		if(!$item->equals($packet->item)){
			$this->server->getLogger()->debug("Tried to equip " . $packet->item . " but have " . $item . " in target slot");
			$this->inventory->sendContents($this);
			return false;
		}

		$this->inventory->equipItem($packet->hotbarSlot);

		$this->setUsingItem(false);

		return true;
	}

	public function handleInteract(InteractPacket $packet) : bool{
		if(!$this->spawned or !$this->isAlive()){
			return true;
		}
		if($packet->action === InteractPacket::ACTION_MOUSEOVER and $packet->target === 0){
			//TODO HACK: silence useless spam (MCPE 1.8)
			//this packet is EXPECTED to only be sent when interacting with an entity, but due to some messy Mojang
			//hacks, it also sends it when changing the held item now, which causes us to think the inventory was closed
			//when it wasn't.
			return true;
		}

		$this->doCloseInventory();

		$target = $this->level->getEntity($packet->target);
		if($target === null){
			return false;
		}

		switch($packet->action){
			case InteractPacket::ACTION_LEAVE_VEHICLE:
			case InteractPacket::ACTION_MOUSEOVER:
				break; //TODO: handle these
			default:
				$this->server->getLogger()->debug("Unhandled/unknown interaction type " . $packet->action . "received from " . $this->getName());

				return false;
		}

		return true;
	}

	public function handleBlockPickRequest(BlockPickRequestPacket $packet) : bool{
		$block = $this->level->getBlockAt($packet->blockX, $packet->blockY, $packet->blockZ);
		if($block instanceof UnknownBlock){
			return true;
		}

		$item = $block->getPickedItem();
		if($packet->addUserData){
			$tile = $this->getLevel()->getTile($block);
			if($tile instanceof Tile){
				$nbt = $tile->getCleanedNBT();
				if($nbt instanceof CompoundTag){
					$item->setCustomBlockData($nbt);
					$item->setLore(["+(DATA)"]);
				}
			}
		}

		$ev = new PlayerBlockPickEvent($this, $block, $item);
		if(!$this->isCreative(true)){
			$this->server->getLogger()->debug("Got block-pick request from " . $this->getName() . " when not in creative mode (gamemode " . $this->getGamemode() . ")");
			$ev->setCancelled();
		}

		$ev->call();
		if(!$ev->isCancelled()){
			$this->inventory->setItemInHand($ev->getResultItem());
		}

		return true;

	}

	public function handlePlayerAction(PlayerActionPacket $packet) : bool{
		if(!$this->spawned or (!$this->isAlive() and $packet->action !== PlayerActionPacket::ACTION_RESPAWN and $packet->action !== PlayerActionPacket::ACTION_DIMENSION_CHANGE_REQUEST)){
			return true;
		}

		$packet->entityRuntimeId = $this->id;
		$pos = new Vector3($packet->x, $packet->y, $packet->z);

		switch($packet->action){
			case PlayerActionPacket::ACTION_START_BREAK:
				if($pos->distanceSquared($this) > 10000){
					break;
				}

				$target = $this->level->getBlock($pos);

				$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, null, $packet->face, PlayerInteractEvent::LEFT_CLICK_BLOCK);
				if($this->level->checkSpawnProtection($this, $target)){
					$ev->setCancelled();
				}

				$ev->call();
				if($ev->isCancelled()){
					$this->inventory->sendHeldItem($this);
					break;
				}

				$block = $target->getSide($packet->face);
				if($block->getId() === Block::FIRE){
					$this->level->setBlock($block, BlockFactory::get(Block::AIR));
					break;
				}

				if(!$this->isCreative()){
					//TODO: improve this to take stuff like swimming, ladders, enchanted tools into account, fix wrong tool break time calculations for bad tools (pmmp/PocketMine-MP#211)
					$breakTime = ceil($target->getBreakTime($this->inventory->getItemInHand()) * 20);
					if($breakTime > 0){
						$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_BLOCK_START_BREAK, (int) (65535 / $breakTime));
					}
				}

				break;

			case PlayerActionPacket::ACTION_ABORT_BREAK:
			case PlayerActionPacket::ACTION_STOP_BREAK:
				$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_BLOCK_STOP_BREAK);
				break;
			case PlayerActionPacket::ACTION_START_SLEEPING:
				//unused
				break;
			case PlayerActionPacket::ACTION_STOP_SLEEPING:
				$this->stopSleep();
				break;
			case PlayerActionPacket::ACTION_RESPAWN:
				if($this->isAlive()){
					break;
				}

				$this->respawn();
				break;
			case PlayerActionPacket::ACTION_JUMP:
				$this->jump();
				return true;
			case PlayerActionPacket::ACTION_START_SPRINT:
				$this->toggleSprint(true);
				return true;
			case PlayerActionPacket::ACTION_STOP_SPRINT:
				$this->toggleSprint(false);
				return true;
			case PlayerActionPacket::ACTION_START_SNEAK:
				$this->toggleSneak(true);
				return true;
			case PlayerActionPacket::ACTION_STOP_SNEAK:
				$this->toggleSneak(false);
				return true;
			case PlayerActionPacket::ACTION_START_GLIDE:
			case PlayerActionPacket::ACTION_STOP_GLIDE:
				break; //TODO
			case PlayerActionPacket::ACTION_CONTINUE_BREAK:
				$block = $this->level->getBlock($pos);
				$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_PARTICLE_PUNCH_BLOCK, $block->getRuntimeId() | ($packet->face << 24));
				//TODO: destroy-progress level event
				break;
			case PlayerActionPacket::ACTION_START_SWIMMING:
				break; //TODO
			case PlayerActionPacket::ACTION_STOP_SWIMMING:
				//TODO: handle this when it doesn't spam every damn tick (yet another spam bug!!)
				break;
			case PlayerActionPacket::ACTION_INTERACT_BLOCK: //ignored (for now)
				break;
			default:
				$this->server->getLogger()->debug("Unhandled/unknown player action type " . $packet->action . " from " . $this->getName());
				return false;
		}

		$this->setUsingItem(false);

		return true;
	}

	public function toggleSprint(bool $sprint) : void{
		$ev = new PlayerToggleSprintEvent($this, $sprint);
		$ev->call();
		if($ev->isCancelled()){
			$this->sendData($this);
		}else{
			$this->setSprinting($sprint);
		}
	}

	public function toggleSneak(bool $sneak) : void{
		$ev = new PlayerToggleSneakEvent($this, $sneak);
		$ev->call();
		if($ev->isCancelled()){
			$this->sendData($this);
		}else{
			$this->setSneaking($sneak);
		}
	}

	public function handleAnimate(AnimatePacket $packet) : bool{
		if(!$this->spawned or !$this->isAlive()){
			return true;
		}

		$ev = new PlayerAnimationEvent($this, $packet->action);
		$ev->call();
		if($ev->isCancelled()){
			return true;
		}

		$pk = new AnimatePacket();
		$pk->entityRuntimeId = $this->getId();
		$pk->action = $ev->getAnimationType();
		$this->server->broadcastPacket($this->getViewers(), $pk);

		return true;
	}

	public function handleRespawn(RespawnPacket $packet) : bool{
		if(!$this->isAlive() && $packet->respawnState === RespawnPacket::CLIENT_READY_TO_SPAWN){
			$this->sendRespawnPacket($this, RespawnPacket::READY_TO_SPAWN);
			return true;
		}

		return false;
	}

	/**
	 * Drops an item on the ground in front of the player. Returns if the item drop was successful.
	 *
	 * @return bool if the item was dropped or if the item was null
	 */
	public function dropItem(Item $item) : bool{
		if(!$this->spawned or !$this->isAlive()){
			return false;
		}

		if($item->isNull()){
			$this->server->getLogger()->debug($this->getName() . " attempted to drop a null item (" . $item . ")");
			return true;
		}

		$motion = $this->getDirectionVector()->multiply(0.4);

		$this->level->dropItem($this->add(0, 1.3, 0), $item, $motion, 40);

		return true;
	}

	public function handleContainerClose(ContainerClosePacket $packet) : bool{
		if(!$this->spawned or $packet->windowId === 0){
			return true;
		}

		$this->doCloseInventory();

		if(isset($this->windowIndex[$packet->windowId])){
			(new InventoryCloseEvent($this->windowIndex[$packet->windowId], $this))->call();
			$this->removeWindow($this->windowIndex[$packet->windowId]);
			return true;
		}elseif($packet->windowId === 255){
			//Closed a fake window
			return true;
		}

		return false;
	}

	public function handleAdventureSettings(AdventureSettingsPacket $packet) : bool{
		if($packet->entityUniqueId !== $this->getId()){
			return false; //TODO
		}

		$handled = false;

		$isFlying = $packet->getFlag(AdventureSettingsPacket::FLYING);
		if($isFlying and !$this->allowFlight){
			$this->kick($this->server->getLanguage()->translateString("kick.reason.cheat", ["%ability.flight"]));
			return true;
		}elseif($isFlying !== $this->isFlying()){
			$ev = new PlayerToggleFlightEvent($this, $isFlying);
			$ev->call();
			if($ev->isCancelled()){
				$this->sendSettings();
			}else{ //don't use setFlying() here, to avoid feedback loops
				$this->flying = $ev->isFlying();
				$this->resetFallDistance();
			}

			$handled = true;
		}

		if($packet->getFlag(AdventureSettingsPacket::NO_CLIP) and !$this->allowMovementCheats and !$this->isSpectator()){
			$this->kick($this->server->getLanguage()->translateString("kick.reason.cheat", ["%ability.noclip"]));
			return true;
		}

		//TODO: check other changes

		return $handled;
	}

	public function handleBlockEntityData(BlockActorDataPacket $packet) : bool{
		if(!$this->spawned or !$this->isAlive()){
			return true;
		}
		$this->doCloseInventory();

		$pos = new Vector3($packet->x, $packet->y, $packet->z);
		if($pos->distanceSquared($this) > 10000 or $this->level->checkSpawnProtection($this, $pos)){
			return true;
		}

		$t = $this->level->getTile($pos);
		if($t instanceof Spawnable){
			$nbt = new NetworkLittleEndianNBTStream();
			$_ = 0;
			$compound = $nbt->read($packet->namedtag, false, $_, 512);

			if(!($compound instanceof CompoundTag)){
				throw new \InvalidArgumentException("Expected " . CompoundTag::class . " in block entity NBT, got " . (is_object($compound) ? get_class($compound) : gettype($compound)));
			}
			if(!$t->updateCompoundTag($compound, $this)){
				$t->spawnTo($this);
			}
		}

		return true;
	}

	public function handleSetPlayerGameType(SetPlayerGameTypePacket $packet) : bool{
		if($packet->gamemode !== $this->gamemode){
			//Set this back to default. TODO: handle this properly
			$this->sendGamemode();
			$this->sendSettings();
		}
		return true;
	}

	public function handleItemFrameDropItem(ItemFrameDropItemPacket $packet) : bool{
		if(!$this->spawned or !$this->isAlive()){
			return true;
		}

		$tile = $this->level->getTileAt($packet->x, $packet->y, $packet->z);
		if($tile instanceof ItemFrame){
			$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $tile->getBlock(), null, 5 - $tile->getBlock()->getDamage(), PlayerInteractEvent::LEFT_CLICK_BLOCK);
			if($this->isSpectator() or $this->level->checkSpawnProtection($this, $tile)){
				$ev->setCancelled();
			}

			$ev->call();
			if($ev->isCancelled()){
				$tile->spawnTo($this);
				return true;
			}

			if(lcg_value() <= $tile->getItemDropChance()){
				$this->level->dropItem($tile->getBlock(), $tile->getItem());
			}
			$tile->setItem(null);
			$tile->setItemRotation(0);
		}

		return true;
	}

	public function handleResourcePackChunkRequest(ResourcePackChunkRequestPacket $packet) : bool{
		if($this->resourcePacksDone){
			return false;
		}
		$manager = $this->server->getResourcePackManager();
		$pack = $manager->getPackById($packet->packId);
		if(!($pack instanceof ResourcePack)){
			$this->close("", "disconnectionScreen.resourcePack", true);
			$this->server->getLogger()->debug("Got a resource pack chunk request for unknown pack with UUID " . $packet->packId . ", available packs: " . implode(", ", $manager->getPackIdList()));

			return false;
		}

		$pk = new ResourcePackChunkDataPacket();
		$pk->packId = $pack->getPackId();
		$pk->chunkIndex = $packet->chunkIndex;
		$pk->data = $pack->getPackChunk(1048576 * $packet->chunkIndex, 1048576);
		$pk->progress = (1048576 * $packet->chunkIndex);
		$this->dataPacket($pk);
		return true;
	}

	public function handleBookEdit(BookEditPacket $packet) : bool{
		/** @var WritableBook $oldBook */
		$oldBook = $this->inventory->getItem($packet->inventorySlot);
		if($oldBook->getId() !== Item::WRITABLE_BOOK){
			return false;
		}

		$newBook = clone $oldBook;
		$modifiedPages = [];

		switch($packet->type){
			case BookEditPacket::TYPE_REPLACE_PAGE:
				$newBook->setPageText($packet->pageNumber, $packet->text);
				$modifiedPages[] = $packet->pageNumber;
				break;
			case BookEditPacket::TYPE_ADD_PAGE:
				$newBook->insertPage($packet->pageNumber, $packet->text);
				$modifiedPages[] = $packet->pageNumber;
				break;
			case BookEditPacket::TYPE_DELETE_PAGE:
				$newBook->deletePage($packet->pageNumber);
				$modifiedPages[] = $packet->pageNumber;
				break;
			case BookEditPacket::TYPE_SWAP_PAGES:
				$newBook->swapPages($packet->pageNumber, $packet->secondaryPageNumber);
				$modifiedPages = [$packet->pageNumber, $packet->secondaryPageNumber];
				break;
			case BookEditPacket::TYPE_SIGN_BOOK:
				/** @var WrittenBook $newBook */
				$newBook = Item::get(Item::WRITTEN_BOOK, 0, 1, $newBook->getNamedTag());
				$newBook->setAuthor($packet->author);
				$newBook->setTitle($packet->title);
				$newBook->setGeneration(WrittenBook::GENERATION_ORIGINAL);
				break;
			default:
				return false;
		}

		$event = new PlayerEditBookEvent($this, $oldBook, $newBook, $packet->type, $modifiedPages);
		$event->call();
		if($event->isCancelled()){
			return true;
		}

		$this->getInventory()->setItem($packet->inventorySlot, $event->getNewBook());

		return true;
	}

	/**
	 * Called when a packet is received from the client. This method will call DataPacketReceiveEvent.
	 *
	 * @return void
	 */
	public function handleDataPacket(DataPacket $packet){
		if($this->sessionAdapter !== null){
			$this->sessionAdapter->handleDataPacket($packet);
		}
	}

	/**
	 * Batch a Data packet into the channel list to send at the end of the tick
	 */
	public function batchDataPacket(DataPacket $packet) : bool{
		if(!$this->isConnected()){
			return false;
		}

		$timings = Timings::getSendDataPacketTimings($packet);
		$timings->startTiming();
		$ev = new DataPacketSendEvent($this, $packet);
		$ev->call();
		if($ev->isCancelled()){
			$timings->stopTiming();
			return false;
		}

		$this->batchedPackets[] = clone $packet;
		$timings->stopTiming();
		return true;
	}

	/**
	 * @return bool|int
	 */
	public function sendDataPacket(DataPacket $packet, bool $needACK = false, bool $immediate = false){
		if(!$this->isConnected()){
			return false;
		}

		//Basic safety restriction. TODO: improve this
		if(!$this->loggedIn and !$packet->canBeSentBeforeLogin()){
			throw new \InvalidArgumentException("Attempted to send " . get_class($packet) . " to " . $this->getName() . " too early");
		}

		$timings = Timings::getSendDataPacketTimings($packet);
		$timings->startTiming();
		try{
			$ev = new DataPacketSendEvent($this, $packet);
			$ev->call();
			if($ev->isCancelled()){
				return false;
			}

			$identifier = $this->interface->putPacket($this, $packet, $needACK, $immediate);

			if($needACK and $identifier !== null){
				$this->needACK[$identifier] = false;
				return $identifier;
			}

			return true;
		}finally{
			$timings->stopTiming();
		}
	}

	/**
	 * @return bool|int
	 */
	public function dataPacket(DataPacket $packet, bool $needACK = false){
		return $this->sendDataPacket($packet, $needACK, false);
	}

	/**
	 * @return bool|int
	 */
	public function directDataPacket(DataPacket $packet, bool $needACK = false){
		return $this->sendDataPacket($packet, $needACK, true);
	}

	/**
	 * Transfers a player to another server.
	 *
	 * @param string $address The IP address or hostname of the destination server
	 * @param int    $port The destination port, defaults to 19132
	 * @param string $message Message to show in the console when closing the player
	 *
	 * @return bool if transfer was successful.
	 */
	public function transfer(string $address, int $port = 19132, string $message = "transfer") : bool{
		$ev = new PlayerTransferEvent($this, $address, $port, $message);
		$ev->call();
		if(!$ev->isCancelled()){
			$pk = new TransferPacket();
			$pk->address = $ev->getAddress();
			$pk->port = $ev->getPort();
			$this->directDataPacket($pk);
			$this->close("", $ev->getMessage(), false);

			return true;
		}

		return false;
	}

	/**
	 * Kicks a player from the server
	 *
	 * @param TextContainer|string $quitMessage
	 */
	public function kick(string $reason = "", bool $isAdmin = true, $quitMessage = null) : bool{
		$ev = new PlayerKickEvent($this, $reason, $quitMessage ?? $this->getLeaveMessage());
		$ev->call();
		if(!$ev->isCancelled()){
			$reason = $ev->getReason();
			$message = $reason;
			if($isAdmin){
				if(!$this->isBanned()){
					$message = "Kicked by admin." . ($reason !== "" ? " Reason: " . $reason : "");
				}
			}else{
				if($reason === ""){
					$message = "disconnectionScreen.noReason";
				}
			}
			$this->close($ev->getQuitMessage(), $message);

			return true;
		}

		return false;
	}

	/**
	 * Adds a title text to the user's screen, with an optional subtitle.
	 *
	 * @param int    $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
	 * @param int    $stay Duration in ticks to stay on screen for
	 * @param int    $fadeOut Duration in ticks for fade-out.
	 *
	 * @return void
	 */
	public function addTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1){
		$this->setTitleDuration($fadeIn, $stay, $fadeOut);
		if($subtitle !== ""){
			$this->addSubTitle($subtitle);
		}
		$this->sendTitleText($title, SetTitlePacket::TYPE_SET_TITLE);
	}

	/**
	 * Sets the subtitle message, without sending a title.
	 *
	 * @return void
	 */
	public function addSubTitle(string $subtitle){
		$this->sendTitleText($subtitle, SetTitlePacket::TYPE_SET_SUBTITLE);
	}

	/**
	 * Adds small text to the user's screen.
	 *
	 * @return void
	 */
	public function addActionBarMessage(string $message){
		$this->sendTitleText($message, SetTitlePacket::TYPE_SET_ACTIONBAR_MESSAGE);
	}

	/**
	 * Removes the title from the client's screen.
	 *
	 * @return void
	 */
	public function removeTitles(){
		$pk = new SetTitlePacket();
		$pk->type = SetTitlePacket::TYPE_CLEAR_TITLE;
		$this->dataPacket($pk);
	}

	/**
	 * Resets the title duration settings to defaults and removes any existing titles.
	 *
	 * @return void
	 */
	public function resetTitles(){
		$pk = new SetTitlePacket();
		$pk->type = SetTitlePacket::TYPE_RESET_TITLE;
		$this->dataPacket($pk);
	}

	/**
	 * Sets the title duration.
	 *
	 * @param int $fadeIn Title fade-in time in ticks.
	 * @param int $stay Title stay time in ticks.
	 * @param int $fadeOut Title fade-out time in ticks.
	 *
	 * @return void
	 */
	public function setTitleDuration(int $fadeIn, int $stay, int $fadeOut){
		if($fadeIn >= 0 and $stay >= 0 and $fadeOut >= 0){
			$pk = new SetTitlePacket();
			$pk->type = SetTitlePacket::TYPE_SET_ANIMATION_TIMES;
			$pk->fadeInTime = $fadeIn;
			$pk->stayTime = $stay;
			$pk->fadeOutTime = $fadeOut;
			$this->dataPacket($pk);
		}
	}

	/**
	 * Internal function used for sending titles.
	 *
	 * @return void
	 */
	protected function sendTitleText(string $title, int $type){
		$pk = new SetTitlePacket();
		$pk->type = $type;
		$pk->text = $title;
		$this->dataPacket($pk);
	}

	/**
	 * Sends a direct chat message to a player
	 *
	 * @param TextContainer|string $message
	 *
	 * @return void
	 */
	public function sendMessage($message){
		if($message instanceof TextContainer){
			if($message instanceof TranslationContainer){
				$this->sendTranslation($message->getText(), $message->getParameters());
				return;
			}
			$message = $message->getText();
		}

		$pk = new TextPacket();
		$pk->type = TextPacket::TYPE_RAW;
		$pk->message = $this->server->getLanguage()->translateString($message);
		$this->dataPacket($pk);
	}

	/**
	 * @param string[] $parameters
	 *
	 * @return void
	 */
	public function sendTranslation(string $message, array $parameters = []){
		$pk = new TextPacket();
		if(!$this->server->isLanguageForced()){
			$pk->type = TextPacket::TYPE_TRANSLATION;
			$pk->needsTranslation = true;
			$pk->message = $this->server->getLanguage()->translateString($message, $parameters, "pocketmine.");
			foreach($parameters as $i => $p){
				$parameters[$i] = $this->server->getLanguage()->translateString($p, [], "pocketmine.");
			}
			$pk->parameters = $parameters;
		}else{
			$pk->type = TextPacket::TYPE_RAW;
			$pk->message = $this->server->getLanguage()->translateString($message, $parameters);
		}
		$this->dataPacket($pk);
	}

	/**
	 * Sends a popup message to the player
	 *
	 * TODO: add translation type popups
	 *
	 * @param string $subtitle @deprecated
	 *
	 * @return void
	 */
	public function sendPopup(string $message, string $subtitle = ""){
		$pk = new TextPacket();
		$pk->type = TextPacket::TYPE_POPUP;
		$pk->message = $message;
		$this->dataPacket($pk);
	}

	/**
	 * @return void
	 */
	public function sendTip(string $message){
		$pk = new TextPacket();
		$pk->type = TextPacket::TYPE_TIP;
		$pk->message = $message;
		$this->dataPacket($pk);
	}

	/**
	 * @return void
	 */
	public function sendWhisper(string $sender, string $message){
		$pk = new TextPacket();
		$pk->type = TextPacket::TYPE_WHISPER;
		$pk->sourceName = $sender;
		$pk->message = $message;
		$this->dataPacket($pk);
	}

	/**
	 * Sends a Form to the player, or queue to send it if a form is already open.
	 */
	public function sendForm(Form $form) : void{
		$id = $this->formIdCounter++;
		$pk = new ModalFormRequestPacket();
		$pk->formId = $id;
		$pk->formData = json_encode($form);
		if($pk->formData === false){
			throw new \InvalidArgumentException("Failed to encode form JSON: " . json_last_error_msg());
		}
		if($this->dataPacket($pk)){
			$this->forms[$id] = $form;
		}
	}

	/**
	 * @param mixed $responseData
	 */
	public function onFormSubmit(int $formId, $responseData) : bool{
		if(!isset($this->forms[$formId])){
			$this->server->getLogger()->debug("Got unexpected response for form $formId");
			return false;
		}

		try{
			$this->forms[$formId]->handleResponse($this, $responseData);
		}catch(FormValidationException $e){
			$this->server->getLogger()->critical("Failed to validate form " . get_class($this->forms[$formId]) . ": " . $e->getMessage());
			$this->server->getLogger()->logException($e);
		}finally{
			unset($this->forms[$formId]);
		}

		return true;
	}

	/**
	 * Note for plugin developers: use kick() with the isAdmin
	 * flag set to kick without the "Kicked by admin" part instead of this method.
	 *
	 * @param TextContainer|string $message Message to be broadcasted
	 * @param string               $reason Reason showed in console
	 */
	final public function close($message = "", string $reason = "generic reason", bool $notify = true) : void{
		if($this->isConnected() and !$this->closed){
			if($notify and strlen($reason) > 0){
				$pk = new DisconnectPacket();
				$pk->message = $reason;
				$this->directDataPacket($pk);
			}
			$this->interface->close($this, $notify ? $reason : "");
			$this->sessionAdapter = null;

			PermissionManager::getInstance()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this);
			PermissionManager::getInstance()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);

			$this->stopSleep();

			if($this->spawned){
				$ev = new PlayerQuitEvent($this, $message, $reason);
				$ev->call();
				if($ev->getQuitMessage() != ""){
					$this->server->broadcastMessage($ev->getQuitMessage());
				}

				$this->save();
			}

			if($this->isValid()){
				foreach($this->usedChunks as $index => $d){
					 $chunkX = ($index >> 32);  $chunkZ = ($index & 0xFFFFFFFF) << 32 >> 32;
					$this->level->unregisterChunkLoader($this, $chunkX, $chunkZ);
					foreach($this->level->getChunkEntities($chunkX, $chunkZ) as $entity){
						$entity->despawnFrom($this);
					}
					unset($this->usedChunks[$index]);
				}
			}
			$this->usedChunks = [];
			$this->loadQueue = [];

			if($this->loggedIn){
				$this->server->onPlayerLogout($this);
				foreach($this->server->getOnlinePlayers() as $player){
					if(!$player->canSee($this)){
						$player->showPlayer($this);
					}
				}
				$this->hiddenPlayers = [];
			}

			$this->removeAllWindows(true);
			$this->windows = [];
			$this->windowIndex = [];
			$this->cursorInventory = null;
			$this->craftingGrid = null;

			if($this->constructed){
				parent::close();
			}
			$this->spawned = false;

			if($this->loggedIn){
				$this->loggedIn = false;
				$this->server->removeOnlinePlayer($this);
			}

			$this->server->removePlayer($this);

			$this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logOut", [
				TextFormat::AQUA . $this->getName() . TextFormat::WHITE,
				$this->ip,
				$this->port,
				$this->getServer()->getLanguage()->translateString($reason)
			]));

			$this->spawnPosition = null;

			if($this->perm !== null){
				$this->perm->clearPermissions();
				$this->perm = null;
			}
		}
	}

	/**
	 * @return mixed[]
	 */
	public function __debugInfo(){
		return [];
	}

	public function canSaveWithChunk() : bool{
		return false;
	}

	public function setCanSaveWithChunk(bool $value) : void{
		throw new \BadMethodCallException("Players can't be saved with chunks");
	}

	/**
	 * Handles player data saving
	 *
	 * @throws \InvalidStateException if the player is closed
	 *
	 * @return void
	 */
	public function save(){
		if($this->closed){
			throw new \InvalidStateException("Tried to save closed player");
		}

		parent::saveNBT();

		if($this->isValid()){
			$this->namedtag->setString("Level", $this->level->getFolderName());
		}

		if($this->hasValidSpawnPosition()){
			$this->namedtag->setString("SpawnLevel", $this->spawnPosition->getLevel()->getFolderName());
			$this->namedtag->setInt("SpawnX", $this->spawnPosition->getFloorX());
			$this->namedtag->setInt("SpawnY", $this->spawnPosition->getFloorY());
			$this->namedtag->setInt("SpawnZ", $this->spawnPosition->getFloorZ());

			if(!$this->isAlive()){
				//hack for respawn after quit
				$this->namedtag->setTag(new ListTag("Pos", [
					new DoubleTag("", $this->spawnPosition->x),
					new DoubleTag("", $this->spawnPosition->y),
					new DoubleTag("", $this->spawnPosition->z)
				]));
			}
		}

		$achievements = new CompoundTag("Achievements");
		foreach($this->achievements as $achievement => $status){
			$achievements->setByte($achievement, $status ? 1 : 0);
		}
		$this->namedtag->setTag($achievements);

		$this->namedtag->setInt("playerGameType", $this->gamemode);
		$this->namedtag->setLong("lastPlayed", (int) floor(microtime(true) * 1000));

		if($this->username != ""){
			$this->server->saveOfflinePlayerData($this->username, $this->namedtag);
		}
	}

	public function kill() : void{
		if(!$this->spawned){
			return;
		}

		parent::kill();

		$this->sendRespawnPacket($this->getSpawn());
	}

	protected function onDeath() : void{
		//Crafting grid must always be evacuated even if keep-inventory is true. This dumps the contents into the
		//main inventory and drops the rest on the ground.
		$this->doCloseInventory();

		$ev = new PlayerDeathEvent($this, $this->getDrops());
		$ev->call();

		if(!$ev->getKeepInventory()){
			foreach($ev->getDrops() as $item){
				$this->level->dropItem($this, $item);
			}

			if($this->inventory !== null){
				$this->inventory->setHeldItemIndex(0);
				$this->inventory->clearAll();
			}
			if($this->armorInventory !== null){
				$this->armorInventory->clearAll();
			}
		}

		//TODO: allow this number to be manipulated during PlayerDeathEvent
		$this->level->dropExperience($this, $this->getXpDropAmount());
		$this->setXpAndProgress(0, 0);

		if($ev->getDeathMessage() != ""){
			$this->server->broadcastMessage($ev->getDeathMessage());
		}
	}

	protected function onDeathUpdate(int $tickDiff) : bool{
		parent::onDeathUpdate($tickDiff);
		return false; //never flag players for despawn
	}

	protected function respawn() : void{
		if($this->server->isHardcore()){
			$this->setBanned(true);
			return;
		}

		$ev = new PlayerRespawnEvent($this, $this->getSpawn());
		$ev->call();

		$realSpawn = Position::fromObject($ev->getRespawnPosition()->add(0.5, 0, 0.5), $ev->getRespawnPosition()->getLevel());
		$this->teleport($realSpawn);

		$this->setSprinting(false);
		$this->setSneaking(false);

		$this->extinguish();
		$this->setAirSupplyTicks($this->getMaxAirSupplyTicks());
		$this->deadTicks = 0;
		$this->noDamageTicks = 60;

		$this->removeAllEffects();
		$this->setHealth($this->getMaxHealth());

		foreach($this->attributeMap->getAll() as $attr){
			$attr->resetToDefault();
		}

		$this->sendData($this);
		$this->sendData($this->getViewers());

		$this->sendSettings();
		$this->sendAllInventories();

		$this->spawnToAll();
		$this->scheduleUpdate();
	}

	protected function applyPostDamageEffects(EntityDamageEvent $source) : void{
		parent::applyPostDamageEffects($source);

		$this->exhaust(0.3, PlayerExhaustEvent::CAUSE_DAMAGE);
	}

	public function attack(EntityDamageEvent $source) : void{
		if(!$this->isAlive()){
			return;
		}

		if($this->isCreative()
			and $source->getCause() !== EntityDamageEvent::CAUSE_SUICIDE
			and $source->getCause() !== EntityDamageEvent::CAUSE_VOID
		){
			$source->setCancelled();
		}elseif($this->allowFlight and $source->getCause() === EntityDamageEvent::CAUSE_FALL){
			$source->setCancelled();
		}

		parent::attack($source);
	}

	public function broadcastEntityEvent(int $eventId, ?int $eventData = null, ?array $players = null) : void{
		if($this->spawned and $players === null){
			$players = $this->getViewers();
			$players[] = $this;
		}
		parent::broadcastEntityEvent($eventId, $eventData, $players);
	}

	public function getOffsetPosition(Vector3 $vector3) : Vector3{
		$result = parent::getOffsetPosition($vector3);
		$result->y += 0.001; //Hack for MCPE falling underground for no good reason (TODO: find out why it's doing this)
		return $result;
	}

	/**
	 * @param Player[]|null $targets
	 *
	 * @return void
	 */
	public function sendPosition(Vector3 $pos, float $yaw = null, float $pitch = null, int $mode = MovePlayerPacket::MODE_NORMAL, array $targets = null){
		$yaw = $yaw ?? $this->yaw;
		$pitch = $pitch ?? $this->pitch;

		$pk = new MovePlayerPacket();
		$pk->entityRuntimeId = $this->getId();
		$pk->position = $this->getOffsetPosition($pos);
		$pk->pitch = $pitch;
		$pk->headYaw = $yaw;
		$pk->yaw = $yaw;
		$pk->mode = $mode;

		if($targets !== null){
			$this->server->broadcastPacket($targets, $pk);
		}else{
			$this->dataPacket($pk);
		}

		$this->newPosition = null;
	}

	/**
	 * {@inheritdoc}
	 */
	public function teleport(Vector3 $pos, float $yaw = null, float $pitch = null) : bool{
		if(parent::teleport($pos, $yaw, $pitch)){

			$this->removeAllWindows();

			$this->sendPosition($this, $this->yaw, $this->pitch, MovePlayerPacket::MODE_TELEPORT);
			$this->sendPosition($this, $this->yaw, $this->pitch, MovePlayerPacket::MODE_TELEPORT, $this->getViewers());

			$this->spawnToAll();

			$this->resetFallDistance();
			$this->nextChunkOrderRun = 0;
			$this->newPosition = null;
			$this->stopSleep();

			$this->isTeleporting = true;

			//TODO: workaround for player last pos not getting updated
			//Entity::updateMovement() normally handles this, but it's overridden with an empty function in Player
			$this->resetLastMovements();

			return true;
		}

		return false;
	}

	/**
	 * @return void
	 */
	protected function addDefaultWindows(){
		$this->addWindow($this->getInventory(), ContainerIds::INVENTORY, true);

		$this->addWindow($this->getArmorInventory(), ContainerIds::ARMOR, true);

		$this->cursorInventory = new PlayerCursorInventory($this);
		$this->addWindow($this->cursorInventory, ContainerIds::UI, true);

		$this->craftingGrid = new CraftingGrid($this, CraftingGrid::SIZE_SMALL);

		//TODO: more windows
	}

	public function getCursorInventory() : PlayerCursorInventory{
		return $this->cursorInventory;
	}

	public function getCraftingGrid() : CraftingGrid{
		return $this->craftingGrid;
	}

	public function setCraftingGrid(CraftingGrid $grid) : void{
		$this->craftingGrid = $grid;
	}

	public function doCloseInventory() : void{
		/** @var Inventory[] $inventories */
		$inventories = [$this->craftingGrid, $this->cursorInventory];
		foreach($inventories as $inventory){
			$contents = $inventory->getContents();
			if(count($contents) > 0){
				$drops = $this->inventory->addItem(...$contents);
				foreach($drops as $drop){
					$this->dropItem($drop);
				}

				$inventory->clearAll();
			}
		}

		if($this->craftingGrid->getGridWidth() > CraftingGrid::SIZE_SMALL){
			$this->craftingGrid = new CraftingGrid($this, CraftingGrid::SIZE_SMALL);
		}
	}

	/**
	 * Returns the window ID which the inventory has for this player, or -1 if the window is not open to the player.
	 */
	public function getWindowId(Inventory $inventory) : int{
		return $this->windows[spl_object_hash($inventory)] ?? ContainerIds::NONE;
	}

	/**
	 * Returns the inventory window open to the player with the specified window ID, or null if no window is open with
	 * that ID.
	 *
	 * @return Inventory|null
	 */
	public function getWindow(int $windowId){
		return $this->windowIndex[$windowId] ?? null;
	}

	/**
	 * Opens an inventory window to the player. Returns the ID of the created window, or the existing window ID if the
	 * player is already viewing the specified inventory.
	 *
	 * @param int|null  $forceId Forces a special ID for the window
	 * @param bool      $isPermanent Prevents the window being removed if true.
	 *
	 * @throws \InvalidArgumentException if a forceID which is already in use is specified
	 * @throws \InvalidStateException if trying to add a window without forceID when no slots are free
	 */
	public function addWindow(Inventory $inventory, int $forceId = null, bool $isPermanent = false) : int{
		if(($id = $this->getWindowId($inventory)) !== ContainerIds::NONE){
			return $id;
		}

		if($forceId === null){
			$cnt = $this->windowCnt;
			do{
				$cnt = max(ContainerIds::FIRST, ($cnt + 1) % ContainerIds::LAST);
				if($cnt === $this->windowCnt){ //wraparound, no free slots
					throw new \InvalidStateException("No free window IDs found");
				}
			}while(isset($this->windowIndex[$cnt]));
			$this->windowCnt = $cnt;
		}else{
			$cnt = $forceId;
			if(isset($this->windowIndex[$cnt])){
				throw new \InvalidArgumentException("Requested force ID $forceId already in use");
			}
		}

		$this->windowIndex[$cnt] = $inventory;
		$this->windows[spl_object_hash($inventory)] = $cnt;
		if($inventory->open($this)){
			if($isPermanent){
				$this->permanentWindows[$cnt] = true;
			}
			return $cnt;
		}else{
			$this->removeWindow($inventory);

			return -1;
		}
	}

	/**
	 * Removes an inventory window from the player.
	 *
	 * @param bool      $force Forces removal of permanent windows such as normal inventory, cursor
	 *
	 * @return void
	 * @throws \InvalidArgumentException if trying to remove a fixed inventory window without the `force` parameter as true
	 */
	public function removeWindow(Inventory $inventory, bool $force = false){
		$id = $this->windows[$hash = spl_object_hash($inventory)] ?? null;

		if($id !== null and !$force and isset($this->permanentWindows[$id])){
			throw new \InvalidArgumentException("Cannot remove fixed window $id (" . get_class($inventory) . ") from " . $this->getName());
		}

		if($id !== null){
			$inventory->close($this);
			unset($this->windows[$hash], $this->windowIndex[$id], $this->permanentWindows[$id]);
		}
	}

	/**
	 * Removes all inventory windows from the player. By default this WILL NOT remove permanent windows.
	 *
	 * @param bool $removePermanentWindows Whether to remove permanent windows.
	 *
	 * @return void
	 */
	public function removeAllWindows(bool $removePermanentWindows = false){
		foreach($this->windowIndex as $id => $window){
			if(!$removePermanentWindows and isset($this->permanentWindows[$id])){
				continue;
			}

			$this->removeWindow($window, $removePermanentWindows);
		}
	}

	/**
	 * @return void
	 */
	protected function sendAllInventories(){
		foreach($this->windowIndex as $id => $inventory){
			$inventory->sendContents($this);
		}
	}

	public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
		$this->server->getPlayerMetadata()->setMetadata($this, $metadataKey, $newMetadataValue);
	}

	public function getMetadata(string $metadataKey){
		return $this->server->getPlayerMetadata()->getMetadata($this, $metadataKey);
	}

	public function hasMetadata(string $metadataKey) : bool{
		return $this->server->getPlayerMetadata()->hasMetadata($this, $metadataKey);
	}

	public function removeMetadata(string $metadataKey, Plugin $owningPlugin){
		$this->server->getPlayerMetadata()->removeMetadata($this, $metadataKey, $owningPlugin);
	}

	public function onChunkChanged(Chunk $chunk){
		if(isset($this->usedChunks[$hash = ((($chunk->getX()) & 0xFFFFFFFF) << 32) | (( $chunk->getZ()) & 0xFFFFFFFF)])){
			$this->usedChunks[$hash] = false;
			$this->nextChunkOrderRun = 0;
		}
	}

	public function onChunkLoaded(Chunk $chunk){

	}

	public function onChunkPopulated(Chunk $chunk){

	}

	public function onChunkUnloaded(Chunk $chunk){

	}

	public function onBlockChanged(Vector3 $block){

	}

	public function getLoaderId() : int{
		return $this->loaderId;
	}

	public function isLoaderActive() : bool{
		return $this->isConnected();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level;

use pocketmine\block\Block;
use pocketmine\level\format\Chunk;
use pocketmine\math\Vector3;

/**
 * If you want to keep chunks loaded and receive notifications on a specific area,
 * extend this class and register it into Level. This will also tick chunks.
 *
 * Register Level->registerChunkLoader($this, $chunkX, $chunkZ)
 * Unregister Level->unregisterChunkLoader($this, $chunkX, $chunkZ)
 *
 * WARNING: When moving this object around in the world or destroying it,
 * be sure to free the existing references from Level, otherwise you'll leak memory.
 */
interface ChunkLoader{

	/**
	 * Returns the ChunkLoader id.
	 * Call Level::generateChunkLoaderId($this) to generate and save it
	 */
	public function getLoaderId() : int;

	/**
	 * Returns if the chunk loader is currently active
	 */
	public function isLoaderActive() : bool;

	/**
	 * @return Position
	 */
	public function getPosition();

	/**
	 * @return float
	 */
	public function getX();

	/**
	 * @return float
	 */
	public function getZ();

	/**
	 * @return Level
	 */
	public function getLevel();

	/**
	 * This method will be called when a Chunk is replaced by a new one
	 *
	 * @return void
	 */
	public function onChunkChanged(Chunk $chunk);

	/**
	 * This method will be called when a registered chunk is loaded
	 *
	 * @return void
	 */
	public function onChunkLoaded(Chunk $chunk);

	/**
	 * This method will be called when a registered chunk is unloaded
	 *
	 * @return void
	 */
	public function onChunkUnloaded(Chunk $chunk);

	/**
	 * This method will be called when a registered chunk is populated
	 * Usually it'll be sent with another call to onChunkChanged()
	 *
	 * @return void
	 */
	public function onChunkPopulated(Chunk $chunk);

	/**
	 * This method will be called when a block changes in a registered chunk
	 *
	 * @param Block|Vector3 $block
	 *
	 * @return void
	 */
	public function onBlockChanged(Vector3 $block);

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine;

use pocketmine\permission\ServerOperator;

interface IPlayer extends ServerOperator{

	public function isOnline() : bool;

	public function getName() : string;

	public function isBanned() : bool;

	/**
	 * @return void
	 */
	public function setBanned(bool $banned);

	public function isWhitelisted() : bool;

	/**
	 * @return void
	 */
	public function setWhitelisted(bool $value);

	/**
	 * @return Player|null
	 */
	public function getPlayer();

	/**
	 * @return int|null
	 */
	public function getFirstPlayed();

	/**
	 * @return int|null
	 */
	public function getLastPlayed();

	public function hasPlayedBefore() : bool;

}
<?php

/*
 * RakLib network library
 *
 *
 * This project is not affiliated with Jenkins Software LLC nor RakNet.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 */

declare(strict_types=1);

namespace raklib;

use function defined;
use function extension_loaded;
use function phpversion;
use function substr_count;
use function version_compare;
use const PHP_EOL;
use const PHP_VERSION;

//Dependencies check
$errors = 0;
if(version_compare(RakLib::MIN_PHP_VERSION, PHP_VERSION) > 0){
	echo "[CRITICAL] Use PHP >= " . RakLib::MIN_PHP_VERSION . PHP_EOL;
	++$errors;
}

$exts = [
	"bcmath" => "BC Math",
	"pthreads" => "pthreads",
	"sockets" => "Sockets"
];

foreach($exts as $ext => $name){
	if(!extension_loaded($ext)){
		echo "[CRITICAL] Unable to find the $name ($ext) extension." . PHP_EOL;
		++$errors;
	}
}

if(extension_loaded("pthreads")){
	$pthreads_version = phpversion("pthreads");
	if(substr_count($pthreads_version, ".") < 2){
		$pthreads_version = "0.$pthreads_version";
	}

	if(version_compare($pthreads_version, "3.1.7dev") < 0){
		echo "[CRITICAL] pthreads >= 3.1.7dev is required, while you have $pthreads_version.";
		++$errors;
	}
}

if(!defined('AF_INET6')){
	echo "[CRITICAL] This build of PHP does not support IPv6. IPv6 support is required.";
	++$errors;
}

if($errors > 0){
	exit(1); //Exit with error
}
unset($errors, $exts);

abstract class RakLib{
	public const VERSION = "0.12.0";

	public const MIN_PHP_VERSION = "7.2.0";

	/**
	 * Default vanilla Raknet protocol version that this library implements. Things using RakNet can override this
	 * protocol version with something different.
	 */
	public const DEFAULT_PROTOCOL_VERSION = 6;
	public const MAGIC = "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78";

	public const PRIORITY_NORMAL = 0;
	public const PRIORITY_IMMEDIATE = 1;

	public const FLAG_NEED_ACK = 0b00001000;

	/*
	 * These internal "packets" DO NOT exist in the RakNet protocol. They are used by the RakLib API to communicate
	 * messages between the RakLib thread and the implementation's thread.
	 *
	 * Internal Packet:
	 * int32 (length without this field)
	 * byte (packet ID)
	 * payload
	 */

	/*
	 * ENCAPSULATED payload:
	 * byte (identifier length)
	 * byte[] (identifier)
	 * byte (flags, last 3 bits, priority)
	 * payload (binary internal EncapsulatedPacket)
	 */
	public const PACKET_ENCAPSULATED = 0x01;

	/*
	 * OPEN_SESSION payload:
	 * byte (identifier length)
	 * byte[] (identifier)
	 * byte (address length)
	 * byte[] (address)
	 * short (port)
	 * long (clientID)
	 */
	public const PACKET_OPEN_SESSION = 0x02;

	/*
	 * CLOSE_SESSION payload:
	 * byte (identifier length)
	 * byte[] (identifier)
	 * string (reason)
	 */
	public const PACKET_CLOSE_SESSION = 0x03;

	/*
	 * INVALID_SESSION payload:
	 * byte (identifier length)
	 * byte[] (identifier)
	 */
	public const PACKET_INVALID_SESSION = 0x04;

	/* TODO: implement this
	 * SEND_QUEUE payload:
	 * byte (identifier length)
	 * byte[] (identifier)
	 */
	public const PACKET_SEND_QUEUE = 0x05;

	/*
	 * ACK_NOTIFICATION payload:
	 * byte (identifier length)
	 * byte[] (identifier)
	 * int (identifierACK)
	 */
	public const PACKET_ACK_NOTIFICATION = 0x06;

	/*
	 * SET_OPTION payload:
	 * byte (option name length)
	 * byte[] (option name)
	 * byte[] (option value)
	 */
	public const PACKET_SET_OPTION = 0x07;

	/*
	 * RAW payload:
	 * byte (address length)
	 * byte[] (address from/to)
	 * short (port)
	 * byte[] (payload)
	 */
	public const PACKET_RAW = 0x08;

	/*
	 * BLOCK_ADDRESS payload:
	 * byte (address length)
	 * byte[] (address)
	 * int (timeout)
	 */
	public const PACKET_BLOCK_ADDRESS = 0x09;

	/*
	 * UNBLOCK_ADDRESS payload:
	 * byte (address length)
	 * byte[] (address)
	 */
	public const PACKET_UNBLOCK_ADDRESS = 0x10;

	/*
	 * REPORT_PING payload:
	 * byte (identifier length)
	 * byte[] (identifier)
	 * int32 (measured latency in MS)
	 */
	public const PACKET_REPORT_PING = 0x11;

	/*
	 * No payload
	 *
	 * Sends the disconnect message, removes sessions correctly, closes sockets.
	 */
	public const PACKET_SHUTDOWN = 0x7e;

	/*
	 * No payload
	 *
	 * Leaves everything as-is and halts, other Threads can be in a post-crash condition.
	 */
	public const PACKET_EMERGENCY_SHUTDOWN = 0x7f;

	/**
	 * Regular RakNet uses 10 by default. MCPE uses 20. Configure this value as appropriate.
	 * @var int
	 */
	public static $SYSTEM_ADDRESS_COUNT = 20;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;

use pocketmine\utils\Binary;

class LongTag extends NamedTag{
	/** @var int */
	private $value;

	/**
	 * @param string $name
	 * @param int    $value
	 */
	public function __construct(string $name = "", int $value = 0){
		parent::__construct($name);
		$this->value = $value;
	}

	public function getType() : int{
		return NBT::TAG_Long;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = $nbt->getLong();
	}

	public function write(NBTStream $nbt) : void{
		$nbt->putLong($this->value);
	}

	/**
	 * @return int
	 */
	public function getValue() : int{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;
use function strlen;

use pocketmine\utils\Binary;

class StringTag extends NamedTag{
	/** @var string */
	private $value;

	/**
	 * @param string $name
	 * @param string $value
	 */
	public function __construct(string $name = "", string $value = ""){
		parent::__construct($name);
		if(strlen($value) > 32767){
			throw new \InvalidArgumentException("StringTag cannot hold more than 32767 bytes, got string of length " . strlen($value));
		}
		$this->value = $value;
	}

	public function getType() : int{
		return NBT::TAG_String;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = $nbt->getString();
	}

	public function write(NBTStream $nbt) : void{
		$nbt->putString($this->value);
	}

	/**
	 * @return string
	 */
	public function getValue() : string{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt;

use function array_values;
use function count;
use function pack;
use function unpack;

use pocketmine\utils\Binary;

class BigEndianNBTStream extends NBTStream{

	public function getShort() : int{
		return (\unpack("n", $this->get(2))[1]);
	}

	public function getSignedShort() : int{
		return (\unpack("n", $this->get(2))[1] << 48 >> 48);
	}

	public function putShort(int $v) : void{
		$this->buffer .= (\pack("n", $v));
	}

	public function getInt() : int{
		return (\unpack("N", $this->get(4))[1] << 32 >> 32);
	}

	public function putInt(int $v) : void{
		$this->buffer .= (\pack("N", $v));
	}

	public function getLong() : int{
		return Binary::readLong($this->get(8));
	}

	public function putLong(int $v) : void{
		$this->buffer .= (\pack("NN", $v >> 32, $v & 0xFFFFFFFF));
	}

	public function getFloat() : float{
		return (\unpack("G", $this->get(4))[1]);
	}

	public function putFloat(float $v) : void{
		$this->buffer .= (\pack("G", $v));
	}

	public function getDouble() : float{
		return (\unpack("E", $this->get(8))[1]);
	}

	public function putDouble(float $v) : void{
		$this->buffer .= (\pack("E", $v));
	}

	public function getIntArray() : array{
		$len = $this->getInt();
		return array_values(unpack("N*", $this->get($len * 4)));
	}

	public function putIntArray(array $array) : void{
		$this->putInt(count($array));
		($this->buffer .= pack("N*", ...$array));
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\metadata;

use pocketmine\block\Block;
use pocketmine\level\Level;
use pocketmine\plugin\Plugin;

class BlockMetadataStore extends MetadataStore{
	/** @var Level */
	private $owningLevel;

	public function __construct(Level $owningLevel){
		$this->owningLevel = $owningLevel;
	}

	private function disambiguate(Block $block, string $metadataKey) : string{
		if($block->getLevel() !== $this->owningLevel){
			throw new \InvalidStateException("Block does not belong to world " . $this->owningLevel->getName());
		}
		return $block->x . ":" . $block->y . ":" . $block->z . ":" . $metadataKey;
	}

	/**
	 * @return MetadataValue[]
	 */
	public function getMetadata(Block $subject, string $metadataKey){
		return $this->getMetadataInternal($this->disambiguate($subject, $metadataKey));
	}

	public function hasMetadata(Block $subject, string $metadataKey) : bool{
		return $this->hasMetadataInternal($this->disambiguate($subject, $metadataKey));
	}

	/**
	 * @return void
	 */
	public function removeMetadata(Block $subject, string $metadataKey, Plugin $owningPlugin){
		$this->removeMetadataInternal($this->disambiguate($subject, $metadataKey), $owningPlugin);
	}

	/**
	 * @return void
	 */
	public function setMetadata(Block $subject, string $metadataKey, MetadataValue $newMetadataValue){
		$this->setMetadataInternal($this->disambiguate($subject, $metadataKey), $newMetadataValue);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\utils;

class ReversePriorityQueue extends \SplPriorityQueue{

	/**
	 * @param mixed $priority1
	 * @param mixed $priority2
	 *
	 * @return int
	 */
	public function compare($priority1, $priority2){
		//TODO: this will crash if non-numeric priorities are used
		return (int) -($priority1 - $priority2);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level;

use pocketmine\timings\Timings;
use pocketmine\timings\TimingsHandler;

class LevelTimings{

	/** @var TimingsHandler */
	public $setBlock;
	/** @var TimingsHandler */
	public $doBlockLightUpdates;
	/** @var TimingsHandler */
	public $doBlockSkyLightUpdates;

	/** @var TimingsHandler */
	public $doChunkUnload;
	/** @var TimingsHandler */
	public $doTickPending;
	/** @var TimingsHandler */
	public $doTickTiles;
	/** @var TimingsHandler */
	public $doChunkGC;
	/** @var TimingsHandler */
	public $entityTick;
	/** @var TimingsHandler */
	public $tileEntityTick;
	/** @var TimingsHandler */
	public $doTick;

	/** @var TimingsHandler */
	public $syncChunkSendTimer;
	/** @var TimingsHandler */
	public $syncChunkSendPrepareTimer;

	/** @var TimingsHandler */
	public $syncChunkLoadTimer;
	/** @var TimingsHandler */
	public $syncChunkLoadDataTimer;
	/** @var TimingsHandler */
	public $syncChunkLoadEntitiesTimer;
	/** @var TimingsHandler */
	public $syncChunkLoadTileEntitiesTimer;
	/** @var TimingsHandler */
	public $syncChunkSaveTimer;

	public function __construct(Level $level){
		$name = $level->getFolderName() . " - ";

		$this->setBlock = new TimingsHandler("** " . $name . "setBlock");
		$this->doBlockLightUpdates = new TimingsHandler("** " . $name . "doBlockLightUpdates");
		$this->doBlockSkyLightUpdates = new TimingsHandler("** " . $name . "doBlockSkyLightUpdates");

		$this->doChunkUnload = new TimingsHandler("** " . $name . "doChunkUnload");
		$this->doTickPending = new TimingsHandler("** " . $name . "doTickPending");
		$this->doTickTiles = new TimingsHandler("** " . $name . "doTickTiles");
		$this->doChunkGC = new TimingsHandler("** " . $name . "doChunkGC");
		$this->entityTick = new TimingsHandler("** " . $name . "entityTick");
		$this->tileEntityTick = new TimingsHandler("** " . $name . "tileEntityTick");

		$this->syncChunkSendTimer = new TimingsHandler("** " . $name . "syncChunkSend");
		$this->syncChunkSendPrepareTimer = new TimingsHandler("** " . $name . "syncChunkSendPrepare");

		$this->syncChunkLoadTimer = new TimingsHandler("** " . $name . "syncChunkLoad");
		$this->syncChunkLoadDataTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Data");
		$this->syncChunkLoadEntitiesTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Entities");
		$this->syncChunkLoadTileEntitiesTimer = new TimingsHandler("** " . $name . "syncChunkLoad - TileEntities");

		Timings::init(); //make sure the timer we want is available
		$this->syncChunkSaveTimer = new TimingsHandler("** " . $name . "syncChunkSave", Timings::$worldSaveTimer);

		$this->doTick = new TimingsHandler($name . "doTick");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\level;

/**
 * Called when a Level is initializing
 */
class LevelInitEvent extends LevelEvent{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Level related events
 */
namespace pocketmine\event\level;

use pocketmine\event\Event;
use pocketmine\level\Level;

abstract class LevelEvent extends Event{
	/** @var Level */
	private $level;

	public function __construct(Level $level){
		$this->level = $level;
	}

	public function getLevel() : Level{
		return $this->level;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\level;

/**
 * Called when a Level is loaded
 */
class LevelLoadEvent extends LevelEvent{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io\region;

use pocketmine\level\format\ChunkException;
use pocketmine\level\format\io\exception\CorruptedChunkException;
use pocketmine\utils\Binary;
use pocketmine\utils\MainLogger;
use function ceil;
use function chr;
use function fclose;
use function feof;
use function file_exists;
use function filesize;
use function fopen;
use function fread;
use function fseek;
use function ftruncate;
use function fwrite;
use function is_resource;
use function max;
use function ord;
use function pack;
use function str_pad;
use function stream_set_read_buffer;
use function stream_set_write_buffer;
use function strlen;
use function substr;
use function time;
use function touch;
use function unpack;
use const STR_PAD_RIGHT;

class RegionLoader{
	public const VERSION = 1;
	public const COMPRESSION_GZIP = 1;
	public const COMPRESSION_ZLIB = 2;

	public const MAX_SECTOR_LENGTH = 255 << 12; //255 sectors (~0.996 MiB)
	public const REGION_HEADER_LENGTH = 8192; //4096 location table + 4096 timestamps

	private const FIRST_SECTOR = 2; //location table occupies 0 and 1

	/** @var int */
	public static $COMPRESSION_LEVEL = 7;

	/** @var int */
	protected $x;
	/** @var int */
	protected $z;
	/** @var string */
	protected $filePath;
	/** @var resource */
	protected $filePointer;
	/** @var int */
	protected $nextSector = self::FIRST_SECTOR;
	/** @var RegionLocationTableEntry[] */
	protected $locationTable = [];
	/** @var int */
	public $lastUsed = 0;

	public function __construct(string $filePath, int $regionX, int $regionZ){
		$this->x = $regionX;
		$this->z = $regionZ;
		$this->filePath = $filePath;
	}

	/**
	 * @return void
	 * @throws CorruptedRegionException
	 */
	public function open(){
		$exists = file_exists($this->filePath);
		if(!$exists){
			touch($this->filePath);
		}elseif(filesize($this->filePath) % 4096 !== 0){
			throw new CorruptedRegionException("Region file should be padded to a multiple of 4KiB");
		}

		$this->filePointer = fopen($this->filePath, "r+b");
		stream_set_read_buffer($this->filePointer, 1024 * 16); //16KB
		stream_set_write_buffer($this->filePointer, 1024 * 16); //16KB
		if(!$exists){
			$this->createBlank();
		}else{
			$this->loadLocationTable();
		}

		$this->lastUsed = time();
	}

	public function __destruct(){
		if(is_resource($this->filePointer)){
			$this->writeLocationTable();
			fclose($this->filePointer);
		}
	}

	protected function isChunkGenerated(int $index) : bool{
		return !$this->locationTable[$index]->isNull();
	}

	/**
	 * @throws \InvalidArgumentException if invalid coordinates are given
	 * @throws CorruptedChunkException if chunk corruption is detected
	 */
	public function readChunk(int $x, int $z) : ?string{
		$index = self::getChunkOffset($x, $z);

		$this->lastUsed = time();

		if(!$this->isChunkGenerated($index)){
			return null;
		}

		fseek($this->filePointer, $this->locationTable[$index]->getFirstSector() << 12);

		$prefix = fread($this->filePointer, 4);
		if($prefix === false or strlen($prefix) !== 4){
			throw new CorruptedChunkException("Corrupted chunk header detected (unexpected end of file reading length prefix)");
		}
		$length = (\unpack("N", $prefix)[1] << 32 >> 32);

		if($length <= 0){ //TODO: if we reached here, the locationTable probably needs updating
			return null;
		}
		if($length > self::MAX_SECTOR_LENGTH){ //corrupted
			throw new CorruptedChunkException("Length for chunk x=$x,z=$z ($length) is larger than maximum " . self::MAX_SECTOR_LENGTH);
		}

		if($length > ($this->locationTable[$index]->getSectorCount() << 12)){ //Invalid chunk, bigger than defined number of sectors
			MainLogger::getLogger()->error("Chunk x=$x,z=$z length mismatch (expected " . ($this->locationTable[$index]->getSectorCount() << 12) . " sectors, got $length sectors)");
			$old = $this->locationTable[$index];
			$this->locationTable[$index] = new RegionLocationTableEntry($old->getFirstSector(), $length >> 12, time());
			$this->writeLocationIndex($index);
		}

		$chunkData = fread($this->filePointer, $length);
		if($chunkData === false or strlen($chunkData) !== $length){
			throw new CorruptedChunkException("Corrupted chunk detected (unexpected end of file reading chunk data)");
		}

		$compression = ord($chunkData[0]);
		if($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP){
			throw new CorruptedChunkException("Invalid compression type (got $compression, expected " . self::COMPRESSION_ZLIB . " or " . self::COMPRESSION_GZIP . ")");
		}

		return substr($chunkData, 1);
	}

	/**
	 * @throws \InvalidArgumentException
	 */
	public function chunkExists(int $x, int $z) : bool{
		return $this->isChunkGenerated(self::getChunkOffset($x, $z));
	}

	/**
	 * @return void
	 * @throws ChunkException
	 * @throws \InvalidArgumentException
	 */
	public function writeChunk(int $x, int $z, string $chunkData){
		$this->lastUsed = time();

		$length = strlen($chunkData) + 1;
		if($length + 4 > self::MAX_SECTOR_LENGTH){
			throw new ChunkException("Chunk is too big! " . ($length + 4) . " > " . self::MAX_SECTOR_LENGTH);
		}

		$newSize = (int) ceil(($length + 4) / 4096);
		$index = self::getChunkOffset($x, $z);
		$offset = $this->locationTable[$index]->getFirstSector();

		if($this->locationTable[$index]->getSectorCount() < $newSize){
			$offset = $this->nextSector;
		}

		$this->locationTable[$index] = new RegionLocationTableEntry($offset, $newSize, time());
		$this->bumpNextFreeSector($this->locationTable[$index]);

		fseek($this->filePointer, $offset << 12);
		fwrite($this->filePointer, str_pad((\pack("N", $length)) . chr(self::COMPRESSION_ZLIB) . $chunkData, $newSize << 12, "\x00", STR_PAD_RIGHT));

		$this->writeLocationIndex($index);
	}

	/**
	 * @return void
	 * @throws \InvalidArgumentException
	 */
	public function removeChunk(int $x, int $z){
		$index = self::getChunkOffset($x, $z);
		$this->locationTable[$index] = new RegionLocationTableEntry(0, 0, 0);
		$this->writeLocationIndex($index);
	}

	/**
	 * @throws \InvalidArgumentException
	 */
	protected static function getChunkOffset(int $x, int $z) : int{
		if($x < 0 or $x > 31 or $z < 0 or $z > 31){
			throw new \InvalidArgumentException("Invalid chunk position in region, expected x/z in range 0-31, got x=$x, z=$z");
		}
		return $x | ($z << 5);
	}

	/**
	 * @param int $x reference parameter
	 * @param int $z reference parameter
	 */
	protected static function getChunkCoords(int $offset, ?int &$x, ?int &$z) : void{
		$x = $offset & 0x1f;
		$z = ($offset >> 5) & 0x1f;
	}

	/**
	 * Writes the region header and closes the file
	 *
	 * @return void
	 */
	public function close(bool $writeHeader = true){
		if(is_resource($this->filePointer)){
			if($writeHeader){
				$this->writeLocationTable();
			}

			fclose($this->filePointer);
		}
	}

	/**
	 * @return void
	 * @throws CorruptedRegionException
	 */
	protected function loadLocationTable(){
		fseek($this->filePointer, 0);

		$headerRaw = fread($this->filePointer, self::REGION_HEADER_LENGTH);
		if(($len = strlen($headerRaw)) !== self::REGION_HEADER_LENGTH){
			throw new CorruptedRegionException("Invalid region file header, expected " . self::REGION_HEADER_LENGTH . " bytes, got " . $len . " bytes");
		}

		$data = unpack("N*", $headerRaw);

		for($i = 0; $i < 1024; ++$i){
			$index = $data[$i + 1];
			$offset = $index >> 8;
			$timestamp = $data[$i + 1025];

			if($offset === 0){
				$this->locationTable[$i] = new RegionLocationTableEntry(0, 0, 0);
			}else{
				$this->locationTable[$i] = new RegionLocationTableEntry($offset, $index & 0xff, $timestamp);
				$this->bumpNextFreeSector($this->locationTable[$i]);
			}
		}

		$this->checkLocationTableValidity();

		fseek($this->filePointer, 0);
	}

	/**
	 * @throws CorruptedRegionException
	 */
	private function checkLocationTableValidity() : void{
		/** @var int[] $usedOffsets */
		$usedOffsets = [];

		for($i = 0; $i < 1024; ++$i){
			$entry = $this->locationTable[$i];
			if($entry->isNull()){
				continue;
			}

			self::getChunkCoords($i, $x, $z);
			$offset = $entry->getFirstSector();
			$fileOffset = $offset << 12;

			//TODO: more validity checks

			fseek($this->filePointer, $fileOffset);
			if(feof($this->filePointer)){
				throw new CorruptedRegionException("Region file location offset x=$x,z=$z points to invalid file location $fileOffset");
			}
			if(isset($usedOffsets[$offset])){
				self::getChunkCoords($usedOffsets[$offset], $existingX, $existingZ);
				throw new CorruptedRegionException("Found two chunk offsets (chunk1: x=$existingX,z=$existingZ, chunk2: x=$x,z=$z) pointing to the file location $fileOffset");
			}
			$usedOffsets[$offset] = $i;
		}
	}

	private function writeLocationTable() : void{
		$write = [];

		for($i = 0; $i < 1024; ++$i){
			$write[] = (($this->locationTable[$i]->getFirstSector() << 8) | $this->locationTable[$i]->getSectorCount());
		}
		for($i = 0; $i < 1024; ++$i){
			$write[] = $this->locationTable[$i]->getTimestamp();
		}
		fseek($this->filePointer, 0);
		fwrite($this->filePointer, pack("N*", ...$write), 4096 * 2);
	}

	/**
	 * @param int $index
	 *
	 * @return void
	 */
	protected function writeLocationIndex($index){
		fseek($this->filePointer, $index << 2);
		fwrite($this->filePointer, (\pack("N", ($this->locationTable[$index]->getFirstSector() << 8) | $this->locationTable[$index]->getSectorCount())), 4);
		fseek($this->filePointer, 4096 + ($index << 2));
		fwrite($this->filePointer, (\pack("N", $this->locationTable[$index]->getTimestamp())), 4);
	}

	/**
	 * @return void
	 */
	protected function createBlank(){
		fseek($this->filePointer, 0);
		ftruncate($this->filePointer, 8192); // this fills the file with the null byte
		for($i = 0; $i < 1024; ++$i){
			$this->locationTable[$i] = new RegionLocationTableEntry(0, 0, 0);
		}
	}

	private function bumpNextFreeSector(RegionLocationTableEntry $entry) : void{
		$this->nextSector = max($this->nextSector, $entry->getLastSector()) + 1;
	}

	public function getX() : int{
		return $this->x;
	}

	public function getZ() : int{
		return $this->z;
	}

	public function getFilePath() : string{
		return $this->filePath;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io\region;

use function range;

class RegionLocationTableEntry{

	/** @var int */
	private $firstSector;
	/** @var int */
	private $sectorCount;
	/** @var int */
	private $timestamp;

	/**
	 * @throws \InvalidArgumentException
	 */
	public function __construct(int $firstSector, int $sectorCount, int $timestamp){
		if($firstSector < 0){
			throw new \InvalidArgumentException("Start sector must be positive, got $firstSector");
		}
		$this->firstSector = $firstSector;
		if($sectorCount < 0 or $sectorCount > 255){
			throw new \InvalidArgumentException("Sector count must be in range 0...255, got $sectorCount");
		}
		$this->sectorCount = $sectorCount;
		$this->timestamp = $timestamp;
	}

	public function getFirstSector() : int{
		return $this->firstSector;
	}

	public function getLastSector() : int{
		return $this->firstSector + $this->sectorCount - 1;
	}

	/**
	 * Returns an array of sector offsets reserved by this chunk.
	 * @return int[]
	 */
	public function getUsedSectors() : array{
		return range($this->getFirstSector(), $this->getLastSector());
	}

	public function getSectorCount() : int{
		return $this->sectorCount;
	}

	public function getTimestamp() : int{
		return $this->timestamp;
	}

	public function isNull() : bool{
		return $this->firstSector === 0 or $this->sectorCount === 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

/**
 * Implementation of MCPE-style chunks with subchunks with XZY ordering.
 */
declare(strict_types=1);

namespace pocketmine\level\format;

use pocketmine\block\BlockFactory;
use pocketmine\entity\Entity;
use pocketmine\level\Level;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\tile\Spawnable;
use pocketmine\tile\Tile;
use pocketmine\utils\BinaryStream;
use function array_fill;
use function array_filter;
use function array_values;
use function assert;
use function chr;
use function count;
use function ord;
use function pack;
use function str_repeat;
use function strlen;
use function unpack;

class Chunk{

	public const MAX_SUBCHUNKS = 16;

	/** @var int */
	protected $x;
	/** @var int */
	protected $z;

	/** @var bool */
	protected $hasChanged = false;

	/** @var bool */
	protected $isInit = false;

	/** @var bool */
	protected $lightPopulated = false;
	/** @var bool */
	protected $terrainGenerated = false;
	/** @var bool */
	protected $terrainPopulated = false;

	/** @var int */
	protected $height = Chunk::MAX_SUBCHUNKS;

	/**
	 * @var \SplFixedArray|SubChunkInterface[]
	 * @phpstan-var \SplFixedArray<SubChunkInterface>
	 */
	protected $subChunks;

	/** @var EmptySubChunk */
	protected $emptySubChunk;

	/** @var Tile[] */
	protected $tiles = [];
	/** @var Tile[] */
	protected $tileList = [];

	/** @var Entity[] */
	protected $entities = [];

	/**
	 * @var \SplFixedArray|int[]
	 * @phpstan-var \SplFixedArray<int>
	 */
	protected $heightMap;

	/** @var string */
	protected $biomeIds;

	/** @var CompoundTag[] */
	protected $NBTtiles = [];

	/** @var CompoundTag[] */
	protected $NBTentities = [];

	/**
	 * @param SubChunkInterface[] $subChunks
	 * @param CompoundTag[]       $entities
	 * @param CompoundTag[]       $tiles
	 * @param int[]               $heightMap
	 */
	public function __construct(int $chunkX, int $chunkZ, array $subChunks = [], array $entities = [], array $tiles = [], string $biomeIds = "", array $heightMap = []){
		$this->x = $chunkX;
		$this->z = $chunkZ;

		$this->height = Chunk::MAX_SUBCHUNKS; //TODO: add a way of changing this

		$this->subChunks = new \SplFixedArray($this->height);
		$this->emptySubChunk = EmptySubChunk::getInstance();

		foreach($this->subChunks as $y => $null){
			$this->subChunks[$y] = $subChunks[$y] ?? $this->emptySubChunk;
		}

		if(count($heightMap) === 256){
			$this->heightMap = \SplFixedArray::fromArray($heightMap);
		}else{
			assert(count($heightMap) === 0, "Wrong HeightMap value count, expected 256, got " . count($heightMap));
			$val = ($this->height * 16);
			$this->heightMap = \SplFixedArray::fromArray(array_fill(0, 256, $val));
		}

		if(strlen($biomeIds) === 256){
			$this->biomeIds = $biomeIds;
		}else{
			assert($biomeIds === "", "Wrong BiomeIds value count, expected 256, got " . strlen($biomeIds));
			$this->biomeIds = str_repeat("\x00", 256);
		}

		$this->NBTtiles = $tiles;
		$this->NBTentities = $entities;
	}

	public function getX() : int{
		return $this->x;
	}

	public function getZ() : int{
		return $this->z;
	}

	/**
	 * @return void
	 */
	public function setX(int $x){
		$this->x = $x;
	}

	/**
	 * @return void
	 */
	public function setZ(int $z){
		$this->z = $z;
	}

	/**
	 * Returns the chunk height in count of subchunks.
	 */
	public function getHeight() : int{
		return $this->height;
	}

	/**
	 * Returns a bitmap of block ID and meta at the specified chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $y
	 * @param int $z 0-15
	 *
	 * @return int bitmap, (id << 4) | meta
	 */
	public function getFullBlock(int $x, int $y, int $z) : int{
		return $this->getSubChunk($y >> 4)->getFullBlock($x, $y & 0x0f, $z);
	}

	/**
	 * Sets block ID and meta in one call at the specified chunk block coordinates
	 *
	 * @param int      $x 0-15
	 * @param int      $y
	 * @param int      $z 0-15
	 * @param int|null $blockId 0-255 if null, does not change
	 * @param int|null $meta 0-15 if null, does not change
	 */
	public function setBlock(int $x, int $y, int $z, ?int $blockId = null, ?int $meta = null) : bool{
		if($this->getSubChunk($y >> 4, true)->setBlock($x, $y & 0x0f, $z, $blockId !== null ? ($blockId & 0xff) : null, $meta !== null ? ($meta & 0x0f) : null)){
			$this->hasChanged = true;
			return true;
		}
		return false;
	}

	/**
	 * Returns the block ID at the specified chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $y
	 * @param int $z 0-15
	 *
	 * @return int 0-255
	 */
	public function getBlockId(int $x, int $y, int $z) : int{
		return $this->getSubChunk($y >> 4)->getBlockId($x, $y & 0x0f, $z);
	}

	/**
	 * Sets the block ID at the specified chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $y
	 * @param int $z 0-15
	 * @param int $id 0-255
	 *
	 * @return void
	 */
	public function setBlockId(int $x, int $y, int $z, int $id){
		if($this->getSubChunk($y >> 4, true)->setBlockId($x, $y & 0x0f, $z, $id)){
			$this->hasChanged = true;
		}
	}

	/**
	 * Returns the block meta value at the specified chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $y
	 * @param int $z 0-15
	 *
	 * @return int 0-15
	 */
	public function getBlockData(int $x, int $y, int $z) : int{
		return $this->getSubChunk($y >> 4)->getBlockData($x, $y & 0x0f, $z);
	}

	/**
	 * Sets the block meta value at the specified chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $y
	 * @param int $z 0-15
	 * @param int $data 0-15
	 *
	 * @return void
	 */
	public function setBlockData(int $x, int $y, int $z, int $data){
		if($this->getSubChunk($y >> 4, true)->setBlockData($x, $y & 0x0f, $z, $data)){
			$this->hasChanged = true;
		}
	}

	/**
	 * Returns the sky light level at the specified chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $y
	 * @param int $z 0-15
	 *
	 * @return int 0-15
	 */
	public function getBlockSkyLight(int $x, int $y, int $z) : int{
		return $this->getSubChunk($y >> 4)->getBlockSkyLight($x, $y & 0x0f, $z);
	}

	/**
	 * Sets the sky light level at the specified chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $y
	 * @param int $z 0-15
	 * @param int $level 0-15
	 *
	 * @return void
	 */
	public function setBlockSkyLight(int $x, int $y, int $z, int $level){
		if($this->getSubChunk($y >> 4, true)->setBlockSkyLight($x, $y & 0x0f, $z, $level)){
			$this->hasChanged = true;
		}
	}

	/**
	 * @return void
	 */
	public function setAllBlockSkyLight(int $level){
		$char = chr(($level & 0x0f) | ($level << 4));
		$data = str_repeat($char, 2048);
		for($y = $this->getHighestSubChunkIndex(); $y >= 0; --$y){
			$this->getSubChunk($y, true)->setBlockSkyLightArray($data);
		}
	}

	/**
	 * Returns the block light level at the specified chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $y 0-15
	 * @param int $z 0-15
	 *
	 * @return int 0-15
	 */
	public function getBlockLight(int $x, int $y, int $z) : int{
		return $this->getSubChunk($y >> 4)->getBlockLight($x, $y & 0x0f, $z);
	}

	/**
	 * Sets the block light level at the specified chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $y 0-15
	 * @param int $z 0-15
	 * @param int $level 0-15
	 *
	 * @return void
	 */
	public function setBlockLight(int $x, int $y, int $z, int $level){
		if($this->getSubChunk($y >> 4, true)->setBlockLight($x, $y & 0x0f, $z, $level)){
			$this->hasChanged = true;
		}
	}

	/**
	 * @return void
	 */
	public function setAllBlockLight(int $level){
		$char = chr(($level & 0x0f) | ($level << 4));
		$data = str_repeat($char, 2048);
		for($y = $this->getHighestSubChunkIndex(); $y >= 0; --$y){
			$this->getSubChunk($y, true)->setBlockLightArray($data);
		}
	}

	/**
	 * Returns the Y coordinate of the highest non-air block at the specified X/Z chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 *
	 * @return int 0-255, or -1 if there are no blocks in the column
	 */
	public function getHighestBlockAt(int $x, int $z) : int{
		$index = $this->getHighestSubChunkIndex();
		if($index === -1){
			return -1;
		}

		for($y = $index; $y >= 0; --$y){
			$height = $this->getSubChunk($y)->getHighestBlockAt($x, $z) | ($y << 4);
			if($height !== -1){
				return $height;
			}
		}

		return -1;
	}

	public function getMaxY() : int{
		return ($this->getHighestSubChunkIndex() << 4) | 0x0f;
	}

	/**
	 * Returns the heightmap value at the specified X/Z chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 */
	public function getHeightMap(int $x, int $z) : int{
		return $this->heightMap[($z << 4) | $x];
	}

	/**
	 * Returns the heightmap value at the specified X/Z chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 *
	 * @return void
	 */
	public function setHeightMap(int $x, int $z, int $value){
		$this->heightMap[($z << 4) | $x] = $value;
	}

	/**
	 * Recalculates the heightmap for the whole chunk.
	 *
	 * @return void
	 */
	public function recalculateHeightMap(){
		for($z = 0; $z < 16; ++$z){
			for($x = 0; $x < 16; ++$x){
				$this->recalculateHeightMapColumn($x, $z);
			}
		}
	}

	/**
	 * Recalculates the heightmap for the block column at the specified X/Z chunk coordinates
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 *
	 * @return int New calculated heightmap value (0-256 inclusive)
	 */
	public function recalculateHeightMapColumn(int $x, int $z) : int{
		$y = $this->getHighestBlockAt($x, $z);
		for(; $y >= 0; --$y){
			if(BlockFactory::$lightFilter[$id = $this->getBlockId($x, $y, $z)] > 1 or BlockFactory::$diffusesSkyLight[$id]){
				break;
			}
		}

		$this->setHeightMap($x, $z, $y + 1);
		return $y + 1;
	}

	/**
	 * Performs basic sky light population on the chunk.
	 * This does not cater for adjacent sky light, this performs direct sky light population only. This may cause some strange visual artifacts
	 * if the chunk is light-populated after being terrain-populated.
	 *
	 * TODO: fast adjacent light spread
	 *
	 * @return void
	 */
	public function populateSkyLight(){
		$maxY = $this->getMaxY();

		$this->setAllBlockSkyLight(0);

		for($x = 0; $x < 16; ++$x){
			for($z = 0; $z < 16; ++$z){
				$y = $maxY;
				$heightMap = $this->getHeightMap($x, $z);
				for(; $y >= $heightMap; --$y){
					$this->setBlockSkyLight($x, $y, $z, 15);
				}

				$light = 15;
				for(; $y >= 0; --$y){
					$light -= BlockFactory::$lightFilter[$this->getBlockId($x, $y, $z)];
					if($light <= 0){
						break;
					}
					$this->setBlockSkyLight($x, $y, $z, $light);
				}
			}
		}
	}

	/**
	 * Returns the biome ID at the specified X/Z chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 *
	 * @return int 0-255
	 */
	public function getBiomeId(int $x, int $z) : int{
		return ord($this->biomeIds[($z << 4) | $x]);
	}

	/**
	 * Sets the biome ID at the specified X/Z chunk block coordinates
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 * @param int $biomeId 0-255
	 *
	 * @return void
	 */
	public function setBiomeId(int $x, int $z, int $biomeId){
		$this->hasChanged = true;
		$this->biomeIds[($z << 4) | $x] = chr($biomeId & 0xff);
	}

	/**
	 * Returns a column of block IDs from bottom to top at the specified X/Z chunk block coordinates.
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 */
	public function getBlockIdColumn(int $x, int $z) : string{
		$result = "";
		foreach($this->subChunks as $subChunk){
			$result .= $subChunk->getBlockIdColumn($x, $z);
		}

		return $result;
	}

	/**
	 * Returns a column of block meta values from bottom to top at the specified X/Z chunk block coordinates.
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 */
	public function getBlockDataColumn(int $x, int $z) : string{
		$result = "";
		foreach($this->subChunks as $subChunk){
			$result .= $subChunk->getBlockDataColumn($x, $z);
		}
		return $result;
	}

	/**
	 * Returns a column of sky light values from bottom to top at the specified X/Z chunk block coordinates.
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 */
	public function getBlockSkyLightColumn(int $x, int $z) : string{
		$result = "";
		foreach($this->subChunks as $subChunk){
			$result .= $subChunk->getBlockSkyLightColumn($x, $z);
		}
		return $result;
	}

	/**
	 * Returns a column of block light values from bottom to top at the specified X/Z chunk block coordinates.
	 *
	 * @param int $x 0-15
	 * @param int $z 0-15
	 */
	public function getBlockLightColumn(int $x, int $z) : string{
		$result = "";
		foreach($this->subChunks as $subChunk){
			$result .= $subChunk->getBlockLightColumn($x, $z);
		}
		return $result;
	}

	public function isLightPopulated() : bool{
		return $this->lightPopulated;
	}

	/**
	 * @return void
	 */
	public function setLightPopulated(bool $value = true){
		$this->lightPopulated = $value;
		$this->hasChanged = true;
	}

	public function isPopulated() : bool{
		return $this->terrainPopulated;
	}

	/**
	 * @return void
	 */
	public function setPopulated(bool $value = true){
		$this->terrainPopulated = $value;
		$this->hasChanged = true;
	}

	public function isGenerated() : bool{
		return $this->terrainGenerated;
	}

	/**
	 * @return void
	 */
	public function setGenerated(bool $value = true){
		$this->terrainGenerated = $value;
		$this->hasChanged = true;
	}

	/**
	 * @return void
	 */
	public function addEntity(Entity $entity){
		if($entity->isClosed()){
			throw new \InvalidArgumentException("Attempted to add a garbage closed Entity to a chunk");
		}
		$this->entities[$entity->getId()] = $entity;
		if(!($entity instanceof Player) and $this->isInit){
			$this->hasChanged = true;
		}
	}

	/**
	 * @return void
	 */
	public function removeEntity(Entity $entity){
		unset($this->entities[$entity->getId()]);
		if(!($entity instanceof Player) and $this->isInit){
			$this->hasChanged = true;
		}
	}

	/**
	 * @return void
	 */
	public function addTile(Tile $tile){
		if($tile->isClosed()){
			throw new \InvalidArgumentException("Attempted to add a garbage closed Tile to a chunk");
		}
		$this->tiles[$tile->getId()] = $tile;
		if(isset($this->tileList[$index = (($tile->x & 0x0f) << 12) | (($tile->z & 0x0f) << 8) | ($tile->y & 0xff)]) and $this->tileList[$index] !== $tile){
			$this->tileList[$index]->close();
		}
		$this->tileList[$index] = $tile;
		if($this->isInit){
			$this->hasChanged = true;
		}
	}

	/**
	 * @return void
	 */
	public function removeTile(Tile $tile){
		unset($this->tiles[$tile->getId()]);
		unset($this->tileList[(($tile->x & 0x0f) << 12) | (($tile->z & 0x0f) << 8) | ($tile->y & 0xff)]);
		if($this->isInit){
			$this->hasChanged = true;
		}
	}

	/**
	 * Returns an array of entities currently using this chunk.
	 *
	 * @return Entity[]
	 */
	public function getEntities() : array{
		return $this->entities;
	}

	/**
	 * @return Entity[]
	 */
	public function getSavableEntities() : array{
		return array_filter($this->entities, function(Entity $entity) : bool{ return $entity->canSaveWithChunk() and !$entity->isClosed(); });
	}

	/**
	 * @return Tile[]
	 */
	public function getTiles() : array{
		return $this->tiles;
	}

	/**
	 * Returns the tile at the specified chunk block coordinates, or null if no tile exists.
	 *
	 * @param int $x 0-15
	 * @param int $y
	 * @param int $z 0-15
	 *
	 * @return Tile|null
	 */
	public function getTile(int $x, int $y, int $z){
		$index = ($x << 12) | ($z << 8) | $y;
		return $this->tileList[$index] ?? null;
	}

	/**
	 * Called when the chunk is unloaded, closing entities and tiles.
	 */
	public function onUnload() : void{
		foreach($this->getEntities() as $entity){
			if($entity instanceof Player){
				continue;
			}
			$entity->close();
		}

		foreach($this->getTiles() as $tile){
			$tile->close();
		}
	}

	/**
	 * Deserializes tiles and entities from NBT
	 *
	 * @return void
	 */
	public function initChunk(Level $level){
		if(!$this->isInit){
			$changed = false;

			$level->timings->syncChunkLoadEntitiesTimer->startTiming();
			foreach($this->NBTentities as $nbt){
				if(!$nbt->hasTag("id")){ //allow mixed types (because of leveldb)
					$changed = true;
					continue;
				}

				try{
					$entity = Entity::createEntity($nbt->getTag("id")->getValue(), $level, $nbt);
					if(!($entity instanceof Entity)){
						$changed = true;
						continue;
					}
				}catch(\Throwable $t){
					$level->getServer()->getLogger()->logException($t);
					$changed = true;
					continue;
				}
			}
			$this->NBTentities = [];
			$level->timings->syncChunkLoadEntitiesTimer->stopTiming();

			$level->timings->syncChunkLoadTileEntitiesTimer->startTiming();
			foreach($this->NBTtiles as $nbt){
				if(!$nbt->hasTag(Tile::TAG_ID, StringTag::class)){
					$changed = true;
					continue;
				}

				if(Tile::createTile($nbt->getString(Tile::TAG_ID), $level, $nbt) === null){
					$changed = true;
					continue;
				}
			}

			$this->NBTtiles = [];
			$level->timings->syncChunkLoadTileEntitiesTimer->stopTiming();

			$this->hasChanged = $changed;

			$this->isInit = true;
		}
	}

	public function getBiomeIdArray() : string{
		return $this->biomeIds;
	}

	/**
	 * @return int[]
	 */
	public function getHeightMapArray() : array{
		return $this->heightMap->toArray();
	}

	public function hasChanged() : bool{
		return $this->hasChanged;
	}

	/**
	 * @return void
	 */
	public function setChanged(bool $value = true){
		$this->hasChanged = $value;
	}

	/**
	 * Returns the subchunk at the specified subchunk Y coordinate, or an empty, unmodifiable stub if it does not exist or the coordinate is out of range.
	 *
	 * @param bool $generateNew Whether to create a new, modifiable subchunk if there is not one in place
	 */
	public function getSubChunk(int $y, bool $generateNew = false) : SubChunkInterface{
		if($y < 0 or $y >= $this->height){
			return $this->emptySubChunk;
		}elseif($generateNew and $this->subChunks[$y] instanceof EmptySubChunk){
			$this->subChunks[$y] = new SubChunk();
		}

		return $this->subChunks[$y];
	}

	/**
	 * Sets a subchunk in the chunk index
	 *
	 * @param bool                   $allowEmpty Whether to check if the chunk is empty, and if so replace it with an empty stub
	 */
	public function setSubChunk(int $y, SubChunkInterface $subChunk = null, bool $allowEmpty = false) : bool{
		if($y < 0 or $y >= $this->height){
			return false;
		}
		if($subChunk === null or ($subChunk->isEmpty() and !$allowEmpty)){
			$this->subChunks[$y] = $this->emptySubChunk;
		}else{
			$this->subChunks[$y] = $subChunk;
		}
		$this->hasChanged = true;
		return true;
	}

	/**
	 * @return \SplFixedArray|SubChunkInterface[]
	 * @phpstan-return \SplFixedArray<SubChunkInterface>
	 */
	public function getSubChunks() : \SplFixedArray{
		return $this->subChunks;
	}

	/**
	 * Returns the Y coordinate of the highest non-empty subchunk in this chunk.
	 */
	public function getHighestSubChunkIndex() : int{
		for($y = $this->subChunks->count() - 1; $y >= 0; --$y){
			if($this->subChunks[$y] instanceof EmptySubChunk){
				//No need to thoroughly prune empties at runtime, this will just reduce performance.
				continue;
			}
			return $y;
		}

		return -1;
	}

	/**
	 * Returns the count of subchunks that need sending to players
	 */
	public function getSubChunkSendCount() : int{
		return $this->getHighestSubChunkIndex() + 1;
	}

	/**
	 * Disposes of empty subchunks and frees data where possible
	 */
	public function collectGarbage() : void{
		foreach($this->subChunks as $y => $subChunk){
			if($subChunk instanceof SubChunk){
				if($subChunk->isEmpty()){
					$this->subChunks[$y] = $this->emptySubChunk;
				}else{
					$subChunk->collectGarbage();
				}
			}
		}
	}

	/**
	 * Serializes the chunk for sending to players
	 */
	public function networkSerialize() : string{
		$result = "";
		$subChunkCount = $this->getSubChunkSendCount();
		for($y = 0; $y < $subChunkCount; ++$y){
			$result .= $this->subChunks[$y]->networkSerialize();
		}
		$result .= $this->biomeIds . chr(0); //border block array count
		//Border block entry format: 1 byte (4 bits X, 4 bits Z). These are however useless since they crash the regular client.

		foreach($this->tiles as $tile){
			if($tile instanceof Spawnable){
				$result .= $tile->getSerializedSpawnCompound();
			}
		}

		return $result;
	}

	/**
	 * Fast-serializes the chunk for passing between threads
	 * TODO: tiles and entities
	 */
	public function fastSerialize() : string{
		$stream = new BinaryStream();
		$stream->putInt($this->x);
		$stream->putInt($this->z);
		$stream->putByte(($this->lightPopulated ? 4 : 0) | ($this->terrainPopulated ? 2 : 0) | ($this->terrainGenerated ? 1 : 0));
		if($this->terrainGenerated){
			//subchunks
			$count = 0;
			$subChunks = "";
			foreach($this->subChunks as $y => $subChunk){
				if($subChunk instanceof EmptySubChunk){
					continue;
				}
				++$count;
				$subChunks .= chr($y) . $subChunk->getBlockIdArray() . $subChunk->getBlockDataArray();
				if($this->lightPopulated){
					$subChunks .= $subChunk->getBlockSkyLightArray() . $subChunk->getBlockLightArray();
				}
			}
			$stream->putByte($count);
			$stream->put($subChunks);

			//biomes
			$stream->put($this->biomeIds);
			if($this->lightPopulated){
				$stream->put(pack("v*", ...$this->heightMap));
			}
		}

		return $stream->getBuffer();
	}

	/**
	 * Deserializes a fast-serialized chunk
	 */
	public static function fastDeserialize(string $data) : Chunk{
		$stream = new BinaryStream($data);

		$x = $stream->getInt();
		$z = $stream->getInt();
		$flags = $stream->getByte();
		$lightPopulated = (bool) ($flags & 4);
		$terrainPopulated = (bool) ($flags & 2);
		$terrainGenerated = (bool) ($flags & 1);

		$subChunks = [];
		$biomeIds = "";
		$heightMap = [];
		if($terrainGenerated){
			$count = $stream->getByte();
			for($y = 0; $y < $count; ++$y){
				$subChunks[$stream->getByte()] = new SubChunk(
					$stream->get(4096), //blockids
					$stream->get(2048), //blockdata
					$lightPopulated ? $stream->get(2048) : "", //skylight
					$lightPopulated ? $stream->get(2048) : "" //blocklight
				);
			}

			$biomeIds = $stream->get(256);
			if($lightPopulated){
				$heightMap = array_values(unpack("v*", $stream->get(512)));
			}
		}

		$chunk = new Chunk($x, $z, $subChunks, [], [], $biomeIds, $heightMap);
		$chunk->setGenerated($terrainGenerated);
		$chunk->setPopulated($terrainPopulated);
		$chunk->setLightPopulated($lightPopulated);

		return $chunk;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format;

use function str_repeat;

class EmptySubChunk implements SubChunkInterface{
	/** @var EmptySubChunk */
	private static $instance;

	public static function getInstance() : self{
		if(self::$instance === null){
			self::$instance = new self();
		}

		return self::$instance;
	}

	public function isEmpty(bool $checkLight = true) : bool{
		return true;
	}

	public function getBlockId(int $x, int $y, int $z) : int{
		return 0;
	}

	public function setBlockId(int $x, int $y, int $z, int $id) : bool{
		return false;
	}

	public function getBlockData(int $x, int $y, int $z) : int{
		return 0;
	}

	public function setBlockData(int $x, int $y, int $z, int $data) : bool{
		return false;
	}

	public function getFullBlock(int $x, int $y, int $z) : int{
		return 0;
	}

	public function setBlock(int $x, int $y, int $z, ?int $id = null, ?int $data = null) : bool{
		return false;
	}

	public function getBlockLight(int $x, int $y, int $z) : int{
		return 0;
	}

	public function setBlockLight(int $x, int $y, int $z, int $level) : bool{
		return false;
	}

	public function getBlockSkyLight(int $x, int $y, int $z) : int{
		return 15;
	}

	public function setBlockSkyLight(int $x, int $y, int $z, int $level) : bool{
		return false;
	}

	public function getHighestBlockAt(int $x, int $z) : int{
		return -1;
	}

	public function getBlockIdColumn(int $x, int $z) : string{
		return "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
	}

	public function getBlockDataColumn(int $x, int $z) : string{
		return "\x00\x00\x00\x00\x00\x00\x00\x00";
	}

	public function getBlockLightColumn(int $x, int $z) : string{
		return "\x00\x00\x00\x00\x00\x00\x00\x00";
	}

	public function getBlockSkyLightColumn(int $x, int $z) : string{
		return "\xff\xff\xff\xff\xff\xff\xff\xff";
	}

	public function getBlockIdArray() : string{
		return str_repeat("\x00", 4096);
	}

	public function getBlockDataArray() : string{
		return str_repeat("\x00", 2048);
	}

	public function getBlockLightArray() : string{
		return str_repeat("\x00", 2048);
	}

	public function setBlockLightArray(string $data){

	}

	public function getBlockSkyLightArray() : string{
		return str_repeat("\xff", 2048);
	}

	public function setBlockSkyLightArray(string $data){

	}

	public function networkSerialize() : string{
		return "\x00" . str_repeat("\x00", 6144);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format;

interface SubChunkInterface{

	public function isEmpty(bool $checkLight = true) : bool;

	public function getBlockId(int $x, int $y, int $z) : int;

	public function setBlockId(int $x, int $y, int $z, int $id) : bool;

	public function getBlockData(int $x, int $y, int $z) : int;

	public function setBlockData(int $x, int $y, int $z, int $data) : bool;

	public function getFullBlock(int $x, int $y, int $z) : int;

	public function setBlock(int $x, int $y, int $z, ?int $id = null, ?int $data = null) : bool;

	public function getBlockLight(int $x, int $y, int $z) : int;

	public function setBlockLight(int $x, int $y, int $z, int $level) : bool;

	public function getBlockSkyLight(int $x, int $y, int $z) : int;

	public function setBlockSkyLight(int $x, int $y, int $z, int $level) : bool;

	public function getHighestBlockAt(int $x, int $z) : int;

	public function getBlockIdColumn(int $x, int $z) : string;

	public function getBlockDataColumn(int $x, int $z) : string;

	public function getBlockLightColumn(int $x, int $z) : string;

	public function getBlockSkyLightColumn(int $x, int $z) : string;

	public function getBlockIdArray() : string;

	public function getBlockDataArray() : string;

	public function getBlockSkyLightArray() : string;

	/**
	 * @return void
	 */
	public function setBlockSkyLightArray(string $data);

	public function getBlockLightArray() : string;

	/**
	 * @return void
	 */
	public function setBlockLightArray(string $data);

	public function networkSerialize() : string;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\level;

use pocketmine\level\format\Chunk;
use pocketmine\level\Level;

/**
 * Called when a Chunk is loaded
 */
class ChunkLoadEvent extends ChunkEvent{
	/** @var bool */
	private $newChunk;

	public function __construct(Level $level, Chunk $chunk, bool $newChunk){
		parent::__construct($level, $chunk);
		$this->newChunk = $newChunk;
	}

	public function isNewChunk() : bool{
		return $this->newChunk;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\level;

use pocketmine\level\format\Chunk;
use pocketmine\level\Level;

/**
 * Chunk-related events
 */
abstract class ChunkEvent extends LevelEvent{
	/** @var Chunk */
	private $chunk;

	public function __construct(Level $level, Chunk $chunk){
		parent::__construct($level);
		$this->chunk = $chunk;
	}

	public function getChunk() : Chunk{
		return $this->chunk;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\generator;

use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\level\SimpleChunkManager;
use pocketmine\scheduler\AsyncTask;
use pocketmine\Server;

class PopulationTask extends AsyncTask{

	/** @var bool */
	public $state;
	/** @var int */
	public $levelId;
	/** @var string */
	public $chunk;

	/** @var string */
	public $chunk0;
	/** @var string */
	public $chunk1;
	/** @var string */
	public $chunk2;
	/** @var string */
	public $chunk3;

	//center chunk

	/** @var string */
	public $chunk5;
	/** @var string */
	public $chunk6;
	/** @var string */
	public $chunk7;
	/** @var string */
	public $chunk8;

	public function __construct(Level $level, Chunk $chunk){
		$this->state = true;
		$this->levelId = $level->getId();
		$this->chunk = $chunk->fastSerialize();

		foreach($level->getAdjacentChunks($chunk->getX(), $chunk->getZ()) as $i => $c){
			$this->{"chunk$i"} = $c !== null ? $c->fastSerialize() : null;
		}
	}

	public function onRun(){
		$manager = $this->getFromThreadStore("generation.level{$this->levelId}.manager");
		$generator = $this->getFromThreadStore("generation.level{$this->levelId}.generator");
		if(!($manager instanceof SimpleChunkManager) or !($generator instanceof Generator)){
			$this->state = false;
			return;
		}

		/** @var Chunk[] $chunks */
		$chunks = [];

		$chunk = Chunk::fastDeserialize($this->chunk);

		for($i = 0; $i < 9; ++$i){
			if($i === 4){
				continue;
			}
			$xx = -1 + $i % 3;
			$zz = -1 + (int) ($i / 3);
			$ck = $this->{"chunk$i"};
			if($ck === null){
				$chunks[$i] = new Chunk($chunk->getX() + $xx, $chunk->getZ() + $zz);
			}else{
				$chunks[$i] = Chunk::fastDeserialize($ck);
			}
		}

		$manager->setChunk($chunk->getX(), $chunk->getZ(), $chunk);
		if(!$chunk->isGenerated()){
			$generator->generateChunk($chunk->getX(), $chunk->getZ());
			$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
			$chunk->setGenerated();
		}

		foreach($chunks as $i => $c){
			$manager->setChunk($c->getX(), $c->getZ(), $c);
			if(!$c->isGenerated()){
				$generator->generateChunk($c->getX(), $c->getZ());
				$chunks[$i] = $manager->getChunk($c->getX(), $c->getZ());
				$chunks[$i]->setGenerated();
			}
		}

		$generator->populateChunk($chunk->getX(), $chunk->getZ());
		$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
		$chunk->setPopulated();

		$chunk->recalculateHeightMap();
		$chunk->populateSkyLight();
		$chunk->setLightPopulated();

		$this->chunk = $chunk->fastSerialize();

		foreach($chunks as $i => $c){
			$this->{"chunk$i"} = $c->hasChanged() ? $c->fastSerialize() : null;
		}

		$manager->cleanChunks();
	}

	public function onCompletion(Server $server){
		$level = $server->getLevel($this->levelId);
		if($level !== null){
			if(!$this->state){
				$level->registerGeneratorToWorker($this->worker->getAsyncWorkerId());
			}

			$chunk = Chunk::fastDeserialize($this->chunk);

			for($i = 0; $i < 9; ++$i){
				if($i === 4){
					continue;
				}
				$c = $this->{"chunk$i"};
				if($c !== null){
					$c = Chunk::fastDeserialize($c);
					$level->generateChunkCallback($c->getX(), $c->getZ(), $this->state ? $c : null);
				}
			}

			$level->generateChunkCallback($chunk->getX(), $chunk->getZ(), $this->state ? $chunk : null);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\generator;

use pocketmine\block\BlockFactory;
use pocketmine\level\biome\Biome;
use pocketmine\level\Level;
use pocketmine\level\SimpleChunkManager;
use pocketmine\scheduler\AsyncTask;
use pocketmine\utils\Random;
use function serialize;
use function unserialize;

class GeneratorRegisterTask extends AsyncTask{

	/** @var string */
	public $generatorClass;
	/** @var string */
	public $settings;
	/** @var int */
	public $seed;
	/** @var int */
	public $levelId;
	/** @var int */
	public $worldHeight = Level::Y_MAX;

	/**
	 * @param mixed[] $generatorSettings
	 * @phpstan-param array<string, mixed> $generatorSettings
	 */
	public function __construct(Level $level, string $generatorClass, array $generatorSettings = []){
		$this->generatorClass = $generatorClass;
		$this->settings = serialize($generatorSettings);
		$this->seed = $level->getSeed();
		$this->levelId = $level->getId();
		$this->worldHeight = $level->getWorldHeight();
	}

	public function onRun(){
		BlockFactory::init();
		Biome::init();
		$manager = new SimpleChunkManager($this->seed, $this->worldHeight);
		$this->saveToThreadStore("generation.level{$this->levelId}.manager", $manager);

		/**
		 * @var Generator $generator
		 * @see Generator::__construct()
		 */
		$generator = new $this->generatorClass(unserialize($this->settings));
		$generator->init($manager, new Random($manager->getSeed()));
		$this->saveToThreadStore("generation.level{$this->levelId}.generator", $generator);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\permission;

abstract class DefaultPermissions{
	public const ROOT = "pocketmine";

	public static function registerPermission(Permission $perm, Permission $parent = null) : Permission{
		if($parent instanceof Permission){
			$parent->getChildren()[$perm->getName()] = true;

			return self::registerPermission($perm);
		}
		PermissionManager::getInstance()->addPermission($perm);

		return PermissionManager::getInstance()->getPermission($perm->getName());
	}

	/**
	 * @return void
	 */
	public static function registerCorePermissions(){
		$parent = self::registerPermission(new Permission(self::ROOT, "Allows using all PocketMine commands and utilities"));

		$broadcasts = self::registerPermission(new Permission(self::ROOT . ".broadcast", "Allows the user to receive all broadcast messages"), $parent);
		self::registerPermission(new Permission(self::ROOT . ".broadcast.admin", "Allows the user to receive administrative broadcasts", Permission::DEFAULT_OP), $broadcasts);
		self::registerPermission(new Permission(self::ROOT . ".broadcast.user", "Allows the user to receive user broadcasts", Permission::DEFAULT_TRUE), $broadcasts);
		$broadcasts->recalculatePermissibles();

		$spawnprotect = self::registerPermission(new Permission(self::ROOT . ".spawnprotect.bypass", "Allows the user to edit blocks within the protected spawn radius", Permission::DEFAULT_OP), $parent);
		$spawnprotect->recalculatePermissibles();

		$commands = self::registerPermission(new Permission(self::ROOT . ".command", "Allows using all PocketMine commands"), $parent);

		$whitelist = self::registerPermission(new Permission(self::ROOT . ".command.whitelist", "Allows the user to modify the server whitelist", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.whitelist.add", "Allows the user to add a player to the server whitelist"), $whitelist);
		self::registerPermission(new Permission(self::ROOT . ".command.whitelist.remove", "Allows the user to remove a player from the server whitelist"), $whitelist);
		self::registerPermission(new Permission(self::ROOT . ".command.whitelist.reload", "Allows the user to reload the server whitelist"), $whitelist);
		self::registerPermission(new Permission(self::ROOT . ".command.whitelist.enable", "Allows the user to enable the server whitelist"), $whitelist);
		self::registerPermission(new Permission(self::ROOT . ".command.whitelist.disable", "Allows the user to disable the server whitelist"), $whitelist);
		self::registerPermission(new Permission(self::ROOT . ".command.whitelist.list", "Allows the user to list all players on the server whitelist"), $whitelist);
		$whitelist->recalculatePermissibles();

		$ban = self::registerPermission(new Permission(self::ROOT . ".command.ban", "Allows the user to ban people", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.ban.player", "Allows the user to ban players"), $ban);
		self::registerPermission(new Permission(self::ROOT . ".command.ban.ip", "Allows the user to ban IP addresses"), $ban);
		self::registerPermission(new Permission(self::ROOT . ".command.ban.list", "Allows the user to list banned players"), $ban);
		$ban->recalculatePermissibles();

		$unban = self::registerPermission(new Permission(self::ROOT . ".command.unban", "Allows the user to unban people", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.unban.player", "Allows the user to unban players"), $unban);
		self::registerPermission(new Permission(self::ROOT . ".command.unban.ip", "Allows the user to unban IP addresses"), $unban);
		$unban->recalculatePermissibles();

		$op = self::registerPermission(new Permission(self::ROOT . ".command.op", "Allows the user to change operators", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.op.give", "Allows the user to give a player operator status"), $op);
		self::registerPermission(new Permission(self::ROOT . ".command.op.take", "Allows the user to take a player's operator status"), $op);
		$op->recalculatePermissibles();

		$save = self::registerPermission(new Permission(self::ROOT . ".command.save", "Allows the user to save the worlds", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.save.enable", "Allows the user to enable automatic saving"), $save);
		self::registerPermission(new Permission(self::ROOT . ".command.save.disable", "Allows the user to disable automatic saving"), $save);
		self::registerPermission(new Permission(self::ROOT . ".command.save.perform", "Allows the user to perform a manual save"), $save);
		$save->recalculatePermissibles();

		$time = self::registerPermission(new Permission(self::ROOT . ".command.time", "Allows the user to alter the time", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.time.add", "Allows the user to fast-forward time"), $time);
		self::registerPermission(new Permission(self::ROOT . ".command.time.set", "Allows the user to change the time"), $time);
		self::registerPermission(new Permission(self::ROOT . ".command.time.start", "Allows the user to restart the time"), $time);
		self::registerPermission(new Permission(self::ROOT . ".command.time.stop", "Allows the user to stop the time"), $time);
		self::registerPermission(new Permission(self::ROOT . ".command.time.query", "Allows the user query the time"), $time);
		$time->recalculatePermissibles();

		$kill = self::registerPermission(new Permission(self::ROOT . ".command.kill", "Allows the user to kill players", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.kill.self", "Allows the user to commit suicide", Permission::DEFAULT_TRUE), $kill);
		self::registerPermission(new Permission(self::ROOT . ".command.kill.other", "Allows the user to kill other players"), $kill);
		$kill->recalculatePermissibles();

		self::registerPermission(new Permission(self::ROOT . ".command.me", "Allows the user to perform a chat action", Permission::DEFAULT_TRUE), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.tell", "Allows the user to privately message another player", Permission::DEFAULT_TRUE), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.say", "Allows the user to talk as the console", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.give", "Allows the user to give items to players", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.effect", "Allows the user to give/take potion effects", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.enchant", "Allows the user to enchant items", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.particle", "Allows the user to create particle effects", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.teleport", "Allows the user to teleport players", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.kick", "Allows the user to kick players", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.stop", "Allows the user to stop the server", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.list", "Allows the user to list all online players", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.help", "Allows the user to view the help menu", Permission::DEFAULT_TRUE), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.plugins", "Allows the user to view the list of plugins", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.reload", "Allows the user to reload the server settings", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.version", "Allows the user to view the version of the server", Permission::DEFAULT_TRUE), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.gamemode", "Allows the user to change the gamemode of players", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.defaultgamemode", "Allows the user to change the default gamemode", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.seed", "Allows the user to view the seed of the world", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.status", "Allows the user to view the server performance", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.gc", "Allows the user to fire garbage collection tasks", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.dumpmemory", "Allows the user to dump memory contents", Permission::DEFAULT_FALSE), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.timings", "Allows the user to records timings for all plugin events", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.spawnpoint", "Allows the user to change player's spawnpoint", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.setworldspawn", "Allows the user to change the world spawn", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.transferserver", "Allows the user to transfer self to another server", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.title", "Allows the user to send a title to the specified player", Permission::DEFAULT_OP), $commands);
		self::registerPermission(new Permission(self::ROOT . ".command.difficulty", "Allows the user to change the game difficulty", Permission::DEFAULT_OP), $commands);

		$commands->recalculatePermissibles();

		$parent->recalculatePermissibles();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Permission related classes
 */

namespace pocketmine\permission;

use function is_array;
use function is_bool;
use function strtolower;

/**
 * Represents a permission
 */
class Permission{
	public const DEFAULT_OP = "op";
	public const DEFAULT_NOT_OP = "notop";
	public const DEFAULT_TRUE = "true";
	public const DEFAULT_FALSE = "false";

	/** @var string */
	public static $DEFAULT_PERMISSION = self::DEFAULT_OP;

	/**
	 * @param bool|string $value
	 *
	 * @throws \InvalidArgumentException
	 */
	public static function getByName($value) : string{
		if(is_bool($value)){
			if($value){
				return "true";
			}else{
				return "false";
			}
		}
		switch(strtolower($value)){
			case "op":
			case "isop":
			case "operator":
			case "isoperator":
			case "admin":
			case "isadmin":
				return self::DEFAULT_OP;

			case "!op":
			case "notop":
			case "!operator":
			case "notoperator":
			case "!admin":
			case "notadmin":
				return self::DEFAULT_NOT_OP;

			case "true":
				return self::DEFAULT_TRUE;
			case "false":
				return self::DEFAULT_FALSE;
		}

		throw new \InvalidArgumentException("Unknown permission default name \"$value\"");
	}

	/**
	 * @param mixed[][] $data
	 * @phpstan-param array<string, array<string, mixed>> $data
	 *
	 * @return Permission[]
	 */
	public static function loadPermissions(array $data, string $default = self::DEFAULT_OP) : array{
		$result = [];
		foreach($data as $key => $entry){
			$result[] = self::loadPermission($key, $entry, $default, $result);
		}

		return $result;
	}

	/**
	 * @param mixed[]      $data
	 * @param Permission[] $output reference parameter
	 * @phpstan-param array<string, mixed> $data
	 *
	 * @throws \Exception
	 */
	public static function loadPermission(string $name, array $data, string $default = self::DEFAULT_OP, array &$output = []) : Permission{
		$desc = null;
		$children = [];
		if(isset($data["default"])){
			$default = Permission::getByName($data["default"]);
		}

		if(isset($data["children"])){
			if(is_array($data["children"])){
				foreach($data["children"] as $k => $v){
					if(is_array($v)){
						$output[] = self::loadPermission($k, $v, $default, $output);
					}
					$children[$k] = true;
				}
			}else{
				throw new \InvalidStateException("'children' key is of wrong type");
			}
		}

		if(isset($data["description"])){
			$desc = $data["description"];
		}

		return new Permission($name, $desc, $default, $children);
	}

	/** @var string */
	private $name;

	/** @var string */
	private $description;

	/**
	 * @var bool[]
	 * @phpstan-var array<string, bool>
	 */
	private $children;

	/** @var string */
	private $defaultValue;

	/**
	 * Creates a new Permission object to be attached to Permissible objects
	 *
	 * @param bool[] $children
	 * @phpstan-param array<string, bool> $children
	 */
	public function __construct(string $name, string $description = null, string $defaultValue = null, array $children = []){
		$this->name = $name;
		$this->description = $description ?? "";
		$this->defaultValue = $defaultValue ?? self::$DEFAULT_PERMISSION;
		$this->children = $children;

		$this->recalculatePermissibles();
	}

	public function getName() : string{
		return $this->name;
	}

	/**
	 * @return bool[]
	 * @phpstan-return array<string, bool>
	 */
	public function &getChildren() : array{
		return $this->children;
	}

	public function getDefault() : string{
		return $this->defaultValue;
	}

	/**
	 * @return void
	 */
	public function setDefault(string $value){
		if($value !== $this->defaultValue){
			$this->defaultValue = $value;
			$this->recalculatePermissibles();
		}
	}

	public function getDescription() : string{
		return $this->description;
	}

	/**
	 * @return void
	 */
	public function setDescription(string $value){
		$this->description = $value;
	}

	/**
	 * @return Permissible[]
	 */
	public function getPermissibles() : array{
		return PermissionManager::getInstance()->getPermissionSubscriptions($this->name);
	}

	/**
	 * @return void
	 */
	public function recalculatePermissibles(){
		$perms = $this->getPermissibles();

		PermissionManager::getInstance()->recalculatePermissionDefaults($this);

		foreach($perms as $p){
			$p->recalculatePermissions();
		}
	}

	/**
	 * @param string|Permission $name
	 *
	 * @return Permission|null Permission if $name is a string, null if it's a Permission
	 */
	public function addParent($name, bool $value){
		if($name instanceof Permission){
			$name->getChildren()[$this->getName()] = $value;
			$name->recalculatePermissibles();
			return null;
		}else{
			$perm = PermissionManager::getInstance()->getPermission($name);
			if($perm === null){
				$perm = new Permission($name);
				PermissionManager::getInstance()->addPermission($perm);
			}

			$this->addParent($perm, $value);

			return $perm;
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\permission;

class PermissionAttachmentInfo{
	/** @var Permissible */
	private $permissible;

	/** @var string */
	private $permission;

	/** @var PermissionAttachment|null */
	private $attachment;

	/** @var bool */
	private $value;

	/**
	 * @throws \InvalidStateException
	 */
	public function __construct(Permissible $permissible, string $permission, PermissionAttachment $attachment = null, bool $value){
		$this->permissible = $permissible;
		$this->permission = $permission;
		$this->attachment = $attachment;
		$this->value = $value;
	}

	public function getPermissible() : Permissible{
		return $this->permissible;
	}

	public function getPermission() : string{
		return $this->permission;
	}

	/**
	 * @return PermissionAttachment|null
	 */
	public function getAttachment(){
		return $this->attachment;
	}

	public function getValue() : bool{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Implementation of the UT3 Query Protocol (GameSpot)
 * Source: http://wiki.unrealadmin.org/UT3_query_protocol
 */
namespace pocketmine\network\query;

use pocketmine\network\AdvancedSourceInterface;
use pocketmine\Server;
use pocketmine\utils\Binary;
use function base64_encode;
use function chr;
use function hash;
use function ord;
use function random_bytes;
use function strlen;
use function substr;

class QueryHandler{
	/** @var Server */
	private $server;
	/** @var string */
	private $lastToken;
	/** @var string */
	private $token;

	public const HANDSHAKE = 9;
	public const STATISTICS = 0;

	public function __construct(){
		$this->server = Server::getInstance();
		$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.server.query.start"));
		$addr = $this->server->getIp();
		$port = $this->server->getPort();
		$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.server.query.info", [$port]));
		/*
		The Query protocol is built on top of the existing Minecraft PE UDP network stack.
		Because the 0xFE packet does not exist in the MCPE protocol,
		we can identify	Query packets and remove them from the packet queue.

		Then, the Query class handles itself sending the packets in raw form, because
		packets can conflict with the MCPE ones.
		*/

		$this->regenerateToken();
		$this->lastToken = $this->token;
		$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.server.query.running", [$addr, $port]));
	}

	private function debug(string $message) : void{
		//TODO: replace this with a proper prefixed logger
		$this->server->getLogger()->debug("[Query] $message");
	}

	/**
	 * @deprecated
	 *
	 * @return void
	 */
	public function regenerateInfo(){

	}

	/**
	 * @return void
	 */
	public function regenerateToken(){
		$this->lastToken = $this->token;
		$this->token = random_bytes(16);
	}

	public static function getTokenString(string $token, string $salt) : int{
		return (\unpack("N", substr(hash("sha512", $salt . ":" . $token, true), 7, 4))[1] << 32 >> 32);
	}

	/**
	 * @return void
	 */
	public function handle(AdvancedSourceInterface $interface, string $address, int $port, string $packet){
		$offset = 2;
		$packetType = ord($packet[$offset++]);
		$sessionID = (\unpack("N", substr($packet, $offset, 4))[1] << 32 >> 32);
		$offset += 4;
		$payload = substr($packet, $offset);

		switch($packetType){
			case self::HANDSHAKE: //Handshake
				$reply = chr(self::HANDSHAKE);
				$reply .= (\pack("N", $sessionID));
				$reply .= self::getTokenString($this->token, $address) . "\x00";

				$interface->sendRawPacket($address, $port, $reply);
				break;
			case self::STATISTICS: //Stat
				$token = (\unpack("N", substr($payload, 0, 4))[1] << 32 >> 32);
				if($token !== ($t1 = self::getTokenString($this->token, $address)) and $token !== ($t2 = self::getTokenString($this->lastToken, $address))){
					$this->debug("Bad token $token from $address $port, expected $t1 or $t2");
					break;
				}
				$reply = chr(self::STATISTICS);
				$reply .= (\pack("N", $sessionID));

				if(strlen($payload) === 8){
					$reply .= $this->server->getQueryInformation()->getLongQuery();
				}else{
					$reply .= $this->server->getQueryInformation()->getShortQuery();
				}
				$interface->sendRawPacket($address, $port, $reply);
				break;
			default:
				$this->debug("Unhandled packet from $address $port: " . base64_encode($packet));
				break;
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\scheduler;

use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\Server;
use pocketmine\utils\Internet;
use pocketmine\utils\Utils;
use pocketmine\utils\UUID;
use pocketmine\utils\VersionString;
use function array_values;
use function count;
use function json_encode;
use function md5;
use function microtime;
use function php_uname;
use function strlen;
use const PHP_VERSION;

class SendUsageTask extends AsyncTask{

	public const TYPE_OPEN = 1;
	public const TYPE_STATUS = 2;
	public const TYPE_CLOSE = 3;

	/** @var string */
	public $endpoint;
	/** @var string */
	public $data;

	/**
	 * @param string[] $playerList
	 * @phpstan-param array<string, string> $playerList
	 */
	public function __construct(Server $server, int $type, array $playerList = []){
		$endpoint = "http://" . $server->getProperty("anonymous-statistics.host", "stats.pocketmine.net") . "/";

		$data = [];
		$data["uniqueServerId"] = $server->getServerUniqueId()->toString();
		$data["uniqueMachineId"] = Utils::getMachineUniqueId()->toString();
		$data["uniqueRequestId"] = UUID::fromData($server->getServerUniqueId()->toString(), microtime(false))->toString();

		switch($type){
			case self::TYPE_OPEN:
				$data["event"] = "open";

				$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);

				$data["server"] = [
					"port" => $server->getPort(),
					"software" => $server->getName(),
					"fullVersion" => $version->getFullVersion(true),
					"version" => $version->getFullVersion(false),
					"build" => $version->getBuild(),
					"api" => $server->getApiVersion(),
					"minecraftVersion" => $server->getVersion(),
					"protocol" => ProtocolInfo::CURRENT_PROTOCOL
				];

				$data["system"] = [
					"operatingSystem" => Utils::getOS(),
					"cores" => Utils::getCoreCount(),
					"phpVersion" => PHP_VERSION,
					"machine" => php_uname("a"),
					"release" => php_uname("r"),
					"platform" => php_uname("i")
				];

				$data["players"] = [
					"count" => 0,
					"limit" => $server->getMaxPlayers()
				];

				$plugins = [];

				foreach($server->getPluginManager()->getPlugins() as $p){
					$d = $p->getDescription();

					$plugins[$d->getName()] = [
						"name" => $d->getName(),
						"version" => $d->getVersion(),
						"enabled" => $p->isEnabled()
					];
				}

				$data["plugins"] = $plugins;

				break;
			case self::TYPE_STATUS:
				$data["event"] = "status";

				$data["server"] = [
					"ticksPerSecond" => $server->getTicksPerSecondAverage(),
					"tickUsage" => $server->getTickUsageAverage(),
					"ticks" => $server->getTick()
				];

				//This anonymizes the user ids so they cannot be reversed to the original
				foreach($playerList as $k => $v){
					$playerList[$k] = md5($v);
				}

				$players = [];
				foreach($server->getOnlinePlayers() as $p){
					if($p->isOnline()){
						$players[] = md5($p->getUniqueId()->toBinary());
					}
				}

				$data["players"] = [
					"count" => count($players),
					"limit" => $server->getMaxPlayers(),
					"currentList" => $players,
					"historyList" => array_values($playerList)
				];

				$info = Utils::getMemoryUsage(true);
				$data["system"] = [
					"mainMemory" => $info[0],
					"totalMemory" => $info[1],
					"availableMemory" => $info[2],
					"threadCount" => Utils::getThreadCount()
				];

				break;
			case self::TYPE_CLOSE:
				$data["event"] = "close";
				$data["crashing"] = $server->isRunning();
				break;
		}

		$this->endpoint = $endpoint . "api/post";
		$this->data = json_encode($data/*, JSON_PRETTY_PRINT*/);
	}

	public function onRun(){
		Internet::postURL($this->endpoint, $this->data, 5, [
			"Content-Type: application/json",
			"Content-Length: " . strlen($this->data)
		]);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format;

use function assert;
use function chr;
use function define;
use function defined;
use function ord;
use function str_repeat;
use function strlen;
use function substr;
use function substr_count;

if(!defined(__NAMESPACE__ . '\ZERO_NIBBLE_ARRAY')){
	define(__NAMESPACE__ . '\ZERO_NIBBLE_ARRAY', str_repeat("\x00", 2048));
}

class SubChunk implements SubChunkInterface{
	/** @var string */
	protected $ids;
	/** @var string */
	protected $data;
	/** @var string */
	protected $blockLight;
	/** @var string */
	protected $skyLight;

	private static function assignData(string $data, int $length, string $value = "\x00") : string{
		if(strlen($data) !== $length){
			assert($data === "", "Invalid non-zero length given, expected $length, got " . strlen($data));
			return str_repeat($value, $length);
		}
		return $data;
	}

	public function __construct(string $ids = "", string $data = "", string $skyLight = "", string $blockLight = ""){
		$this->ids = self::assignData($ids, 4096);
		$this->data = self::assignData($data, 2048);
		$this->skyLight = self::assignData($skyLight, 2048, "\xff");
		$this->blockLight = self::assignData($blockLight, 2048);
		$this->collectGarbage();
	}

	public function isEmpty(bool $checkLight = true) : bool{
		return (
			substr_count($this->ids, "\x00") === 4096 and
			(!$checkLight or (
				substr_count($this->skyLight, "\xff") === 2048 and
				$this->blockLight === ZERO_NIBBLE_ARRAY
			))
		);
	}

	public function getBlockId(int $x, int $y, int $z) : int{
		return ord($this->ids[($x << 8) | ($z << 4) | $y]);
	}

	public function setBlockId(int $x, int $y, int $z, int $id) : bool{
		$this->ids[($x << 8) | ($z << 4) | $y] = chr($id);
		return true;
	}

	public function getBlockData(int $x, int $y, int $z) : int{
		return (ord($this->data[($x << 7) | ($z << 3) | ($y >> 1)]) >> (($y & 1) << 2)) & 0xf;
	}

	public function setBlockData(int $x, int $y, int $z, int $data) : bool{
		$i = ($x << 7) | ($z << 3) | ($y >> 1);

		$shift = ($y & 1) << 2;
		$byte = ord($this->data[$i]);
		$this->data[$i] = chr(($byte & ~(0xf << $shift)) | (($data & 0xf) << $shift));

		return true;
	}

	public function getFullBlock(int $x, int $y, int $z) : int{
		$i = ($x << 8) | ($z << 4) | $y;
		return (ord($this->ids[$i]) << 4) | ((ord($this->data[$i >> 1]) >> (($y & 1) << 2)) & 0xf);
	}

	public function setBlock(int $x, int $y, int $z, ?int $id = null, ?int $data = null) : bool{
		$i = ($x << 8) | ($z << 4) | $y;
		$changed = false;
		if($id !== null){
			$block = chr($id);
			if($this->ids[$i] !== $block){
				$this->ids[$i] = $block;
				$changed = true;
			}
		}

		if($data !== null){
			$i >>= 1;

			$shift = ($y & 1) << 2;
			$oldPair = ord($this->data[$i]);
			$newPair = ($oldPair & ~(0xf << $shift)) | (($data & 0xf) << $shift);
			if($newPair !== $oldPair){
				$this->data[$i] = chr($newPair);
				$changed = true;
			}
		}

		return $changed;
	}

	public function getBlockLight(int $x, int $y, int $z) : int{
		return (ord($this->blockLight[($x << 7) | ($z << 3) | ($y >> 1)]) >> (($y & 1) << 2)) & 0xf;
	}

	public function setBlockLight(int $x, int $y, int $z, int $level) : bool{
		$i = ($x << 7) | ($z << 3) | ($y >> 1);

		$shift = ($y & 1) << 2;
		$byte = ord($this->blockLight[$i]);
		$this->blockLight[$i] = chr(($byte & ~(0xf << $shift)) | (($level & 0xf) << $shift));

		return true;
	}

	public function getBlockSkyLight(int $x, int $y, int $z) : int{
		return (ord($this->skyLight[($x << 7) | ($z << 3) | ($y >> 1)]) >> (($y & 1) << 2)) & 0xf;
	}

	public function setBlockSkyLight(int $x, int $y, int $z, int $level) : bool{
		$i = ($x << 7) | ($z << 3) | ($y >> 1);

		$shift = ($y & 1) << 2;
		$byte = ord($this->skyLight[$i]);
		$this->skyLight[$i] = chr(($byte & ~(0xf << $shift)) | (($level & 0xf) << $shift));

		return true;
	}

	public function getHighestBlockAt(int $x, int $z) : int{
		$low = ($x << 8) | ($z << 4);
		$i = $low | 0x0f;
		for(; $i >= $low; --$i){
			if($this->ids[$i] !== "\x00"){
				return $i & 0x0f;
			}
		}

		return -1; //highest block not in this subchunk
	}

	public function getBlockIdColumn(int $x, int $z) : string{
		return substr($this->ids, ($x << 8) | ($z << 4), 16);
	}

	public function getBlockDataColumn(int $x, int $z) : string{
		return substr($this->data, ($x << 7) | ($z << 3), 8);
	}

	public function getBlockLightColumn(int $x, int $z) : string{
		return substr($this->blockLight, ($x << 7) | ($z << 3), 8);
	}

	public function getBlockSkyLightColumn(int $x, int $z) : string{
		return substr($this->skyLight, ($x << 7) | ($z << 3), 8);
	}

	public function getBlockIdArray() : string{
		assert(strlen($this->ids) === 4096, "Wrong length of ID array, expecting 4096 bytes, got " . strlen($this->ids));
		return $this->ids;
	}

	public function getBlockDataArray() : string{
		assert(strlen($this->data) === 2048, "Wrong length of data array, expecting 2048 bytes, got " . strlen($this->data));
		return $this->data;
	}

	public function getBlockSkyLightArray() : string{
		assert(strlen($this->skyLight) === 2048, "Wrong length of skylight array, expecting 2048 bytes, got " . strlen($this->skyLight));
		return $this->skyLight;
	}

	public function setBlockSkyLightArray(string $data){
		assert(strlen($data) === 2048, "Wrong length of skylight array, expecting 2048 bytes, got " . strlen($data));
		$this->skyLight = $data;
	}

	public function getBlockLightArray() : string{
		assert(strlen($this->blockLight) === 2048, "Wrong length of light array, expecting 2048 bytes, got " . strlen($this->blockLight));
		return $this->blockLight;
	}

	public function setBlockLightArray(string $data){
		assert(strlen($data) === 2048, "Wrong length of light array, expecting 2048 bytes, got " . strlen($data));
		$this->blockLight = $data;
	}

	public function networkSerialize() : string{
		return "\x00" . $this->ids . $this->data;
	}

	/**
	 * @return mixed[]
	 */
	public function __debugInfo(){
		return [];
	}

	public function collectGarbage() : void{
		/*
		 * This strange looking code is designed to exploit PHP's copy-on-write behaviour. Assigning will copy a
		 * reference to the const instead of duplicating the whole string. The string will only be duplicated when
		 * modified, which is perfect for this purpose.
		 */
		if($this->data === ZERO_NIBBLE_ARRAY){
			$this->data = ZERO_NIBBLE_ARRAY;
		}
		if($this->skyLight === ZERO_NIBBLE_ARRAY){
			$this->skyLight = ZERO_NIBBLE_ARRAY;
		}
		if($this->blockLight === ZERO_NIBBLE_ARRAY){
			$this->blockLight = ZERO_NIBBLE_ARRAY;
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\level;

/**
 * Called when a Chunk is populated (after receiving it on the main thread)
 */
class ChunkPopulateEvent extends ChunkEvent{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\level;

use pocketmine\event\Cancellable;

/**
 * Called when a Chunk is unloaded
 */
class ChunkUnloadEvent extends ChunkEvent implements Cancellable{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;
use function assert;
use function get_class;
use function implode;
use function is_int;
use function str_repeat;

use pocketmine\utils\Binary;

class IntArrayTag extends NamedTag{
	/** @var int[] */
	private $value;

	/**
	 * @param string $name
	 * @param int[]  $value
	 */
	public function __construct(string $name = "", array $value = []){
		parent::__construct($name);

		assert((function() use(&$value){
			foreach($value as $v){
				if(!is_int($v)){
					return false;
				}
			}

			return true;
		})());

		$this->value = $value;
	}

	public function getType() : int{
		return NBT::TAG_IntArray;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = $nbt->getIntArray();
	}

	public function write(NBTStream $nbt) : void{
		$nbt->putIntArray($this->value);
	}

	public function toString(int $indentation = 0) : string{
		return str_repeat("  ", $indentation) . get_class($this) . ": " . ($this->__name !== "" ? "name='$this->__name', " : "") . "value=[" . implode(",", $this->value) . "]";
	}

	/**
	 * @return int[]
	 */
	public function getValue() : array{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\event\Event;
use pocketmine\network\SourceInterface;
use pocketmine\Player;
use function is_a;

/**
 * Allows the creation of players overriding the base Player class
 */
class PlayerCreationEvent extends Event{
	/** @var SourceInterface */
	private $interface;
	/** @var string */
	private $address;
	/** @var int */
	private $port;

	/** @var string */
	private $baseClass;
	/** @var string */
	private $playerClass;

	/**
	 * @param string          $baseClass
	 * @param string          $playerClass
	 */
	public function __construct(SourceInterface $interface, $baseClass, $playerClass, string $address, int $port){
		$this->interface = $interface;
		$this->address = $address;
		$this->port = $port;

		if(!is_a($baseClass, Player::class, true)){
			throw new \RuntimeException("Base class $baseClass must extend " . Player::class);
		}

		$this->baseClass = $baseClass;

		if(!is_a($playerClass, Player::class, true)){
			throw new \RuntimeException("Class $playerClass must extend " . Player::class);
		}

		$this->playerClass = $playerClass;
	}

	public function getInterface() : SourceInterface{
		return $this->interface;
	}

	public function getAddress() : string{
		return $this->address;
	}

	public function getPort() : int{
		return $this->port;
	}

	/**
	 * @return string
	 */
	public function getBaseClass(){
		return $this->baseClass;
	}

	/**
	 * @param string $class
	 *
	 * @return void
	 */
	public function setBaseClass($class){
		if(!is_a($class, $this->baseClass, true)){
			throw new \RuntimeException("Base class $class must extend " . $this->baseClass);
		}

		$this->baseClass = $class;
	}

	/**
	 * @return string
	 */
	public function getPlayerClass(){
		return $this->playerClass;
	}

	/**
	 * @param string $class
	 *
	 * @return void
	 */
	public function setPlayerClass($class){
		if(!is_a($class, $this->baseClass, true)){
			throw new \RuntimeException("Class $class must extend " . $this->baseClass);
		}

		$this->playerClass = $class;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\math;

use const PHP_INT_MAX;

class AxisAlignedBB{

	/** @var float */
	public $minX;
	/** @var float */
	public $minY;
	/** @var float */
	public $minZ;
	/** @var float */
	public $maxX;
	/** @var float */
	public $maxY;
	/** @var float */
	public $maxZ;

	public function __construct(float $minX, float $minY, float $minZ, float $maxX, float $maxY, float $maxZ){
		$this->setBounds($minX, $minY, $minZ, $maxX, $maxY, $maxZ);
	}

	/**
	 * @return $this
	 */
	public function setBounds(float $minX, float $minY, float $minZ, float $maxX, float $maxY, float $maxZ){
		$this->minX = $minX;
		$this->minY = $minY;
		$this->minZ = $minZ;
		$this->maxX = $maxX;
		$this->maxY = $maxY;
		$this->maxZ = $maxZ;

		return $this;
	}

	/**
	 * Sets the bounding box's bounds from another AxisAlignedBB, and returns itself
	 *
	 * @param AxisAlignedBB $bb
	 * @return $this
	 */
	public function setBB(AxisAlignedBB $bb){
		return $this->setBounds($bb->minX, $bb->minY, $bb->minZ, $bb->maxX, $bb->maxY, $bb->maxZ);
	}

	/**
	 * Returns a new AxisAlignedBB extended by the specified X, Y and Z.
	 * If each of X, Y and Z are positive, the relevant max bound will be increased. If negative, the relevant min
	 * bound will be decreased.
	 *
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return AxisAlignedBB
	 */
	public function addCoord(float $x, float $y, float $z) : AxisAlignedBB{
		$minX = $this->minX;
		$minY = $this->minY;
		$minZ = $this->minZ;
		$maxX = $this->maxX;
		$maxY = $this->maxY;
		$maxZ = $this->maxZ;

		if($x < 0){
			$minX += $x;
		}elseif($x > 0){
			$maxX += $x;
		}

		if($y < 0){
			$minY += $y;
		}elseif($y > 0){
			$maxY += $y;
		}

		if($z < 0){
			$minZ += $z;
		}elseif($z > 0){
			$maxZ += $z;
		}

		return new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ);
	}

	/**
	 * Outsets the bounds of this AxisAlignedBB by the specified X, Y and Z.
	 *
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return $this
	 */
	public function expand(float $x, float $y, float $z){
		$this->minX -= $x;
		$this->minY -= $y;
		$this->minZ -= $z;
		$this->maxX += $x;
		$this->maxY += $y;
		$this->maxZ += $z;

		return $this;
	}

	/**
	 * Returns an expanded clone of this AxisAlignedBB.
	 *
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return AxisAlignedBB
	 */
	public function expandedCopy(float $x, float $y, float $z) : AxisAlignedBB{
		return (clone $this)->expand($x, $y, $z);
	}

	/**
	 * Shifts this AxisAlignedBB by the given X, Y and Z.
	 *
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return $this
	 */
	public function offset(float $x, float $y, float $z){
		$this->minX += $x;
		$this->minY += $y;
		$this->minZ += $z;
		$this->maxX += $x;
		$this->maxY += $y;
		$this->maxZ += $z;

		return $this;
	}

	/**
	 * Returns an offset clone of this AxisAlignedBB.
	 *
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return AxisAlignedBB
	 */
	public function offsetCopy(float $x, float $y, float $z) : AxisAlignedBB{
		return (clone $this)->offset($x, $y, $z);
	}

	/**
	 * Insets the bounds of this AxisAlignedBB by the specified X, Y and Z.
	 *
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return $this
	 */
	public function contract(float $x, float $y, float $z){
		$this->minX += $x;
		$this->minY += $y;
		$this->minZ += $z;
		$this->maxX -= $x;
		$this->maxY -= $y;
		$this->maxZ -= $z;

		return $this;
	}

	/**
	 * Returns a contracted clone of this AxisAlignedBB.
	 *
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return AxisAlignedBB
	 */
	public function contractedCopy(float $x, float $y, float $z) : AxisAlignedBB{
		return (clone $this)->contract($x, $y, $z);
	}

	public function calculateXOffset(AxisAlignedBB $bb, float $x) : float{
		if($bb->maxY <= $this->minY or $bb->minY >= $this->maxY){
			return $x;
		}
		if($bb->maxZ <= $this->minZ or $bb->minZ >= $this->maxZ){
			return $x;
		}
		if($x > 0 and $bb->maxX <= $this->minX){
			$x1 = $this->minX - $bb->maxX;
			if($x1 < $x){
				$x = $x1;
			}
		}elseif($x < 0 and $bb->minX >= $this->maxX){
			$x2 = $this->maxX - $bb->minX;
			if($x2 > $x){
				$x = $x2;
			}
		}

		return $x;
	}

	public function calculateYOffset(AxisAlignedBB $bb, float $y) : float{
		if($bb->maxX <= $this->minX or $bb->minX >= $this->maxX){
			return $y;
		}
		if($bb->maxZ <= $this->minZ or $bb->minZ >= $this->maxZ){
			return $y;
		}
		if($y > 0 and $bb->maxY <= $this->minY){
			$y1 = $this->minY - $bb->maxY;
			if($y1 < $y){
				$y = $y1;
			}
		}elseif($y < 0 and $bb->minY >= $this->maxY){
			$y2 = $this->maxY - $bb->minY;
			if($y2 > $y){
				$y = $y2;
			}
		}

		return $y;
	}

	public function calculateZOffset(AxisAlignedBB $bb, float $z) : float{
		if($bb->maxX <= $this->minX or $bb->minX >= $this->maxX){
			return $z;
		}
		if($bb->maxY <= $this->minY or $bb->minY >= $this->maxY){
			return $z;
		}
		if($z > 0 and $bb->maxZ <= $this->minZ){
			$z1 = $this->minZ - $bb->maxZ;
			if($z1 < $z){
				$z = $z1;
			}
		}elseif($z < 0 and $bb->minZ >= $this->maxZ){
			$z2 = $this->maxZ - $bb->minZ;
			if($z2 > $z){
				$z = $z2;
			}
		}

		return $z;
	}

	/**
	 * Returns whether any part of the specified AABB is inside (intersects with) this one.
	 *
	 * @param AxisAlignedBB $bb
	 * @param float         $epsilon
	 *
	 * @return bool
	 */
	public function intersectsWith(AxisAlignedBB $bb, float $epsilon = 0.00001) : bool{
		if($bb->maxX - $this->minX > $epsilon and $this->maxX - $bb->minX > $epsilon){
			if($bb->maxY - $this->minY > $epsilon and $this->maxY - $bb->minY > $epsilon){
				return $bb->maxZ - $this->minZ > $epsilon and $this->maxZ - $bb->minZ > $epsilon;
			}
		}

		return false;
	}

	/**
	 * Returns whether the specified vector is within the bounds of this AABB on all axes.
	 *
	 * @param Vector3 $vector
	 * @return bool
	 */
	public function isVectorInside(Vector3 $vector) : bool{
		if($vector->x <= $this->minX or $vector->x >= $this->maxX){
			return false;
		}
		if($vector->y <= $this->minY or $vector->y >= $this->maxY){
			return false;
		}

		return $vector->z > $this->minZ and $vector->z < $this->maxZ;
	}

	/**
	 * Returns the mean average of the AABB's X, Y and Z lengths.
	 * @return float
	 */
	public function getAverageEdgeLength() : float{
		return ($this->maxX - $this->minX + $this->maxY - $this->minY + $this->maxZ - $this->minZ) / 3;
	}

	/**
	 * Returns whether the specified vector is within the Y and Z bounds of this AABB.
	 *
	 * @param Vector3 $vector
	 * @return bool
	 */
	public function isVectorInYZ(Vector3 $vector) : bool{
		return $vector->y >= $this->minY and $vector->y <= $this->maxY and $vector->z >= $this->minZ and $vector->z <= $this->maxZ;
	}

	/**
	 * Returns whether the specified vector is within the X and Z bounds of this AABB.
	 *
	 * @param Vector3 $vector
	 * @return bool
	 */
	public function isVectorInXZ(Vector3 $vector) : bool{
		return $vector->x >= $this->minX and $vector->x <= $this->maxX and $vector->z >= $this->minZ and $vector->z <= $this->maxZ;
	}

	/**
	 * Returns whether the specified vector is within the X and Y bounds of this AABB.
	 *
	 * @param Vector3 $vector
	 * @return bool
	 */
	public function isVectorInXY(Vector3 $vector) : bool{
		return $vector->x >= $this->minX and $vector->x <= $this->maxX and $vector->y >= $this->minY and $vector->y <= $this->maxY;
	}

	/**
	 * Performs a ray-trace and calculates the point on the AABB's edge nearest the start position that the ray-trace
	 * collided with. Returns a RayTraceResult with colliding vector closest to the start position.
	 * Returns null if no colliding point was found.
	 *
	 * @param Vector3 $pos1
	 * @param Vector3 $pos2
	 *
	 * @return RayTraceResult|null
	 */
	public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
		$v1 = $pos1->getIntermediateWithXValue($pos2, $this->minX);
		$v2 = $pos1->getIntermediateWithXValue($pos2, $this->maxX);
		$v3 = $pos1->getIntermediateWithYValue($pos2, $this->minY);
		$v4 = $pos1->getIntermediateWithYValue($pos2, $this->maxY);
		$v5 = $pos1->getIntermediateWithZValue($pos2, $this->minZ);
		$v6 = $pos1->getIntermediateWithZValue($pos2, $this->maxZ);

		if($v1 !== null and !$this->isVectorInYZ($v1)){
			$v1 = null;
		}

		if($v2 !== null and !$this->isVectorInYZ($v2)){
			$v2 = null;
		}

		if($v3 !== null and !$this->isVectorInXZ($v3)){
			$v3 = null;
		}

		if($v4 !== null and !$this->isVectorInXZ($v4)){
			$v4 = null;
		}

		if($v5 !== null and !$this->isVectorInXY($v5)){
			$v5 = null;
		}

		if($v6 !== null and !$this->isVectorInXY($v6)){
			$v6 = null;
		}

		$vector = null;
		$distance = PHP_INT_MAX;

		foreach([$v1, $v2, $v3, $v4, $v5, $v6] as $v){
			if($v !== null and ($d = $pos1->distanceSquared($v)) < $distance){
				$vector = $v;
				$distance = $d;
			}
		}

		if($vector === null){
			return null;
		}

		$f = -1;

		if($vector === $v1){
			$f = Vector3::SIDE_WEST;
		}elseif($vector === $v2){
			$f = Vector3::SIDE_EAST;
		}elseif($vector === $v3){
			$f = Vector3::SIDE_DOWN;
		}elseif($vector === $v4){
			$f = Vector3::SIDE_UP;
		}elseif($vector === $v5){
			$f = Vector3::SIDE_NORTH;
		}elseif($vector === $v6){
			$f = Vector3::SIDE_SOUTH;
		}

		return new RayTraceResult($this, $f, $vector);
	}

	public function __toString(){
		return "AxisAlignedBB({$this->minX}, {$this->minY}, {$this->minZ}, {$this->maxX}, {$this->maxY}, {$this->maxZ})";
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe;

use pocketmine\event\server\DataPacketReceiveEvent;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\ActorFallPacket;
use pocketmine\network\mcpe\protocol\ActorPickRequestPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
use pocketmine\network\mcpe\protocol\BookEditPacket;
use pocketmine\network\mcpe\protocol\BossEventPacket;
use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket;
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\CommandRequestPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\InteractPacket;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacketV1;
use pocketmine\network\mcpe\protocol\LoginPacket;
use pocketmine\network\mcpe\protocol\MapInfoRequestPacket;
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\ModalFormResponsePacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
use pocketmine\network\mcpe\protocol\PlayerActionPacket;
use pocketmine\network\mcpe\protocol\PlayerHotbarPacket;
use pocketmine\network\mcpe\protocol\PlayerInputPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
use pocketmine\network\mcpe\protocol\ResourcePackChunkRequestPacket;
use pocketmine\network\mcpe\protocol\ResourcePackClientResponsePacket;
use pocketmine\network\mcpe\protocol\RespawnPacket;
use pocketmine\network\mcpe\protocol\ServerSettingsRequestPacket;
use pocketmine\network\mcpe\protocol\SetLocalPlayerAsInitializedPacket;
use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\timings\Timings;
use function base64_encode;
use function bin2hex;
use function implode;
use function json_decode;
use function json_last_error_msg;
use function preg_match;
use function strlen;
use function substr;
use function trim;

class PlayerNetworkSessionAdapter extends NetworkSession{

	/** @var Server */
	private $server;
	/** @var Player */
	private $player;

	public function __construct(Server $server, Player $player){
		$this->server = $server;
		$this->player = $player;
	}

	public function handleDataPacket(DataPacket $packet){
		if(!$this->player->isConnected()){
			return;
		}

		$timings = Timings::getReceiveDataPacketTimings($packet);
		$timings->startTiming();

		$packet->decode();
		if(!$packet->feof() and !$packet->mayHaveUnreadBytes()){
			$remains = substr($packet->buffer, $packet->offset);
			$this->server->getLogger()->debug("Still " . strlen($remains) . " bytes unread in " . $packet->getName() . ": 0x" . bin2hex($remains));
		}

		$ev = new DataPacketReceiveEvent($this->player, $packet);
		$ev->call();
		if(!$ev->isCancelled() and !$packet->handle($this)){
			$this->server->getLogger()->debug("Unhandled " . $packet->getName() . " received from " . $this->player->getName() . ": " . base64_encode($packet->buffer));
		}

		$timings->stopTiming();
	}

	public function handleLogin(LoginPacket $packet) : bool{
		return $this->player->handleLogin($packet);
	}

	public function handleClientToServerHandshake(ClientToServerHandshakePacket $packet) : bool{
		return false; //TODO
	}

	public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
		return $this->player->handleResourcePackClientResponse($packet);
	}

	public function handleText(TextPacket $packet) : bool{
		if($packet->type === TextPacket::TYPE_CHAT){
			return $this->player->chat($packet->message);
		}

		return false;
	}

	public function handleMovePlayer(MovePlayerPacket $packet) : bool{
		return $this->player->handleMovePlayer($packet);
	}

	public function handleLevelSoundEventPacketV1(LevelSoundEventPacketV1 $packet) : bool{
		return true; //useless leftover from 1.8
	}

	public function handleActorEvent(ActorEventPacket $packet) : bool{
		return $this->player->handleEntityEvent($packet);
	}

	public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
		return $this->player->handleInventoryTransaction($packet);
	}

	public function handleMobEquipment(MobEquipmentPacket $packet) : bool{
		return $this->player->handleMobEquipment($packet);
	}

	public function handleMobArmorEquipment(MobArmorEquipmentPacket $packet) : bool{
		return true; //Not used
	}

	public function handleInteract(InteractPacket $packet) : bool{
		return $this->player->handleInteract($packet);
	}

	public function handleBlockPickRequest(BlockPickRequestPacket $packet) : bool{
		return $this->player->handleBlockPickRequest($packet);
	}

	public function handleActorPickRequest(ActorPickRequestPacket $packet) : bool{
		return false; //TODO
	}

	public function handlePlayerAction(PlayerActionPacket $packet) : bool{
		return $this->player->handlePlayerAction($packet);
	}

	public function handleActorFall(ActorFallPacket $packet) : bool{
		return true; //Not used
	}

	public function handleAnimate(AnimatePacket $packet) : bool{
		return $this->player->handleAnimate($packet);
	}

	public function handleRespawn(RespawnPacket $packet) : bool{
		return $this->player->handleRespawn($packet);
	}

	public function handleContainerClose(ContainerClosePacket $packet) : bool{
		return $this->player->handleContainerClose($packet);
	}

	public function handlePlayerHotbar(PlayerHotbarPacket $packet) : bool{
		return true; //this packet is useless
	}

	public function handleCraftingEvent(CraftingEventPacket $packet) : bool{
		return true; //this is a broken useless packet, so we don't use it
	}

	public function handleAdventureSettings(AdventureSettingsPacket $packet) : bool{
		return $this->player->handleAdventureSettings($packet);
	}

	public function handleBlockActorData(BlockActorDataPacket $packet) : bool{
		return $this->player->handleBlockEntityData($packet);
	}

	public function handlePlayerInput(PlayerInputPacket $packet) : bool{
		return false; //TODO
	}

	public function handleSetPlayerGameType(SetPlayerGameTypePacket $packet) : bool{
		return $this->player->handleSetPlayerGameType($packet);
	}

	public function handleSpawnExperienceOrb(SpawnExperienceOrbPacket $packet) : bool{
		return false; //TODO
	}

	public function handleMapInfoRequest(MapInfoRequestPacket $packet) : bool{
		return false; //TODO
	}

	public function handleRequestChunkRadius(RequestChunkRadiusPacket $packet) : bool{
		$this->player->setViewDistance($packet->radius);

		return true;
	}

	public function handleItemFrameDropItem(ItemFrameDropItemPacket $packet) : bool{
		return $this->player->handleItemFrameDropItem($packet);
	}

	public function handleBossEvent(BossEventPacket $packet) : bool{
		return false; //TODO
	}

	public function handleShowCredits(ShowCreditsPacket $packet) : bool{
		return false; //TODO: handle resume
	}

	public function handleCommandRequest(CommandRequestPacket $packet) : bool{
		return $this->player->chat($packet->command);
	}

	public function handleCommandBlockUpdate(CommandBlockUpdatePacket $packet) : bool{
		return false; //TODO
	}

	public function handleResourcePackChunkRequest(ResourcePackChunkRequestPacket $packet) : bool{
		return $this->player->handleResourcePackChunkRequest($packet);
	}

	public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{
		return $this->player->changeSkin(SkinAdapterSingleton::get()->fromSkinData($packet->skin), $packet->newSkinName, $packet->oldSkinName);
	}

	public function handleBookEdit(BookEditPacket $packet) : bool{
		return $this->player->handleBookEdit($packet);
	}

	public function handleModalFormResponse(ModalFormResponsePacket $packet) : bool{
		return $this->player->onFormSubmit($packet->formId, self::stupid_json_decode($packet->formData, true));
	}

	/**
	 * Hack to work around a stupid bug in Minecraft W10 which causes empty strings to be sent unquoted in form responses.
	 *
	 * @return mixed
	 */
	private static function stupid_json_decode(string $json, bool $assoc = false){
		if(preg_match('/^\[(.+)\]$/s', $json, $matches) > 0){
			$raw = $matches[1];
			$lastComma = -1;
			$newParts = [];
			$inQuotes = false;
			for($i = 0, $len = strlen($raw); $i <= $len; ++$i){
				if($i === $len or ($raw[$i] === "," and !$inQuotes)){
					$part = substr($raw, $lastComma + 1, $i - ($lastComma + 1));
					if(trim($part) === ""){ //regular parts will have quotes or something else that makes them non-empty
						$part = '""';
					}
					$newParts[] = $part;
					$lastComma = $i;
				}elseif($raw[$i] === '"'){
					if(!$inQuotes){
						$inQuotes = true;
					}else{
						$backslashes = 0;
						for(; $backslashes < $i && $raw[$i - $backslashes - 1] === "\\"; ++$backslashes){}
						if(($backslashes % 2) === 0){ //unescaped quote
							$inQuotes = false;
						}
					}
				}
			}

			$fixed = "[" . implode(",", $newParts) . "]";
			if(($ret = json_decode($fixed, $assoc)) === null){
				throw new \InvalidArgumentException("Failed to fix JSON: " . json_last_error_msg() . "(original: $json, modified: $fixed)");
			}

			return $ret;
		}

		return json_decode($json, $assoc);
	}

	public function handleServerSettingsRequest(ServerSettingsRequestPacket $packet) : bool{
		return false; //TODO: GUI stuff
	}

	public function handleSetLocalPlayerAsInitialized(SetLocalPlayerAsInitializedPacket $packet) : bool{
		$this->player->doFirstSpawn();
		return true;
	}

	public function handleLevelSoundEvent(LevelSoundEventPacket $packet) : bool{
		return $this->player->handleLevelSoundEvent($packet);
	}

	public function handleNetworkStackLatency(NetworkStackLatencyPacket $packet) : bool{
		return true; //TODO: implement this properly - this is here to silence debug spam from MCPE dev builds
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe;

use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\ActorFallPacket;
use pocketmine\network\mcpe\protocol\ActorPickRequestPacket;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\AddBehaviorTreePacket;
use pocketmine\network\mcpe\protocol\AddEntityPacket;
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\AddPaintingPacket;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\AnvilDamagePacket;
use pocketmine\network\mcpe\protocol\AutomationClientConnectPacket;
use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket;
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\BlockEventPacket;
use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
use pocketmine\network\mcpe\protocol\BookEditPacket;
use pocketmine\network\mcpe\protocol\BossEventPacket;
use pocketmine\network\mcpe\protocol\CameraPacket;
use pocketmine\network\mcpe\protocol\ChangeDimensionPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
use pocketmine\network\mcpe\protocol\ClientboundMapItemDataPacket;
use pocketmine\network\mcpe\protocol\ClientCacheBlobStatusPacket;
use pocketmine\network\mcpe\protocol\ClientCacheMissResponsePacket;
use pocketmine\network\mcpe\protocol\ClientCacheStatusPacket;
use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket;
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\CommandOutputPacket;
use pocketmine\network\mcpe\protocol\CommandRequestPacket;
use pocketmine\network\mcpe\protocol\CompletedUsingItemPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\EducationSettingsPacket;
use pocketmine\network\mcpe\protocol\EmotePacket;
use pocketmine\network\mcpe\protocol\EventPacket;
use pocketmine\network\mcpe\protocol\GameRulesChangedPacket;
use pocketmine\network\mcpe\protocol\GuiDataPickItemPacket;
use pocketmine\network\mcpe\protocol\HurtArmorPacket;
use pocketmine\network\mcpe\protocol\InteractPacket;
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket;
use pocketmine\network\mcpe\protocol\LabTablePacket;
use pocketmine\network\mcpe\protocol\LecternUpdatePacket;
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
use pocketmine\network\mcpe\protocol\LevelEventGenericPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacketV1;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacketV2;
use pocketmine\network\mcpe\protocol\LoginPacket;
use pocketmine\network\mcpe\protocol\MapCreateLockedCopyPacket;
use pocketmine\network\mcpe\protocol\MapInfoRequestPacket;
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
use pocketmine\network\mcpe\protocol\MobEffectPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
use pocketmine\network\mcpe\protocol\ModalFormResponsePacket;
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
use pocketmine\network\mcpe\protocol\MoveActorDeltaPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\MultiplayerSettingsPacket;
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
use pocketmine\network\mcpe\protocol\NetworkSettingsPacket;
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
use pocketmine\network\mcpe\protocol\NpcRequestPacket;
use pocketmine\network\mcpe\protocol\OnScreenTextureAnimationPacket;
use pocketmine\network\mcpe\protocol\PhotoTransferPacket;
use pocketmine\network\mcpe\protocol\PlayerActionPacket;
use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
use pocketmine\network\mcpe\protocol\PlayerHotbarPacket;
use pocketmine\network\mcpe\protocol\PlayerInputPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\PlaySoundPacket;
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
use pocketmine\network\mcpe\protocol\PurchaseReceiptPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\RemoveEntityPacket;
use pocketmine\network\mcpe\protocol\RemoveObjectivePacket;
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
use pocketmine\network\mcpe\protocol\ResourcePackChunkDataPacket;
use pocketmine\network\mcpe\protocol\ResourcePackChunkRequestPacket;
use pocketmine\network\mcpe\protocol\ResourcePackClientResponsePacket;
use pocketmine\network\mcpe\protocol\ResourcePackDataInfoPacket;
use pocketmine\network\mcpe\protocol\ResourcePacksInfoPacket;
use pocketmine\network\mcpe\protocol\ResourcePackStackPacket;
use pocketmine\network\mcpe\protocol\RespawnPacket;
use pocketmine\network\mcpe\protocol\RiderJumpPacket;
use pocketmine\network\mcpe\protocol\ScriptCustomEventPacket;
use pocketmine\network\mcpe\protocol\ServerSettingsRequestPacket;
use pocketmine\network\mcpe\protocol\ServerSettingsResponsePacket;
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
use pocketmine\network\mcpe\protocol\SetActorDataPacket;
use pocketmine\network\mcpe\protocol\SetActorLinkPacket;
use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
use pocketmine\network\mcpe\protocol\SetCommandsEnabledPacket;
use pocketmine\network\mcpe\protocol\SetDefaultGameTypePacket;
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
use pocketmine\network\mcpe\protocol\SetDisplayObjectivePacket;
use pocketmine\network\mcpe\protocol\SetHealthPacket;
use pocketmine\network\mcpe\protocol\SetLastHurtByPacket;
use pocketmine\network\mcpe\protocol\SetLocalPlayerAsInitializedPacket;
use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
use pocketmine\network\mcpe\protocol\SetScoreboardIdentityPacket;
use pocketmine\network\mcpe\protocol\SetScorePacket;
use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket;
use pocketmine\network\mcpe\protocol\SetTimePacket;
use pocketmine\network\mcpe\protocol\SettingsCommandPacket;
use pocketmine\network\mcpe\protocol\SetTitlePacket;
use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
use pocketmine\network\mcpe\protocol\ShowProfilePacket;
use pocketmine\network\mcpe\protocol\ShowStoreOfferPacket;
use pocketmine\network\mcpe\protocol\SimpleEventPacket;
use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket;
use pocketmine\network\mcpe\protocol\SpawnParticleEffectPacket;
use pocketmine\network\mcpe\protocol\StartGamePacket;
use pocketmine\network\mcpe\protocol\StopSoundPacket;
use pocketmine\network\mcpe\protocol\StructureBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataRequestPacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataResponsePacket;
use pocketmine\network\mcpe\protocol\SubClientLoginPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\TickSyncPacket;
use pocketmine\network\mcpe\protocol\TransferPacket;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPropertiesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockSyncedPacket;
use pocketmine\network\mcpe\protocol\UpdateEquipPacket;
use pocketmine\network\mcpe\protocol\UpdateSoftEnumPacket;
use pocketmine\network\mcpe\protocol\UpdateTradePacket;
use pocketmine\network\mcpe\protocol\VideoStreamConnectPacket;

abstract class NetworkSession{

	/**
	 * @return void
	 */
	abstract public function handleDataPacket(DataPacket $packet);

	public function handleLogin(LoginPacket $packet) : bool{
		return false;
	}

	public function handlePlayStatus(PlayStatusPacket $packet) : bool{
		return false;
	}

	public function handleServerToClientHandshake(ServerToClientHandshakePacket $packet) : bool{
		return false;
	}

	public function handleClientToServerHandshake(ClientToServerHandshakePacket $packet) : bool{
		return false;
	}

	public function handleDisconnect(DisconnectPacket $packet) : bool{
		return false;
	}

	public function handleResourcePacksInfo(ResourcePacksInfoPacket $packet) : bool{
		return false;
	}

	public function handleResourcePackStack(ResourcePackStackPacket $packet) : bool{
		return false;
	}

	public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
		return false;
	}

	public function handleText(TextPacket $packet) : bool{
		return false;
	}

	public function handleSetTime(SetTimePacket $packet) : bool{
		return false;
	}

	public function handleStartGame(StartGamePacket $packet) : bool{
		return false;
	}

	public function handleAddPlayer(AddPlayerPacket $packet) : bool{
		return false;
	}

	public function handleAddActor(AddActorPacket $packet) : bool{
		return false;
	}

	public function handleRemoveActor(RemoveActorPacket $packet) : bool{
		return false;
	}

	public function handleAddItemActor(AddItemActorPacket $packet) : bool{
		return false;
	}

	public function handleTakeItemActor(TakeItemActorPacket $packet) : bool{
		return false;
	}

	public function handleMoveActorAbsolute(MoveActorAbsolutePacket $packet) : bool{
		return false;
	}

	public function handleMovePlayer(MovePlayerPacket $packet) : bool{
		return false;
	}

	public function handleRiderJump(RiderJumpPacket $packet) : bool{
		return false;
	}

	public function handleUpdateBlock(UpdateBlockPacket $packet) : bool{
		return false;
	}

	public function handleAddPainting(AddPaintingPacket $packet) : bool{
		return false;
	}

	public function handleTickSync(TickSyncPacket $packet) : bool{
		return false;
	}

	public function handleLevelSoundEventPacketV1(LevelSoundEventPacketV1 $packet) : bool{
		return false;
	}

	public function handleLevelEvent(LevelEventPacket $packet) : bool{
		return false;
	}

	public function handleBlockEvent(BlockEventPacket $packet) : bool{
		return false;
	}

	public function handleActorEvent(ActorEventPacket $packet) : bool{
		return false;
	}

	public function handleMobEffect(MobEffectPacket $packet) : bool{
		return false;
	}

	public function handleUpdateAttributes(UpdateAttributesPacket $packet) : bool{
		return false;
	}

	public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
		return false;
	}

	public function handleMobEquipment(MobEquipmentPacket $packet) : bool{
		return false;
	}

	public function handleMobArmorEquipment(MobArmorEquipmentPacket $packet) : bool{
		return false;
	}

	public function handleInteract(InteractPacket $packet) : bool{
		return false;
	}

	public function handleBlockPickRequest(BlockPickRequestPacket $packet) : bool{
		return false;
	}

	public function handleActorPickRequest(ActorPickRequestPacket $packet) : bool{
		return false;
	}

	public function handlePlayerAction(PlayerActionPacket $packet) : bool{
		return false;
	}

	public function handleActorFall(ActorFallPacket $packet) : bool{
		return false;
	}

	public function handleHurtArmor(HurtArmorPacket $packet) : bool{
		return false;
	}

	public function handleSetActorData(SetActorDataPacket $packet) : bool{
		return false;
	}

	public function handleSetActorMotion(SetActorMotionPacket $packet) : bool{
		return false;
	}

	public function handleSetActorLink(SetActorLinkPacket $packet) : bool{
		return false;
	}

	public function handleSetHealth(SetHealthPacket $packet) : bool{
		return false;
	}

	public function handleSetSpawnPosition(SetSpawnPositionPacket $packet) : bool{
		return false;
	}

	public function handleAnimate(AnimatePacket $packet) : bool{
		return false;
	}

	public function handleRespawn(RespawnPacket $packet) : bool{
		return false;
	}

	public function handleContainerOpen(ContainerOpenPacket $packet) : bool{
		return false;
	}

	public function handleContainerClose(ContainerClosePacket $packet) : bool{
		return false;
	}

	public function handlePlayerHotbar(PlayerHotbarPacket $packet) : bool{
		return false;
	}

	public function handleInventoryContent(InventoryContentPacket $packet) : bool{
		return false;
	}

	public function handleInventorySlot(InventorySlotPacket $packet) : bool{
		return false;
	}

	public function handleContainerSetData(ContainerSetDataPacket $packet) : bool{
		return false;
	}

	public function handleCraftingData(CraftingDataPacket $packet) : bool{
		return false;
	}

	public function handleCraftingEvent(CraftingEventPacket $packet) : bool{
		return false;
	}

	public function handleGuiDataPickItem(GuiDataPickItemPacket $packet) : bool{
		return false;
	}

	public function handleAdventureSettings(AdventureSettingsPacket $packet) : bool{
		return false;
	}

	public function handleBlockActorData(BlockActorDataPacket $packet) : bool{
		return false;
	}

	public function handlePlayerInput(PlayerInputPacket $packet) : bool{
		return false;
	}

	public function handleLevelChunk(LevelChunkPacket $packet) : bool{
		return false;
	}

	public function handleSetCommandsEnabled(SetCommandsEnabledPacket $packet) : bool{
		return false;
	}

	public function handleSetDifficulty(SetDifficultyPacket $packet) : bool{
		return false;
	}

	public function handleChangeDimension(ChangeDimensionPacket $packet) : bool{
		return false;
	}

	public function handleSetPlayerGameType(SetPlayerGameTypePacket $packet) : bool{
		return false;
	}

	public function handlePlayerList(PlayerListPacket $packet) : bool{
		return false;
	}

	public function handleSimpleEvent(SimpleEventPacket $packet) : bool{
		return false;
	}

	public function handleEvent(EventPacket $packet) : bool{
		return false;
	}

	public function handleSpawnExperienceOrb(SpawnExperienceOrbPacket $packet) : bool{
		return false;
	}

	public function handleClientboundMapItemData(ClientboundMapItemDataPacket $packet) : bool{
		return false;
	}

	public function handleMapInfoRequest(MapInfoRequestPacket $packet) : bool{
		return false;
	}

	public function handleRequestChunkRadius(RequestChunkRadiusPacket $packet) : bool{
		return false;
	}

	public function handleChunkRadiusUpdated(ChunkRadiusUpdatedPacket $packet) : bool{
		return false;
	}

	public function handleItemFrameDropItem(ItemFrameDropItemPacket $packet) : bool{
		return false;
	}

	public function handleGameRulesChanged(GameRulesChangedPacket $packet) : bool{
		return false;
	}

	public function handleCamera(CameraPacket $packet) : bool{
		return false;
	}

	public function handleBossEvent(BossEventPacket $packet) : bool{
		return false;
	}

	public function handleShowCredits(ShowCreditsPacket $packet) : bool{
		return false;
	}

	public function handleAvailableCommands(AvailableCommandsPacket $packet) : bool{
		return false;
	}

	public function handleCommandRequest(CommandRequestPacket $packet) : bool{
		return false;
	}

	public function handleCommandBlockUpdate(CommandBlockUpdatePacket $packet) : bool{
		return false;
	}

	public function handleCommandOutput(CommandOutputPacket $packet) : bool{
		return false;
	}

	public function handleUpdateTrade(UpdateTradePacket $packet) : bool{
		return false;
	}

	public function handleUpdateEquip(UpdateEquipPacket $packet) : bool{
		return false;
	}

	public function handleResourcePackDataInfo(ResourcePackDataInfoPacket $packet) : bool{
		return false;
	}

	public function handleResourcePackChunkData(ResourcePackChunkDataPacket $packet) : bool{
		return false;
	}

	public function handleResourcePackChunkRequest(ResourcePackChunkRequestPacket $packet) : bool{
		return false;
	}

	public function handleTransfer(TransferPacket $packet) : bool{
		return false;
	}

	public function handlePlaySound(PlaySoundPacket $packet) : bool{
		return false;
	}

	public function handleStopSound(StopSoundPacket $packet) : bool{
		return false;
	}

	public function handleSetTitle(SetTitlePacket $packet) : bool{
		return false;
	}

	public function handleAddBehaviorTree(AddBehaviorTreePacket $packet) : bool{
		return false;
	}

	public function handleStructureBlockUpdate(StructureBlockUpdatePacket $packet) : bool{
		return false;
	}

	public function handleShowStoreOffer(ShowStoreOfferPacket $packet) : bool{
		return false;
	}

	public function handlePurchaseReceipt(PurchaseReceiptPacket $packet) : bool{
		return false;
	}

	public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{
		return false;
	}

	public function handleSubClientLogin(SubClientLoginPacket $packet) : bool{
		return false;
	}

	public function handleAutomationClientConnect(AutomationClientConnectPacket $packet) : bool{
		return false;
	}

	public function handleSetLastHurtBy(SetLastHurtByPacket $packet) : bool{
		return false;
	}

	public function handleBookEdit(BookEditPacket $packet) : bool{
		return false;
	}

	public function handleNpcRequest(NpcRequestPacket $packet) : bool{
		return false;
	}

	public function handlePhotoTransfer(PhotoTransferPacket $packet) : bool{
		return false;
	}

	public function handleModalFormRequest(ModalFormRequestPacket $packet) : bool{
		return false;
	}

	public function handleModalFormResponse(ModalFormResponsePacket $packet) : bool{
		return false;
	}

	public function handleServerSettingsRequest(ServerSettingsRequestPacket $packet) : bool{
		return false;
	}

	public function handleServerSettingsResponse(ServerSettingsResponsePacket $packet) : bool{
		return false;
	}

	public function handleShowProfile(ShowProfilePacket $packet) : bool{
		return false;
	}

	public function handleSetDefaultGameType(SetDefaultGameTypePacket $packet) : bool{
		return false;
	}

	public function handleRemoveObjective(RemoveObjectivePacket $packet) : bool{
		return false;
	}

	public function handleSetDisplayObjective(SetDisplayObjectivePacket $packet) : bool{
		return false;
	}

	public function handleSetScore(SetScorePacket $packet) : bool{
		return false;
	}

	public function handleLabTable(LabTablePacket $packet) : bool{
		return false;
	}

	public function handleUpdateBlockSynced(UpdateBlockSyncedPacket $packet) : bool{
		return false;
	}

	public function handleMoveActorDelta(MoveActorDeltaPacket $packet) : bool{
		return false;
	}

	public function handleSetScoreboardIdentity(SetScoreboardIdentityPacket $packet) : bool{
		return false;
	}

	public function handleSetLocalPlayerAsInitialized(SetLocalPlayerAsInitializedPacket $packet) : bool{
		return false;
	}

	public function handleUpdateSoftEnum(UpdateSoftEnumPacket $packet) : bool{
		return false;
	}

	public function handleNetworkStackLatency(NetworkStackLatencyPacket $packet) : bool{
		return false;
	}

	public function handleScriptCustomEvent(ScriptCustomEventPacket $packet) : bool{
		return false;
	}

	public function handleSpawnParticleEffect(SpawnParticleEffectPacket $packet) : bool{
		return false;
	}

	public function handleAvailableActorIdentifiers(AvailableActorIdentifiersPacket $packet) : bool{
		return false;
	}

	public function handleLevelSoundEventPacketV2(LevelSoundEventPacketV2 $packet) : bool{
		return false;
	}

	public function handleNetworkChunkPublisherUpdate(NetworkChunkPublisherUpdatePacket $packet) : bool{
		return false;
	}

	public function handleBiomeDefinitionList(BiomeDefinitionListPacket $packet) : bool{
		return false;
	}

	public function handleLevelSoundEvent(LevelSoundEventPacket $packet) : bool{
		return false;
	}

	public function handleLevelEventGeneric(LevelEventGenericPacket $packet) : bool{
		return false;
	}

	public function handleLecternUpdate(LecternUpdatePacket $packet) : bool{
		return false;
	}

	public function handleVideoStreamConnect(VideoStreamConnectPacket $packet) : bool{
		return false;
	}

	public function handleAddEntity(AddEntityPacket $packet) : bool{
		return false;
	}

	public function handleRemoveEntity(RemoveEntityPacket $packet) : bool{
		return false;
	}

	public function handleClientCacheStatus(ClientCacheStatusPacket $packet) : bool{
		return false;
	}

	public function handleOnScreenTextureAnimation(OnScreenTextureAnimationPacket $packet) : bool{
		return false;
	}

	public function handleMapCreateLockedCopy(MapCreateLockedCopyPacket $packet) : bool{
		return false;
	}

	public function handleStructureTemplateDataRequest(StructureTemplateDataRequestPacket $packet) : bool{
		return false;
	}

	public function handleStructureTemplateDataResponse(StructureTemplateDataResponsePacket $packet) : bool{
		return false;
	}

	public function handleUpdateBlockProperties(UpdateBlockPropertiesPacket $packet) : bool{
		return false;
	}

	public function handleClientCacheBlobStatus(ClientCacheBlobStatusPacket $packet) : bool{
		return false;
	}

	public function handleClientCacheMissResponse(ClientCacheMissResponsePacket $packet) : bool{
		return false;
	}

	public function handleEducationSettings(EducationSettingsPacket $packet) : bool{
		return false;
	}

	public function handleEmote(EmotePacket $packet) : bool{
		return false;
	}

	public function handleMultiplayerSettings(MultiplayerSettingsPacket $packet) : bool{
		return false;
	}

	public function handleSettingsCommand(SettingsCommandPacket $packet) : bool{
		return false;
	}

	public function handleAnvilDamage(AnvilDamagePacket $packet) : bool{
		return false;
	}

	public function handleCompletedUsingItem(CompletedUsingItemPacket $packet) : bool{
		return false;
	}

	public function handleNetworkSettings(NetworkSettingsPacket $packet) : bool{
		return false;
	}

	public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
		return false;
	}
}
<?php

/*
 * RakLib network library
 *
 *
 * This project is not affiliated with Jenkins Software LLC nor RakNet.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 */

declare(strict_types=1);

namespace raklib\protocol;

use function ceil;
use function chr;
use function ord;
use function strlen;
use function substr;

use pocketmine\utils\Binary;

class EncapsulatedPacket{
	private const RELIABILITY_SHIFT = 5;
	private const RELIABILITY_FLAGS = 0b111 << self::RELIABILITY_SHIFT;

	private const SPLIT_FLAG = 0b00010000;

	/** @var int */
	public $reliability;
	/** @var bool */
	public $hasSplit = false;
	/** @var int */
	public $length = 0;
	/** @var int|null */
	public $messageIndex;
	/** @var int|null */
	public $sequenceIndex;
	/** @var int|null */
	public $orderIndex;
	/** @var int|null */
	public $orderChannel;
	/** @var int|null */
	public $splitCount;
	/** @var int|null */
	public $splitID;
	/** @var int|null */
	public $splitIndex;
	/** @var string */
	public $buffer = "";
	/** @var bool */
	public $needACK = false;
	/** @var int|null */
	public $identifierACK;

	/**
	 * Decodes an EncapsulatedPacket from bytes generated by toInternalBinary().
	 *
	 * @param string   $bytes
	 * @param int|null $offset reference parameter, will be set to the number of bytes read
	 *
	 * @return EncapsulatedPacket
	 */
	public static function fromInternalBinary(string $bytes, ?int &$offset = null) : EncapsulatedPacket{
		$packet = new EncapsulatedPacket();

		$offset = 0;
		$packet->reliability = ord($bytes[$offset++]);

		$length = (\unpack("N", substr($bytes, $offset, 4))[1] << 32 >> 32);
		$offset += 4;
		$packet->identifierACK = (\unpack("N", substr($bytes, $offset, 4))[1] << 32 >> 32); //TODO: don't read this for non-ack-receipt reliabilities
		$offset += 4;

		if(PacketReliability::isSequencedOrOrdered($packet->reliability)){
			$packet->orderChannel = ord($bytes[$offset++]);
		}

		$packet->buffer = substr($bytes, $offset, $length);
		$offset += $length;
		return $packet;
	}

	/**
	 * Encodes data needed for the EncapsulatedPacket to be transmitted from RakLib to the implementation's thread.
	 * @return string
	 */
	public function toInternalBinary() : string{
		return
			chr($this->reliability) .
			(\pack("N", strlen($this->buffer))) .
			(\pack("N", $this->identifierACK ?? -1)) . //TODO: don't write this for non-ack-receipt reliabilities
			(PacketReliability::isSequencedOrOrdered($this->reliability) ? chr($this->orderChannel) : "") .
			$this->buffer;
	}

	/**
	 * @param string $binary
	 * @param int    $offset reference parameter
	 *
	 * @return EncapsulatedPacket
	 */
	public static function fromBinary(string $binary, ?int &$offset = null) : EncapsulatedPacket{

		$packet = new EncapsulatedPacket();

		$flags = ord($binary[0]);
		$packet->reliability = $reliability = ($flags & self::RELIABILITY_FLAGS) >> self::RELIABILITY_SHIFT;
		$packet->hasSplit = $hasSplit = ($flags & self::SPLIT_FLAG) > 0;

		$length = (int) ceil((\unpack("n", substr($binary, 1, 2))[1]) / 8);
		$offset = 3;

		if(PacketReliability::isReliable($reliability)){
			$packet->messageIndex = (\unpack("V", substr($binary, $offset, 3) . "\x00")[1]);
			$offset += 3;
		}

		if(PacketReliability::isSequenced($reliability)){
			$packet->sequenceIndex = (\unpack("V", substr($binary, $offset, 3) . "\x00")[1]);
			$offset += 3;
		}

		if(PacketReliability::isSequencedOrOrdered($reliability)){
			$packet->orderIndex = (\unpack("V", substr($binary, $offset, 3) . "\x00")[1]);
			$offset += 3;
			$packet->orderChannel = ord($binary[$offset++]);
		}

		if($hasSplit){
			$packet->splitCount = (\unpack("N", substr($binary, $offset, 4))[1] << 32 >> 32);
			$offset += 4;
			$packet->splitID = (\unpack("n", substr($binary, $offset, 2))[1]);
			$offset += 2;
			$packet->splitIndex = (\unpack("N", substr($binary, $offset, 4))[1] << 32 >> 32);
			$offset += 4;
		}

		$packet->buffer = substr($binary, $offset, $length);
		$offset += $length;

		return $packet;
	}

	/**
	 * @return string
	 */
	public function toBinary() : string{
		return
			chr(($this->reliability << self::RELIABILITY_SHIFT) | ($this->hasSplit ? self::SPLIT_FLAG : 0)) .
			(\pack("n", strlen($this->buffer) << 3)) .
			(PacketReliability::isReliable($this->reliability) ? (\substr(\pack("V", $this->messageIndex), 0, -1)) : "") .
			(PacketReliability::isSequenced($this->reliability) ? (\substr(\pack("V", $this->sequenceIndex), 0, -1)) : "") .
			(PacketReliability::isSequencedOrOrdered($this->reliability) ? (\substr(\pack("V", $this->orderIndex), 0, -1)) . chr($this->orderChannel) : "") .
			($this->hasSplit ? (\pack("N", $this->splitCount)) . (\pack("n", $this->splitID)) . (\pack("N", $this->splitIndex)) : "")
			. $this->buffer;
	}

	public function getTotalLength() : int{
		return
			1 + //reliability
			2 + //length
			(PacketReliability::isReliable($this->reliability) ? 3 : 0) + //message index
			(PacketReliability::isSequenced($this->reliability) ? 3 : 0) + //sequence index
			(PacketReliability::isSequencedOrOrdered($this->reliability) ? 3 + 1 : 0) + //order index (3) + order channel (1)
			($this->hasSplit ? 4 + 2 + 4 : 0) + //split count (4) + split ID (2) + split index (4)
			strlen($this->buffer);
	}

	public function __toString() : string{
		return $this->toBinary();
	}
}
<?php

/*
 * RakLib network library
 *
 *
 * This project is not affiliated with Jenkins Software LLC nor RakNet.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 */

declare(strict_types=1);

namespace raklib\protocol;

abstract class PacketReliability{

	/*
	 * From https://github.com/OculusVR/RakNet/blob/master/Source/PacketPriority.h
	 *
	 * Default: 0b010 (2) or 0b011 (3)
	 */

	public const UNRELIABLE = 0;
	public const UNRELIABLE_SEQUENCED = 1;
	public const RELIABLE = 2;
	public const RELIABLE_ORDERED = 3;
	public const RELIABLE_SEQUENCED = 4;
	public const UNRELIABLE_WITH_ACK_RECEIPT = 5;
	public const RELIABLE_WITH_ACK_RECEIPT = 6;
	public const RELIABLE_ORDERED_WITH_ACK_RECEIPT = 7;

	public static function isReliable(int $reliability) : bool{
		return (
			$reliability === self::RELIABLE or
			$reliability === self::RELIABLE_ORDERED or
			$reliability === self::RELIABLE_SEQUENCED or
			$reliability === self::RELIABLE_WITH_ACK_RECEIPT or
			$reliability === self::RELIABLE_ORDERED_WITH_ACK_RECEIPT
		);
	}

	public static function isSequenced(int $reliability) : bool{
		return (
			$reliability === self::UNRELIABLE_SEQUENCED or
			$reliability === self::RELIABLE_SEQUENCED
		);
	}

	public static function isOrdered(int $reliability) : bool{
		return (
			$reliability === self::RELIABLE_ORDERED or
			$reliability === self::RELIABLE_ORDERED_WITH_ACK_RECEIPT
		);
	}

	public static function isSequencedOrOrdered(int $reliability) : bool{
		return (
			$reliability === self::UNRELIABLE_SEQUENCED or
			$reliability === self::RELIABLE_ORDERED or
			$reliability === self::RELIABLE_SEQUENCED or
			$reliability === self::RELIABLE_ORDERED_WITH_ACK_RECEIPT
		);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\server;

use pocketmine\event\Cancellable;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\Player;

class DataPacketReceiveEvent extends ServerEvent implements Cancellable{
	/** @var DataPacket */
	private $packet;
	/** @var Player */
	private $player;

	public function __construct(Player $player, DataPacket $packet){
		$this->packet = $packet;
		$this->player = $player;
	}

	public function getPacket() : DataPacket{
		return $this->packet;
	}

	public function getPlayer() : Player{
		return $this->player;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

class SkinData{

	/** @var string */
	private $skinId;
	/** @var string */
	private $resourcePatch;
	/** @var SkinImage */
	private $skinImage;
	/** @var SkinAnimation[] */
	private $animations;
	/** @var SkinImage */
	private $capeImage;
	/** @var string */
	private $geometryData;
	/** @var string */
	private $animationData;
	/** @var bool */
	private $persona;
	/** @var bool */
	private $premium;
	/** @var bool */
	private $personaCapeOnClassic;
	/** @var string */
	private $capeId;

	/**
	 * @param SkinAnimation[] $animations
	 */
	public function __construct(string $skinId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = ""){
		$this->skinId = $skinId;
		$this->resourcePatch = $resourcePatch;
		$this->skinImage = $skinImage;
		$this->animations = $animations;
		$this->capeImage = $capeImage;
		$this->geometryData = $geometryData;
		$this->animationData = $animationData;
		$this->premium = $premium;
		$this->persona = $persona;
		$this->personaCapeOnClassic = $personaCapeOnClassic;
		$this->capeId = $capeId;
	}

	public function getSkinId() : string{
		return $this->skinId;
	}

	public function getResourcePatch() : string{
		return $this->resourcePatch;
	}

	public function getSkinImage() : SkinImage{
		return $this->skinImage;
	}

	/**
	 * @return SkinAnimation[]
	 */
	public function getAnimations() : array{
		return $this->animations;
	}

	public function getCapeImage() : SkinImage{
		return $this->capeImage;
	}

	public function getGeometryData() : string{
		return $this->geometryData;
	}

	public function getAnimationData() : string{
		return $this->animationData;
	}

	public function isPersona() : bool{
		return $this->persona;
	}

	public function isPremium() : bool{
		return $this->premium;
	}

	public function isPersonaCapeOnClassic() : bool{
		return $this->personaCapeOnClassic;
	}

	public function getCapeId() : string{
		return $this->capeId;
	}

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

use function strlen;

class SkinImage{

	/** @var int */
	private $height;
	/** @var int */
	private $width;
	/** @var string */
	private $data;

	public function __construct(int $height, int $width, string $data){
		if($height < 0 or $width < 0){
			throw new \InvalidArgumentException("Height and width cannot be negative");
		}
		if(($expected = $height * $width * 4) !== ($actual = strlen($data))){
			throw new \InvalidArgumentException("Data should be exactly $expected bytes, got $actual bytes");
		}
		$this->height = $height;
		$this->width = $width;
		$this->data = $data;
	}

	public static function fromLegacy(string $data) : SkinImage{
		switch(strlen($data)){
			case 64 * 32 * 4:
				return new self(64, 32, $data);
			case 64 * 64 * 4:
				return new self(64, 64, $data);
			case 128 * 64 * 4:
				return new self(128, 64, $data);
			case 128 * 128 * 4:
				return new self(128, 128, $data);
		}

		throw new \InvalidArgumentException("Unknown size");
	}

	public function getHeight() : int{
		return $this->height;
	}

	public function getWidth() : int{
		return $this->width;
	}

	public function getData() : string{
		return $this->data;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

/**
 * Accessor for SkinAdapter
 */
class SkinAdapterSingleton{
	/** @var SkinAdapter|null */
	private static $skinAdapter = null;

	public static function get() : SkinAdapter{
		if(self::$skinAdapter === null){
			self::$skinAdapter = new LegacySkinAdapter();
		}
		return self::$skinAdapter;
	}

	public static function set(SkinAdapter $adapter) : void{
		self::$skinAdapter = $adapter;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

use pocketmine\entity\Skin;

use function is_string;
use function json_decode;
use function json_encode;
use function random_bytes;
use function str_repeat;

class LegacySkinAdapter implements SkinAdapter{

	public function toSkinData(Skin $skin) : SkinData{
		$capeData = $skin->getCapeData();
		$capeImage = $capeData === "" ? new SkinImage(0, 0, "") : new SkinImage(32, 64, $capeData);
		$geometryName = $skin->getGeometryName();
		if($geometryName === ""){
			$geometryName = "geometry.humanoid.custom";
		}
		return new SkinData(
			$skin->getSkinId(),
			json_encode(["geometry" => ["default" => $geometryName]]),
			SkinImage::fromLegacy($skin->getSkinData()), [],
			$capeImage,
			$skin->getGeometryData()
		);
	}

	public function fromSkinData(SkinData $data) : Skin{
		if($data->isPersona()){
			return new Skin("Standard_Custom", str_repeat(random_bytes(3) . "\xff", 2048));
		}

		$capeData = $data->isPersonaCapeOnClassic() ? "" : $data->getCapeImage()->getData();

		$geometryName = "";
		$resourcePatch = json_decode($data->getResourcePatch(), true);
		if(isset($resourcePatch["geometry"]["default"]) && is_string($resourcePatch["geometry"]["default"])){
			$geometryName = $resourcePatch["geometry"]["default"];
		}else{
			//TODO: Kick for invalid skin
		}

		return new Skin($data->getSkinId(), $data->getSkinImage()->getData(), $capeData, $geometryName, $data->getGeometryData());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

use pocketmine\entity\Skin;

/**
 * Used to convert new skin data to the skin entity or old skin entity to skin data.
 */
interface SkinAdapter{

	/**
	 * Allows you to convert a skin entity to skin data.
	 */
	public function toSkinData(Skin $skin) : SkinData;

	/**
	 * Allows you to convert skin data to a skin entity.
	 */
	public function fromSkinData(SkinData $data) : Skin;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use Ahc\Json\Comment as CommentedJsonDecoder;
use function implode;
use function in_array;
use function json_encode;
use function strlen;

class Skin{
	public const ACCEPTED_SKIN_SIZES = [
		64 * 32 * 4,
		64 * 64 * 4,
		128 * 128 * 4
	];

	/** @var string */
	private $skinId;
	/** @var string */
	private $skinData;
	/** @var string */
	private $capeData;
	/** @var string */
	private $geometryName;
	/** @var string */
	private $geometryData;

	public function __construct(string $skinId, string $skinData, string $capeData = "", string $geometryName = "", string $geometryData = ""){
		$this->skinId = $skinId;
		$this->skinData = $skinData;
		$this->capeData = $capeData;
		$this->geometryName = $geometryName;
		$this->geometryData = $geometryData;
	}

	/**
	 * @deprecated
	 */
	public function isValid() : bool{
		try{
			$this->validate();
			return true;
		}catch(\InvalidArgumentException $e){
			return false;
		}
	}

	/**
	 * @throws \InvalidArgumentException
	 */
	public function validate() : void{
		if($this->skinId === ""){
			throw new \InvalidArgumentException("Skin ID must not be empty");
		}
		$len = strlen($this->skinData);
		if(!in_array($len, self::ACCEPTED_SKIN_SIZES, true)){
			throw new \InvalidArgumentException("Invalid skin data size $len bytes (allowed sizes: " . implode(", ", self::ACCEPTED_SKIN_SIZES) . ")");
		}
		if($this->capeData !== "" and strlen($this->capeData) !== 8192){
			throw new \InvalidArgumentException("Invalid cape data size " . strlen($this->capeData) . " bytes (must be exactly 8192 bytes)");
		}
		//TODO: validate geometry
	}

	public function getSkinId() : string{
		return $this->skinId;
	}

	public function getSkinData() : string{
		return $this->skinData;
	}

	public function getCapeData() : string{
		return $this->capeData;
	}

	public function getGeometryName() : string{
		return $this->geometryName;
	}

	public function getGeometryData() : string{
		return $this->geometryData;
	}

	/**
	 * Hack to cut down on network overhead due to skins, by un-pretty-printing geometry JSON.
	 *
	 * Mojang, some stupid reason, send every single model for every single skin in the selected skin-pack.
	 * Not only that, they are pretty-printed.
	 * TODO: find out what model crap can be safely dropped from the packet (unless it gets fixed first)
	 */
	public function debloatGeometryData() : void{
		if($this->geometryData !== ""){
			$this->geometryData = (string) json_encode((new CommentedJsonDecoder())->decode($this->geometryData));
		}
	}
}
<?php

/*
 * This file is part of the PHP-JSON-COMMENT package.
 *
 * (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
 *     <https://github.com/adhocore>
 *
 * Licensed under MIT license.
 */

namespace Ahc\Json;

/**
 * JSON comment stripper.
 *
 * @author Jitendra Adhikari <jiten.adhikary@gmail.com>
 */
class Comment
{
    /** @var int The current index being scanned */
    protected $index   = -1;

    /** @var bool If current char is within a string */
    protected $inStr   = false;

    /** @var int Lines of comments 0 = no comment, 1 = single line, 2 = multi lines */
    protected $comment = 0;

    /**
     * Strip comments from JSON string.
     *
     * @param string $json
     *
     * @return string The comment stripped JSON.
     */
    public function strip($json)
    {
        if (!\preg_match('%\/(\/|\*)%', $json)) {
            return $json;
        }

        $this->reset();

        return $this->doStrip($json);
    }

    protected function reset()
    {
        $this->index   = -1;
        $this->inStr   = false;
        $this->comment = 0;
    }

    protected function doStrip($json)
    {
        $return = '';

        while (isset($json[++$this->index])) {
            list($prev, $char, $next) = $this->getSegments($json);

            if ($this->inStringOrCommentEnd($prev, $char, $char . $next)) {
                $return .= $char;

                continue;
            }

            $wasSingle = 1 === $this->comment;
            if ($this->hasCommentEnded($char, $char . $next) && $wasSingle) {
                $return = \rtrim($return) . $char;
            }

            $this->index += $char . $next === '*/' ? 1 : 0;
        }

        return $return;
    }

    protected function getSegments($json)
    {
        return [
            isset($json[$this->index - 1]) ? $json[$this->index - 1] : '',
            $json[$this->index],
            isset($json[$this->index + 1]) ? $json[$this->index + 1] : '',
        ];
    }

    protected function inStringOrCommentEnd($prev, $char, $charnext)
    {
        return $this->inString($char, $prev) || $this->inCommentEnd($charnext);
    }

    protected function inString($char, $prev)
    {
        if (0 === $this->comment && $char === '"' && $prev !== '\\') {
            $this->inStr = !$this->inStr;
        }

        return $this->inStr;
    }

    protected function inCommentEnd($charnext)
    {
        if (!$this->inStr && 0 === $this->comment) {
            $this->comment = $charnext === '//' ? 1 : ($charnext === '/*' ? 2 : 0);
        }

        return 0 === $this->comment;
    }

    protected function hasCommentEnded($char, $charnext)
    {
        $singleEnded = $this->comment === 1 && $char == "\n";
        $multiEnded  = $this->comment === 2 && $charnext == '*/';

        if ($singleEnded || $multiEnded) {
            $this->comment = 0;

            return true;
        }

        return false;
    }

    /**
     * Strip comments and decode JSON string.
     *
     * @param string    $json
     * @param bool|bool $assoc
     * @param int|int   $depth
     * @param int|int   $options
     *
     * @see http://php.net/json_decode [JSON decode native function]
     *
     * @throws \RuntimeException When decode fails.
     *
     * @return mixed
     */
    public function decode($json, $assoc = false, $depth = 512, $options = 0)
    {
        $decoded = \json_decode($this->strip($json), $assoc, $depth, $options);

        if (\JSON_ERROR_NONE !== $err = \json_last_error()) {
            $msg = 'JSON decode failed';

            if (\function_exists('json_last_error_msg')) {
                $msg .= ': ' . \json_last_error_msg();
            }

            throw new \RuntimeException($msg, $err);
        }

        return $decoded;
    }

    /**
     * Static alias of decode().
     */
    public static function parse($json, $assoc = false, $depth = 512, $options = 0)
    {
        static $parser;

        if (!$parser) {
            $parser = new static;
        }

        return $parser->decode($json, $assoc, $depth, $options);
    }
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\event\Cancellable;
use pocketmine\Player;

/**
 * Called when a player connects to the server, prior to authentication taking place.
 * Cancelling this event will cause the player to be disconnected with the kick message set.
 *
 * This event should be used to decide if the player may continue to login to the server. Do things like checking
 * bans, whitelisting, server-full etc here.
 *
 * WARNING: Any information about the player CANNOT be trusted at this stage, because they are not authenticated and
 * could be a hacker posing as another player.
 *
 * WARNING: Due to internal bad architecture, the player is not fully constructed at this stage, and errors might occur
 * when calling API methods on the player. Tread with caution.
 */
class PlayerPreLoginEvent extends PlayerEvent implements Cancellable{
	/** @var string */
	protected $kickMessage;

	public function __construct(Player $player, string $kickMessage){
		$this->player = $player;
		$this->kickMessage = $kickMessage;
	}

	public function setKickMessage(string $kickMessage) : void{
		$this->kickMessage = $kickMessage;
	}

	public function getKickMessage() : string{
		return $this->kickMessage;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Player-only related events
 */
namespace pocketmine\event\player;

use pocketmine\event\Event;
use pocketmine\Player;

abstract class PlayerEvent extends Event{
	/** @var Player */
	protected $player;

	public function getPlayer() : Player{
		return $this->player;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe;

use pocketmine\network\mcpe\protocol\LoginPacket;
use pocketmine\Player;
use pocketmine\scheduler\AsyncTask;
use pocketmine\Server;
use function assert;
use function base64_decode;
use function chr;
use function explode;
use function json_decode;
use function ltrim;
use function openssl_verify;
use function ord;
use function str_split;
use function strlen;
use function strtr;
use function time;
use function wordwrap;
use const OPENSSL_ALGO_SHA384;

class VerifyLoginTask extends AsyncTask{

	public const MOJANG_ROOT_PUBLIC_KEY = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V";

	private const CLOCK_DRIFT_MAX = 60;

	/** @var LoginPacket */
	private $packet;

	/**
	 * @var string|null
	 * Whether the keychain signatures were validated correctly. This will be set to an error message if any link in the
	 * keychain is invalid for whatever reason (bad signature, not in nbf-exp window, etc). If this is non-null, the
	 * keychain might have been tampered with. The player will always be disconnected if this is non-null.
	 */
	private $error = "Unknown";
	/**
	 * @var bool
	 * Whether the player is logged into Xbox Live. This is true if any link in the keychain is signed with the Mojang
	 * root public key.
	 */
	private $authenticated = false;

	public function __construct(Player $player, LoginPacket $packet){
		$this->storeLocal($player);
		$this->packet = $packet;
	}

	public function onRun(){
		$packet = $this->packet; //Get it in a local variable to make sure it stays unserialized

		try{
			$currentKey = null;
			$first = true;

			foreach($packet->chainData["chain"] as $jwt){
				$this->validateToken($jwt, $currentKey, $first);
				$first = false;
			}

			$this->validateToken($packet->clientDataJwt, $currentKey);

			$this->error = null;
		}catch(VerifyLoginException $e){
			$this->error = $e->getMessage();
		}
	}

	/**
	 * @throws VerifyLoginException if errors are encountered
	 */
	private function validateToken(string $jwt, ?string &$currentPublicKey, bool $first = false) : void{
		[$headB64, $payloadB64, $sigB64] = explode('.', $jwt);

		$headers = json_decode(base64_decode(strtr($headB64, '-_', '+/'), true), true);

		if($currentPublicKey === null){
			if(!$first){
				throw new VerifyLoginException("%pocketmine.disconnect.invalidSession.missingKey");
			}

			//First link, check that it is self-signed
			$currentPublicKey = $headers["x5u"];
		}

		$plainSignature = base64_decode(strtr($sigB64, '-_', '+/'), true);

		//OpenSSL wants a DER-encoded signature, so we extract R and S from the plain signature and crudely serialize it.

		assert(strlen($plainSignature) === 96);

		[$rString, $sString] = str_split($plainSignature, 48);

		$rString = ltrim($rString, "\x00");
		if(ord($rString[0]) >= 128){ //Would be considered signed, pad it with an extra zero
			$rString = "\x00" . $rString;
		}

		$sString = ltrim($sString, "\x00");
		if(ord($sString[0]) >= 128){ //Would be considered signed, pad it with an extra zero
			$sString = "\x00" . $sString;
		}

		//0x02 = Integer ASN.1 tag
		$sequence = "\x02" . chr(strlen($rString)) . $rString . "\x02" . chr(strlen($sString)) . $sString;
		//0x30 = Sequence ASN.1 tag
		$derSignature = "\x30" . chr(strlen($sequence)) . $sequence;

		$v = openssl_verify("$headB64.$payloadB64", $derSignature, "-----BEGIN PUBLIC KEY-----\n" . wordwrap($currentPublicKey, 64, "\n", true) . "\n-----END PUBLIC KEY-----\n", OPENSSL_ALGO_SHA384);
		if($v !== 1){
			throw new VerifyLoginException("%pocketmine.disconnect.invalidSession.badSignature");
		}

		if($currentPublicKey === self::MOJANG_ROOT_PUBLIC_KEY){
			$this->authenticated = true; //we're signed into xbox live
		}

		$claims = json_decode(base64_decode(strtr($payloadB64, '-_', '+/'), true), true);

		$time = time();
		if(isset($claims["nbf"]) and $claims["nbf"] > $time + self::CLOCK_DRIFT_MAX){
			throw new VerifyLoginException("%pocketmine.disconnect.invalidSession.tooEarly");
		}

		if(isset($claims["exp"]) and $claims["exp"] < $time - self::CLOCK_DRIFT_MAX){
			throw new VerifyLoginException("%pocketmine.disconnect.invalidSession.tooLate");
		}

		$currentPublicKey = $claims["identityPublicKey"] ?? null; //if there are further links, the next link should be signed with this
	}

	public function onCompletion(Server $server){
		/** @var Player $player */
		$player = $this->fetchLocal();
		if(!$player->isConnected()){
			$server->getLogger()->error("Player " . $player->getName() . " was disconnected before their login could be verified");
		}else{
			$player->onVerifyCompleted($this->packet, $this->error, $this->authenticated);
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;

use pocketmine\utils\Binary;

class DoubleTag extends NamedTag{
	/** @var float */
	private $value;

	/**
	 * @param string $name
	 * @param float  $value
	 */
	public function __construct(string $name = "", float $value = 0.0){
		parent::__construct($name);
		$this->value = $value;
	}

	public function getType() : int{
		return NBT::TAG_Double;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = $nbt->getDouble();
	}

	public function write(NBTStream $nbt) : void{
		$nbt->putDouble($this->value);
	}

	/**
	 * @return float
	 */
	public function getValue() : float{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\nbt\tag;

use pocketmine\nbt\NBT;
use pocketmine\nbt\NBTStream;
use pocketmine\nbt\ReaderTracker;

use pocketmine\utils\Binary;

class FloatTag extends NamedTag{
	/** @var float */
	private $value;

	/**
	 * @param string $name
	 * @param float  $value
	 */
	public function __construct(string $name = "", float $value = 0.0){
		parent::__construct($name);
		$this->value = $value;
	}

	public function getType() : int{
		return NBT::TAG_Float;
	}

	public function read(NBTStream $nbt, ReaderTracker $tracker) : void{
		$this->value = $nbt->getFloat();
	}

	public function write(NBTStream $nbt) : void{
		$nbt->putFloat($this->value);
	}

	/**
	 * @return float
	 */
	public function getValue() : float{
		return $this->value;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\server;

use pocketmine\event\Cancellable;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\Player;

class DataPacketSendEvent extends ServerEvent implements Cancellable{
	/** @var DataPacket */
	private $packet;
	/** @var Player */
	private $player;

	public function __construct(Player $player, DataPacket $packet){
		$this->packet = $packet;
		$this->player = $player;
	}

	public function getPacket() : DataPacket{
		return $this->packet;
	}

	public function getPlayer() : Player{
		return $this->player;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe;

use raklib\protocol\EncapsulatedPacket;

class CachedEncapsulatedPacket extends EncapsulatedPacket{
	/** @var string|null */
	private $internalData = null;

	public function toInternalBinary() : string{
		return $this->internalData ?? ($this->internalData = parent::toInternalBinary());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use function assert;
use function is_float;
use function is_int;
use function is_string;

class DataPropertyManager{

	/**
	 * @var mixed[][]
	 * @phpstan-var array<int, array{0: int, 1: mixed}>
	 */
	private $properties = [];

	/**
	 * @var mixed[][]
	 * @phpstan-var array<int, array{0: int, 1: mixed}>
	 */
	private $dirtyProperties = [];

	public function __construct(){

	}

	public function getByte(int $key) : ?int{
		$value = $this->getPropertyValue($key, Entity::DATA_TYPE_BYTE);
		assert(is_int($value) or $value === null);
		return $value;
	}

	public function setByte(int $key, int $value, bool $force = false) : void{
		$this->setPropertyValue($key, Entity::DATA_TYPE_BYTE, $value, $force);
	}

	public function getShort(int $key) : ?int{
		$value = $this->getPropertyValue($key, Entity::DATA_TYPE_SHORT);
		assert(is_int($value) or $value === null);
		return $value;
	}

	public function setShort(int $key, int $value, bool $force = false) : void{
		$this->setPropertyValue($key, Entity::DATA_TYPE_SHORT, $value, $force);
	}

	public function getInt(int $key) : ?int{
		$value = $this->getPropertyValue($key, Entity::DATA_TYPE_INT);
		assert(is_int($value) or $value === null);
		return $value;
	}

	public function setInt(int $key, int $value, bool $force = false) : void{
		$this->setPropertyValue($key, Entity::DATA_TYPE_INT, $value, $force);
	}

	public function getFloat(int $key) : ?float{
		$value = $this->getPropertyValue($key, Entity::DATA_TYPE_FLOAT);
		assert(is_float($value) or $value === null);
		return $value;
	}

	public function setFloat(int $key, float $value, bool $force = false) : void{
		$this->setPropertyValue($key, Entity::DATA_TYPE_FLOAT, $value, $force);
	}

	public function getString(int $key) : ?string{
		$value = $this->getPropertyValue($key, Entity::DATA_TYPE_STRING);
		assert(is_string($value) or $value === null);
		return $value;
	}

	public function setString(int $key, string $value, bool $force = false) : void{
		$this->setPropertyValue($key, Entity::DATA_TYPE_STRING, $value, $force);
	}

	public function getCompoundTag(int $key) : ?CompoundTag{
		$value = $this->getPropertyValue($key, Entity::DATA_TYPE_COMPOUND_TAG);
		assert($value instanceof CompoundTag or $value === null);
		return $value;
	}

	public function setCompoundTag(int $key, CompoundTag $value, bool $force = false) : void{
		$this->setPropertyValue($key, Entity::DATA_TYPE_COMPOUND_TAG, $value, $force);
	}

	public function getBlockPos(int $key) : ?Vector3{
		$value = $this->getPropertyValue($key, Entity::DATA_TYPE_POS);
		assert($value instanceof Vector3 or $value === null);
		return $value;
	}

	public function setBlockPos(int $key, ?Vector3 $value, bool $force = false) : void{
		$this->setPropertyValue($key, Entity::DATA_TYPE_POS, $value !== null ? $value->floor() : null, $force);
	}

	public function getLong(int $key) : ?int{
		$value = $this->getPropertyValue($key, Entity::DATA_TYPE_LONG);
		assert(is_int($value) or $value === null);
		return $value;
	}

	public function setLong(int $key, int $value, bool $force = false) : void{
		$this->setPropertyValue($key, Entity::DATA_TYPE_LONG, $value, $force);
	}

	public function getVector3(int $key) : ?Vector3{
		$value = $this->getPropertyValue($key, Entity::DATA_TYPE_VECTOR3F);
		assert($value instanceof Vector3 or $value === null);
		return $value;
	}

	public function setVector3(int $key, ?Vector3 $value, bool $force = false) : void{
		$this->setPropertyValue($key, Entity::DATA_TYPE_VECTOR3F, $value !== null ? $value->asVector3() : null, $force);
	}

	public function removeProperty(int $key) : void{
		unset($this->properties[$key]);
	}

	public function hasProperty(int $key) : bool{
		return isset($this->properties[$key]);
	}

	public function getPropertyType(int $key) : int{
		if(isset($this->properties[$key])){
			return $this->properties[$key][0];
		}

		return -1;
	}

	private function checkType(int $key, int $type) : void{
		if(isset($this->properties[$key]) and $this->properties[$key][0] !== $type){
			throw new \RuntimeException("Expected type $type, but have " . $this->properties[$key][0]);
		}
	}

	/**
	 * @return mixed
	 */
	public function getPropertyValue(int $key, int $type){
		if($type !== -1){
			$this->checkType($key, $type);
		}
		return isset($this->properties[$key]) ? $this->properties[$key][1] : null;
	}

	/**
	 * @param mixed $value
	 */
	public function setPropertyValue(int $key, int $type, $value, bool $force = false) : void{
		if(!$force){
			$this->checkType($key, $type);
		}
		$this->properties[$key] = $this->dirtyProperties[$key] = [$type, $value];
	}

	/**
	 * Returns all properties.
	 *
	 * @return mixed[][]
	 * @phpstan-return array<int, array{0: int, 1: mixed}>
	 */
	public function getAll() : array{
		return $this->properties;
	}

	/**
	 * Returns properties that have changed and need to be broadcasted.
	 *
	 * @return mixed[][]
	 * @phpstan-return array<int, array{0: int, 1: mixed}>
	 */
	public function getDirty() : array{
		return $this->dirtyProperties;
	}

	/**
	 * Clears records of dirty properties.
	 */
	public function clearDirtyProperties() : void{
		$this->dirtyProperties = [];
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\entity;

use function array_filter;

/**
 * @phpstan-implements \ArrayAccess<int, float>
 */
class AttributeMap implements \ArrayAccess{
	/** @var Attribute[] */
	private $attributes = [];

	public function addAttribute(Attribute $attribute) : void{
		$this->attributes[$attribute->getId()] = $attribute;
	}

	public function getAttribute(int $id) : ?Attribute{
		return $this->attributes[$id] ?? null;
	}

	/**
	 * @return Attribute[]
	 */
	public function getAll() : array{
		return $this->attributes;
	}

	/**
	 * @return Attribute[]
	 */
	public function needSend() : array{
		return array_filter($this->attributes, function(Attribute $attribute) : bool{
			return $attribute->isSyncable() and $attribute->isDesynchronized();
		});
	}

	/**
	 * @param int $offset
	 */
	public function offsetExists($offset) : bool{
		return isset($this->attributes[$offset]);
	}

	/**
	 * @param int $offset
	 */
	public function offsetGet($offset) : float{
		return $this->attributes[$offset]->getValue();
	}

	/**
	 * @param int   $offset
	 * @param float $value
	 */
	public function offsetSet($offset, $value) : void{
		$this->attributes[$offset]->setValue($value);
	}

	/**
	 * @param int $offset
	 */
	public function offsetUnset($offset) : void{
		throw new \RuntimeException("Could not unset an attribute from an attribute map");
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
use pocketmine\Player;
use function array_merge;

class ArmorInventory extends BaseInventory{
	public const SLOT_HEAD = 0;
	public const SLOT_CHEST = 1;
	public const SLOT_LEGS = 2;
	public const SLOT_FEET = 3;

	/** @var Living */
	protected $holder;

	public function __construct(Living $holder){
		$this->holder = $holder;
		parent::__construct();
	}

	public function getHolder() : Living{
		return $this->holder;
	}

	public function getName() : string{
		return "Armor";
	}

	public function getDefaultSize() : int{
		return 4;
	}

	public function getHelmet() : Item{
		return $this->getItem(self::SLOT_HEAD);
	}

	public function getChestplate() : Item{
		return $this->getItem(self::SLOT_CHEST);
	}

	public function getLeggings() : Item{
		return $this->getItem(self::SLOT_LEGS);
	}

	public function getBoots() : Item{
		return $this->getItem(self::SLOT_FEET);
	}

	public function setHelmet(Item $helmet) : bool{
		return $this->setItem(self::SLOT_HEAD, $helmet);
	}

	public function setChestplate(Item $chestplate) : bool{
		return $this->setItem(self::SLOT_CHEST, $chestplate);
	}

	public function setLeggings(Item $leggings) : bool{
		return $this->setItem(self::SLOT_LEGS, $leggings);
	}

	public function setBoots(Item $boots) : bool{
		return $this->setItem(self::SLOT_FEET, $boots);
	}

	public function sendSlot(int $index, $target) : void{
		if($target instanceof Player){
			$target = [$target];
		}

		$pk = new MobArmorEquipmentPacket();
		$pk->entityRuntimeId = $this->getHolder()->getId();
		$pk->head = $this->getHelmet();
		$pk->chest = $this->getChestplate();
		$pk->legs = $this->getLeggings();
		$pk->feet = $this->getBoots();
		$pk->encode();

		foreach($target as $player){
			if($player === $this->getHolder()){
				/** @var Player $player */

				$pk2 = new InventorySlotPacket();
				$pk2->windowId = $player->getWindowId($this);
				$pk2->inventorySlot = $index;
				$pk2->item = $this->getItem($index);
				$player->dataPacket($pk2);
			}else{
				$player->dataPacket($pk);
			}
		}
	}

	public function sendContents($target) : void{
		if($target instanceof Player){
			$target = [$target];
		}

		$pk = new MobArmorEquipmentPacket();
		$pk->entityRuntimeId = $this->getHolder()->getId();
		$pk->head = $this->getHelmet();
		$pk->chest = $this->getChestplate();
		$pk->legs = $this->getLeggings();
		$pk->feet = $this->getBoots();
		$pk->encode();

		foreach($target as $player){
			if($player === $this->getHolder()){
				$pk2 = new InventoryContentPacket();
				$pk2->windowId = $player->getWindowId($this);
				$pk2->items = $this->getContents(true);
				$player->dataPacket($pk2);
			}else{
				$player->dataPacket($pk);
			}
		}
	}

	/**
	 * @return Player[]
	 */
	public function getViewers() : array{
		return array_merge(parent::getViewers(), $this->holder->getViewers());
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\event\inventory\InventoryOpenEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\Player;
use function array_slice;
use function count;
use function max;
use function min;
use function spl_object_hash;

abstract class BaseInventory implements Inventory{

	/** @var int */
	protected $maxStackSize = Inventory::MAX_STACK;
	/** @var string */
	protected $name;
	/** @var string */
	protected $title;
	/**
	 * @var \SplFixedArray|(Item|null)[]
	 * @phpstan-var \SplFixedArray<Item|null>
	 */
	protected $slots;
	/** @var Player[] */
	protected $viewers = [];
	/** @var InventoryEventProcessor */
	protected $eventProcessor;

	/**
	 * @param Item[] $items
	 */
	public function __construct(array $items = [], int $size = null, string $title = null){
		$this->slots = new \SplFixedArray($size ?? $this->getDefaultSize());
		$this->title = $title ?? $this->getName();

		$this->setContents($items, false);
	}

	abstract public function getName() : string;

	public function getTitle() : string{
		return $this->title;
	}

	/**
	 * Returns the size of the inventory.
	 */
	public function getSize() : int{
		return $this->slots->getSize();
	}

	/**
	 * Sets the new size of the inventory.
	 * WARNING: If the size is smaller, any items past the new size will be lost.
	 *
	 * @return void
	 */
	public function setSize(int $size){
		$this->slots->setSize($size);
	}

	abstract public function getDefaultSize() : int;

	public function getMaxStackSize() : int{
		return $this->maxStackSize;
	}

	public function getItem(int $index) : Item{
		return $this->slots[$index] !== null ? clone $this->slots[$index] : ItemFactory::get(Item::AIR, 0, 0);
	}

	/**
	 * @return Item[]
	 */
	public function getContents(bool $includeEmpty = false) : array{
		$contents = [];
		$air = null;

		foreach($this->slots as $i => $slot){
			if($slot !== null){
				$contents[$i] = clone $slot;
			}elseif($includeEmpty){
				$contents[$i] = $air ?? ($air = ItemFactory::get(Item::AIR, 0, 0));
			}
		}

		return $contents;
	}

	/**
	 * @param Item[] $items
	 */
	public function setContents(array $items, bool $send = true) : void{
		if(count($items) > $this->getSize()){
			$items = array_slice($items, 0, $this->getSize(), true);
		}

		for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
			if(!isset($items[$i])){
				if($this->slots[$i] !== null){
					$this->clear($i, false);
				}
			}else{
				if(!$this->setItem($i, $items[$i], false)){
					$this->clear($i, false);
				}
			}
		}

		if($send){
			$this->sendContents($this->getViewers());
		}
	}

	/**
	 * Drops the contents of the inventory into the specified Level at the specified position and clears the inventory
	 * contents.
	 */
	public function dropContents(Level $level, Vector3 $position) : void{
		foreach($this->getContents() as $item){
			$level->dropItem($position, $item);
		}

		$this->clearAll();
	}

	public function setItem(int $index, Item $item, bool $send = true) : bool{
		if($item->isNull()){
			$item = ItemFactory::get(Item::AIR, 0, 0);
		}else{
			$item = clone $item;
		}

		$oldItem = $this->getItem($index);
		if($this->eventProcessor !== null){
			$newItem = $this->eventProcessor->onSlotChange($this, $index, $oldItem, $item);
			if($newItem === null){
				return false;
			}
		}else{
			$newItem = $item;
		}

		$this->slots[$index] = $newItem->isNull() ? null : $newItem;
		$this->onSlotChange($index, $oldItem, $send);

		return true;
	}

	public function contains(Item $item) : bool{
		$count = max(1, $item->getCount());
		$checkDamage = !$item->hasAnyDamageValue();
		$checkTags = $item->hasCompoundTag();
		foreach($this->getContents() as $i){
			if($item->equals($i, $checkDamage, $checkTags)){
				$count -= $i->getCount();
				if($count <= 0){
					return true;
				}
			}
		}

		return false;
	}

	public function all(Item $item) : array{
		$slots = [];
		$checkDamage = !$item->hasAnyDamageValue();
		$checkTags = $item->hasCompoundTag();
		foreach($this->getContents() as $index => $i){
			if($item->equals($i, $checkDamage, $checkTags)){
				$slots[$index] = $i;
			}
		}

		return $slots;
	}

	public function remove(Item $item) : void{
		$checkDamage = !$item->hasAnyDamageValue();
		$checkTags = $item->hasCompoundTag();

		foreach($this->getContents() as $index => $i){
			if($item->equals($i, $checkDamage, $checkTags)){
				$this->clear($index);
			}
		}
	}

	public function first(Item $item, bool $exact = false) : int{
		$count = $exact ? $item->getCount() : max(1, $item->getCount());
		$checkDamage = $exact || !$item->hasAnyDamageValue();
		$checkTags = $exact || $item->hasCompoundTag();

		foreach($this->getContents() as $index => $i){
			if($item->equals($i, $checkDamage, $checkTags) and ($i->getCount() === $count or (!$exact and $i->getCount() > $count))){
				return $index;
			}
		}

		return -1;
	}

	public function firstEmpty() : int{
		foreach($this->slots as $i => $slot){
			if($slot === null or $slot->isNull()){
				return $i;
			}
		}

		return -1;
	}

	public function isSlotEmpty(int $index) : bool{
		return $this->slots[$index] === null or $this->slots[$index]->isNull();
	}

	public function canAddItem(Item $item) : bool{
		$item = clone $item;
		for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
			$slot = $this->getItem($i);
			if($item->equals($slot)){
				if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){
					$item->setCount($item->getCount() - $diff);
				}
			}elseif($slot->isNull()){
				$item->setCount($item->getCount() - $this->getMaxStackSize());
			}

			if($item->getCount() <= 0){
				return true;
			}
		}

		return false;
	}

	public function addItem(Item ...$slots) : array{
		/** @var Item[] $itemSlots */
		/** @var Item[] $slots */
		$itemSlots = [];
		foreach($slots as $slot){
			if(!$slot->isNull()){
				$itemSlots[] = clone $slot;
			}
		}

		$emptySlots = [];

		for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
			$item = $this->getItem($i);
			if($item->isNull()){
				$emptySlots[] = $i;
			}

			foreach($itemSlots as $index => $slot){
				if($slot->equals($item) and $item->getCount() < $item->getMaxStackSize()){
					$amount = min($item->getMaxStackSize() - $item->getCount(), $slot->getCount(), $this->getMaxStackSize());
					if($amount > 0){
						$slot->setCount($slot->getCount() - $amount);
						$item->setCount($item->getCount() + $amount);
						$this->setItem($i, $item);
						if($slot->getCount() <= 0){
							unset($itemSlots[$index]);
						}
					}
				}
			}

			if(count($itemSlots) === 0){
				break;
			}
		}

		if(count($itemSlots) > 0 and count($emptySlots) > 0){
			foreach($emptySlots as $slotIndex){
				//This loop only gets the first item, then goes to the next empty slot
				foreach($itemSlots as $index => $slot){
					$amount = min($slot->getMaxStackSize(), $slot->getCount(), $this->getMaxStackSize());
					$slot->setCount($slot->getCount() - $amount);
					$item = clone $slot;
					$item->setCount($amount);
					$this->setItem($slotIndex, $item);
					if($slot->getCount() <= 0){
						unset($itemSlots[$index]);
					}
					break;
				}
			}
		}

		return $itemSlots;
	}

	public function removeItem(Item ...$slots) : array{
		/** @var Item[] $itemSlots */
		/** @var Item[] $slots */
		$itemSlots = [];
		foreach($slots as $slot){
			if(!$slot->isNull()){
				$itemSlots[] = clone $slot;
			}
		}

		for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
			$item = $this->getItem($i);
			if($item->isNull()){
				continue;
			}

			foreach($itemSlots as $index => $slot){
				if($slot->equals($item, !$slot->hasAnyDamageValue(), $slot->hasCompoundTag())){
					$amount = min($item->getCount(), $slot->getCount());
					$slot->setCount($slot->getCount() - $amount);
					$item->setCount($item->getCount() - $amount);
					$this->setItem($i, $item);
					if($slot->getCount() <= 0){
						unset($itemSlots[$index]);
					}
				}
			}

			if(count($itemSlots) === 0){
				break;
			}
		}

		return $itemSlots;
	}

	public function clear(int $index, bool $send = true) : bool{
		return $this->setItem($index, ItemFactory::get(Item::AIR, 0, 0), $send);
	}

	public function clearAll(bool $send = true) : void{
		for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
			$this->clear($i, false);
		}

		if($send){
			$this->sendContents($this->getViewers());
		}
	}

	/**
	 * @return Player[]
	 */
	public function getViewers() : array{
		return $this->viewers;
	}

	/**
	 * Removes the inventory window from all players currently viewing it.
	 *
	 * @param bool $force Force removal of permanent windows such as the player's own inventory. Used internally.
	 */
	public function removeAllViewers(bool $force = false) : void{
		foreach($this->viewers as $hash => $viewer){
			$viewer->removeWindow($this, $force);
			unset($this->viewers[$hash]);
		}
	}

	public function setMaxStackSize(int $size) : void{
		$this->maxStackSize = $size;
	}

	public function open(Player $who) : bool{
		$ev = new InventoryOpenEvent($this, $who);
		$ev->call();
		if($ev->isCancelled()){
			return false;
		}
		$this->onOpen($who);

		return true;
	}

	public function close(Player $who) : void{
		$this->onClose($who);
	}

	public function onOpen(Player $who) : void{
		$this->viewers[spl_object_hash($who)] = $who;
	}

	public function onClose(Player $who) : void{
		unset($this->viewers[spl_object_hash($who)]);
	}

	public function onSlotChange(int $index, Item $before, bool $send) : void{
		if($send){
			$this->sendSlot($index, $this->getViewers());
		}
	}

	/**
	 * @param Player|Player[] $target
	 */
	public function sendContents($target) : void{
		if($target instanceof Player){
			$target = [$target];
		}

		$pk = new InventoryContentPacket();
		$pk->items = $this->getContents(true);

		foreach($target as $player){
			if(($id = $player->getWindowId($this)) === ContainerIds::NONE){
				$this->close($player);
				continue;
			}
			$pk->windowId = $id;
			$player->dataPacket($pk);
		}
	}

	/**
	 * @param Player|Player[] $target
	 */
	public function sendSlot(int $index, $target) : void{
		if($target instanceof Player){
			$target = [$target];
		}

		$pk = new InventorySlotPacket();
		$pk->inventorySlot = $index;
		$pk->item = $this->getItem($index);

		foreach($target as $player){
			if(($id = $player->getWindowId($this)) === ContainerIds::NONE){
				$this->close($player);
				continue;
			}
			$pk->windowId = $id;
			$player->dataPacket($pk);
		}
	}

	public function slotExists(int $slot) : bool{
		return $slot >= 0 and $slot < $this->slots->getSize();
	}

	public function getEventProcessor() : ?InventoryEventProcessor{
		return $this->eventProcessor;
	}

	public function setEventProcessor(?InventoryEventProcessor $eventProcessor) : void{
		$this->eventProcessor = $eventProcessor;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Handles the creation of virtual inventories or mapped to an InventoryHolder
 */
namespace pocketmine\inventory;

use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\Player;

interface Inventory{
	public const MAX_STACK = 64;

	public function getSize() : int;

	public function getMaxStackSize() : int;

	public function setMaxStackSize(int $size) : void;

	public function getName() : string;

	public function getTitle() : string;

	public function getItem(int $index) : Item;

	/**
	 * Puts an Item in a slot.
	 * If a plugin refuses the update or $index is invalid, it'll return false
	 */
	public function setItem(int $index, Item $item, bool $send = true) : bool;

	/**
	 * Stores the given Items in the inventory. This will try to fill
	 * existing stacks and empty slots as well as it can.
	 *
	 * Returns the Items that did not fit.
	 *
	 * @param Item ...$slots
	 *
	 * @return Item[]
	 */
	public function addItem(Item ...$slots) : array;

	/**
	 * Checks if a given Item can be added to the inventory
	 */
	public function canAddItem(Item $item) : bool;

	/**
	 * Removes the given Item from the inventory.
	 * It will return the Items that couldn't be removed.
	 *
	 * @param Item ...$slots
	 *
	 * @return Item[]
	 */
	public function removeItem(Item ...$slots) : array;

	/**
	 * @return Item[]
	 */
	public function getContents(bool $includeEmpty = false) : array;

	/**
	 * @param Item[] $items
	 */
	public function setContents(array $items, bool $send = true) : void;

	/**
	 * Drops the contents of the inventory into the specified Level at the specified position and clears the inventory
	 * contents.
	 */
	public function dropContents(Level $level, Vector3 $position) : void;

	/**
	 * @param Player|Player[] $target
	 */
	public function sendContents($target) : void;

	/**
	 * @param Player|Player[] $target
	 */
	public function sendSlot(int $index, $target) : void;

	/**
	 * Checks if the inventory contains any Item with the same material data.
	 * It will check id, amount, and metadata (if not null)
	 */
	public function contains(Item $item) : bool;

	/**
	 * Will return all the Items that has the same id and metadata (if not null).
	 * Won't check amount
	 *
	 * @return Item[]
	 */
	public function all(Item $item) : array;

	/**
	 * Returns the first slot number containing an item with the same ID, damage (if not any-damage), NBT (if not empty)
	 * and count >= to the count of the specified item stack.
	 *
	 * If $exact is true, only items with equal ID, damage, NBT and count will match.
	 */
	public function first(Item $item, bool $exact = false) : int;

	/**
	 * Returns the first empty slot, or -1 if not found
	 */
	public function firstEmpty() : int;

	/**
	 * Returns whether the given slot is empty.
	 */
	public function isSlotEmpty(int $index) : bool;

	/**
	 * Will remove all the Items that has the same id and metadata (if not null)
	 */
	public function remove(Item $item) : void;

	/**
	 * Will clear a specific slot
	 */
	public function clear(int $index, bool $send = true) : bool;

	/**
	 * Clears all the slots
	 */
	public function clearAll(bool $send = true) : void;

	/**
	 * Gets all the Players viewing the inventory
	 * Players will view their inventory at all times, even when not open.
	 *
	 * @return Player[]
	 */
	public function getViewers() : array;

	public function onOpen(Player $who) : void;

	/**
	 * Tries to open the inventory to a player
	 */
	public function open(Player $who) : bool;

	public function close(Player $who) : void;

	public function onClose(Player $who) : void;

	public function onSlotChange(int $index, Item $before, bool $send) : void;

	/**
	 * Returns whether the specified slot exists in the inventory.
	 */
	public function slotExists(int $slot) : bool;

	public function getEventProcessor() : ?InventoryEventProcessor;

	public function setEventProcessor(?InventoryEventProcessor $eventProcessor) : void;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\entity\Entity;
use pocketmine\event\entity\EntityArmorChangeEvent;
use pocketmine\item\Item;

class ArmorInventoryEventProcessor implements InventoryEventProcessor{
	/** @var Entity */
	private $entity;

	public function __construct(Entity $entity){
		$this->entity = $entity;
	}

	public function onSlotChange(Inventory $inventory, int $slot, Item $oldItem, Item $newItem) : ?Item{
		$ev = new EntityArmorChangeEvent($this->entity, $oldItem, $newItem, $slot);
		$ev->call();
		if($ev->isCancelled()){
			return null;
		}

		return $ev->getNewItem();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\item\Item;

/**
 * This interface can be used to listen for events on a specific Inventory.
 *
 * If you want to listen to changes on an inventory, create a class implementing this interface and implement its
 * methods, then register it onto the inventory or inventories that you want to receive events for.
 */
interface InventoryEventProcessor{

	/**
	 * Called prior to a slot in the given inventory changing. This is called by inventories that this listener is
	 * attached to.
	 *
	 * @return Item|null that should be used in place of $newItem, or null if the slot change should not proceed.
	 */
	public function onSlotChange(Inventory $inventory, int $slot, Item $oldItem, Item $newItem) : ?Item;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\entity\Human;
use pocketmine\event\player\PlayerItemHeldEvent;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\Player;
use function in_array;
use function is_array;

class PlayerInventory extends BaseInventory{

	/** @var Human */
	protected $holder;

	/** @var int */
	protected $itemInHandIndex = 0;

	public function __construct(Human $player){
		$this->holder = $player;
		parent::__construct();
	}

	public function getName() : string{
		return "Player";
	}

	public function getDefaultSize() : int{
		return 36;
	}

	/**
	 * Called when a client equips a hotbar slot. This method should not be used by plugins.
	 * This method will call PlayerItemHeldEvent.
	 *
	 * @param int $hotbarSlot Number of the hotbar slot to equip.
	 *
	 * @return bool if the equipment change was successful, false if not.
	 */
	public function equipItem(int $hotbarSlot) : bool{
		$holder = $this->getHolder();
		if(!$this->isHotbarSlot($hotbarSlot)){
			if($holder instanceof Player){
				$this->sendContents($holder);
			}
			return false;
		}

		if($holder instanceof Player){
			$ev = new PlayerItemHeldEvent($holder, $this->getItem($hotbarSlot), $hotbarSlot);
			$ev->call();

			if($ev->isCancelled()){
				$this->sendHeldItem($holder);
				return false;
			}
		}
		$this->setHeldItemIndex($hotbarSlot, false);

		return true;
	}

	private function isHotbarSlot(int $slot) : bool{
		return $slot >= 0 and $slot <= $this->getHotbarSize();
	}

	/**
	 * @throws \InvalidArgumentException
	 */
	private function throwIfNotHotbarSlot(int $slot) : void{
		if(!$this->isHotbarSlot($slot)){
			throw new \InvalidArgumentException("$slot is not a valid hotbar slot index (expected 0 - " . ($this->getHotbarSize() - 1) . ")");
		}
	}

	/**
	 * Returns the item in the specified hotbar slot.
	 *
	 * @throws \InvalidArgumentException if the hotbar slot index is out of range
	 */
	public function getHotbarSlotItem(int $hotbarSlot) : Item{
		$this->throwIfNotHotbarSlot($hotbarSlot);
		return $this->getItem($hotbarSlot);
	}

	/**
	 * Returns the hotbar slot number the holder is currently holding.
	 */
	public function getHeldItemIndex() : int{
		return $this->itemInHandIndex;
	}

	/**
	 * Sets which hotbar slot the player is currently loading.
	 *
	 * @param int  $hotbarSlot 0-8 index of the hotbar slot to hold
	 * @param bool $send Whether to send updates back to the inventory holder. This should usually be true for plugin calls.
	 *                    It should only be false to prevent feedback loops of equipment packets between client and server.
	 *
	 * @return void
	 * @throws \InvalidArgumentException if the hotbar slot is out of range
	 */
	public function setHeldItemIndex(int $hotbarSlot, bool $send = true){
		$this->throwIfNotHotbarSlot($hotbarSlot);

		$this->itemInHandIndex = $hotbarSlot;

		if($this->getHolder() instanceof Player and $send){
			$this->sendHeldItem($this->getHolder());
		}

		$this->sendHeldItem($this->getHolder()->getViewers());
	}

	/**
	 * Returns the currently-held item.
	 */
	public function getItemInHand() : Item{
		return $this->getHotbarSlotItem($this->itemInHandIndex);
	}

	/**
	 * Sets the item in the currently-held slot to the specified item.
	 */
	public function setItemInHand(Item $item) : bool{
		return $this->setItem($this->getHeldItemIndex(), $item);
	}

	/**
	 * Sends the currently-held item to specified targets.
	 *
	 * @param Player|Player[] $target
	 *
	 * @return void
	 */
	public function sendHeldItem($target){
		$item = $this->getItemInHand();

		$pk = new MobEquipmentPacket();
		$pk->entityRuntimeId = $this->getHolder()->getId();
		$pk->item = $item;
		$pk->inventorySlot = $pk->hotbarSlot = $this->getHeldItemIndex();
		$pk->windowId = ContainerIds::INVENTORY;

		if(!is_array($target)){
			$target->dataPacket($pk);
			if($target === $this->getHolder()){
				$this->sendSlot($this->getHeldItemIndex(), $target);
			}
		}else{
			$this->getHolder()->getLevel()->getServer()->broadcastPacket($target, $pk);
			if(in_array($this->getHolder(), $target, true)){
				$this->sendSlot($this->getHeldItemIndex(), $this->getHolder());
			}
		}
	}

	/**
	 * Returns the number of slots in the hotbar.
	 */
	public function getHotbarSize() : int{
		return 9;
	}

	/**
	 * @return void
	 */
	public function sendCreativeContents(){
		//TODO: this mess shouldn't be in here
		$holder = $this->getHolder();
		if(!($holder instanceof Player)){
			throw new \LogicException("Cannot send creative inventory contents to non-player inventory holder");
		}
		$pk = new InventoryContentPacket();
		$pk->windowId = ContainerIds::CREATIVE;

		if(!$holder->isSpectator()){ //fill it for all gamemodes except spectator
			foreach(Item::getCreativeItems() as $i => $item){
				$pk->items[$i] = clone $item;
			}
		}

		$holder->dataPacket($pk);
	}

	/**
	 * This override is here for documentation and code completion purposes only.
	 * @return Human|Player
	 */
	public function getHolder(){
		return $this->holder;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\level\Position;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\types\WindowTypes;
use pocketmine\tile\EnderChest;

class EnderChestInventory extends ChestInventory{

	/** @var Position */
	protected $holder;

	public function __construct(){
		ContainerInventory::__construct(new Position());
	}

	public function getNetworkType() : int{
		return WindowTypes::CONTAINER;
	}

	public function getName() : string{
		return "EnderChest";
	}

	public function getDefaultSize() : int{
		return 27;
	}

	/**
	 * Set the holder's position to that of a tile
	 *
	 * @return void
	 */
	public function setHolderPosition(EnderChest $enderChest){
		$this->holder->setComponents($enderChest->getFloorX(), $enderChest->getFloorY(), $enderChest->getFloorZ());
		$this->holder->setLevel($enderChest->getLevel());
	}

	protected function getOpenSound() : int{
		return LevelSoundEventPacket::SOUND_ENDERCHEST_OPEN;
	}

	protected function getCloseSound() : int{
		return LevelSoundEventPacket::SOUND_ENDERCHEST_CLOSED;
	}

	/**
	 * This override is here for documentation and code completion purposes only.
	 * @return Position
	 */
	public function getHolder(){
		return $this->holder;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\level\Position;
use pocketmine\network\mcpe\protocol\BlockEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\types\WindowTypes;
use pocketmine\Player;
use pocketmine\tile\Chest;
use function count;

class ChestInventory extends ContainerInventory{

	/** @var Chest */
	protected $holder;

	public function __construct(Chest $tile){
		parent::__construct($tile);
	}

	public function getNetworkType() : int{
		return WindowTypes::CONTAINER;
	}

	public function getName() : string{
		return "Chest";
	}

	public function getDefaultSize() : int{
		return 27;
	}

	/**
	 * This override is here for documentation and code completion purposes only.
	 * @return Chest|Position
	 */
	public function getHolder(){
		return $this->holder;
	}

	protected function getOpenSound() : int{
		return LevelSoundEventPacket::SOUND_CHEST_OPEN;
	}

	protected function getCloseSound() : int{
		return LevelSoundEventPacket::SOUND_CHEST_CLOSED;
	}

	public function onOpen(Player $who) : void{
		parent::onOpen($who);

		if(count($this->getViewers()) === 1 and $this->getHolder()->isValid()){
			//TODO: this crap really shouldn't be managed by the inventory
			$this->broadcastBlockEventPacket(true);
			$this->getHolder()->getLevel()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound());
		}
	}

	public function onClose(Player $who) : void{
		if(count($this->getViewers()) === 1 and $this->getHolder()->isValid()){
			//TODO: this crap really shouldn't be managed by the inventory
			$this->broadcastBlockEventPacket(false);
			$this->getHolder()->getLevel()->broadcastLevelSoundEvent($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound());
		}
		parent::onClose($who);
	}

	protected function broadcastBlockEventPacket(bool $isOpen) : void{
		$holder = $this->getHolder();

		$pk = new BlockEventPacket();
		$pk->x = (int) $holder->x;
		$pk->y = (int) $holder->y;
		$pk->z = (int) $holder->z;
		$pk->eventType = 1; //it's always 1 for a chest
		$pk->eventData = $isOpen ? 1 : 0;
		$holder->getLevel()->broadcastPacketToViewers($holder, $pk);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\entity\Entity;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
use pocketmine\Player;

abstract class ContainerInventory extends BaseInventory{
	/** @var Vector3 */
	protected $holder;

	public function __construct(Vector3 $holder, array $items = [], int $size = null, string $title = null){
		$this->holder = $holder;
		parent::__construct($items, $size, $title);
	}

	public function onOpen(Player $who) : void{
		parent::onOpen($who);
		$pk = new ContainerOpenPacket();
		$pk->windowId = $who->getWindowId($this);
		$pk->type = $this->getNetworkType();
		$holder = $this->getHolder();

		$pk->x = $pk->y = $pk->z = 0;
		$pk->entityUniqueId = -1;

		if($holder instanceof Entity){
			$pk->entityUniqueId = $holder->getId();
		}else{
			$pk->x = $holder->getFloorX();
			$pk->y = $holder->getFloorY();
			$pk->z = $holder->getFloorZ();
		}

		$who->dataPacket($pk);

		$this->sendContents($who);
	}

	public function onClose(Player $who) : void{
		$pk = new ContainerClosePacket();
		$pk->windowId = $who->getWindowId($this);
		$who->dataPacket($pk);
		parent::onClose($who);
	}

	/**
	 * Returns the Minecraft PE inventory type used to show the inventory window to clients.
	 */
	abstract public function getNetworkType() : int;

	/**
	 * @return Vector3
	 */
	public function getHolder(){
		return $this->holder;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\entity\Entity;
use pocketmine\event\entity\EntityInventoryChangeEvent;
use pocketmine\item\Item;

class EntityInventoryEventProcessor implements InventoryEventProcessor{
	/** @var Entity */
	private $entity;

	public function __construct(Entity $entity){
		$this->entity = $entity;
	}

	public function onSlotChange(Inventory $inventory, int $slot, Item $oldItem, Item $newItem) : ?Item{
		$ev = new EntityInventoryChangeEvent($this->entity, $oldItem, $newItem, $slot);
		$ev->call();
		if($ev->isCancelled()){
			return null;
		}

		return $ev->getNewItem();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\inventory;

use pocketmine\event\Cancellable;
use pocketmine\inventory\Inventory;
use pocketmine\Player;

class InventoryOpenEvent extends InventoryEvent implements Cancellable{
	/** @var Player */
	private $who;

	public function __construct(Inventory $inventory, Player $who){
		$this->who = $who;
		parent::__construct($inventory);
	}

	public function getPlayer() : Player{
		return $this->who;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Inventory related events
 */
namespace pocketmine\event\inventory;

use pocketmine\entity\Human;
use pocketmine\event\Event;
use pocketmine\inventory\Inventory;

abstract class InventoryEvent extends Event{
	/** @var Inventory */
	protected $inventory;

	public function __construct(Inventory $inventory){
		$this->inventory = $inventory;
	}

	public function getInventory() : Inventory{
		return $this->inventory;
	}

	/**
	 * @return Human[]
	 */
	public function getViewers() : array{
		return $this->inventory->getViewers();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\Player;

class PlayerCursorInventory extends BaseInventory{
	/** @var Player */
	protected $holder;

	public function __construct(Player $holder){
		$this->holder = $holder;
		parent::__construct();
	}

	public function getName() : string{
		return "Cursor";
	}

	public function getDefaultSize() : int{
		return 1;
	}

	public function setSize(int $size){
		throw new \BadMethodCallException("Cursor can only carry one item at a time");
	}

	/**
	 * This override is here for documentation and code completion purposes only.
	 * @return Player
	 */
	public function getHolder(){
		return $this->holder;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\inventory;

use pocketmine\item\Item;
use pocketmine\Player;
use function max;
use function min;
use const PHP_INT_MAX;

class CraftingGrid extends BaseInventory{
	public const SIZE_SMALL = 2;
	public const SIZE_BIG = 3;

	/** @var Player */
	protected $holder;
	/** @var int */
	private $gridWidth;

	/** @var int|null */
	private $startX;
	/** @var int|null */
	private $xLen;
	/** @var int|null */
	private $startY;
	/** @var int|null */
	private $yLen;

	public function __construct(Player $holder, int $gridWidth){
		$this->holder = $holder;
		$this->gridWidth = $gridWidth;
		parent::__construct();
	}

	public function getGridWidth() : int{
		return $this->gridWidth;
	}

	public function getDefaultSize() : int{
		return $this->getGridWidth() ** 2;
	}

	public function setSize(int $size){
		throw new \BadMethodCallException("Cannot change the size of a crafting grid");
	}

	public function getName() : string{
		return "Crafting";
	}

	public function setItem(int $index, Item $item, bool $send = true) : bool{
		if(parent::setItem($index, $item, $send)){
			$this->seekRecipeBounds();

			return true;
		}

		return false;
	}

	public function sendSlot(int $index, $target) : void{
		//we can't send a slot of a client-sided inventory window
	}

	public function sendContents($target) : void{
		//no way to do this
	}

	/**
	 * @return Player
	 */
	public function getHolder(){
		return $this->holder;
	}

	private function seekRecipeBounds() : void{
		$minX = PHP_INT_MAX;
		$maxX = 0;

		$minY = PHP_INT_MAX;
		$maxY = 0;

		$empty = true;

		for($y = 0; $y < $this->gridWidth; ++$y){
			for($x = 0; $x < $this->gridWidth; ++$x){
				if(!$this->isSlotEmpty($y * $this->gridWidth + $x)){
					$minX = min($minX, $x);
					$maxX = max($maxX, $x);

					$minY = min($minY, $y);
					$maxY = max($maxY, $y);

					$empty = false;
				}
			}
		}

		if(!$empty){
			$this->startX = $minX;
			$this->xLen = $maxX - $minX + 1;
			$this->startY = $minY;
			$this->yLen = $maxY - $minY + 1;
		}else{
			$this->startX = $this->xLen = $this->startY = $this->yLen = null;
		}
	}

	/**
	 * Returns the item at offset x,y, offset by where the starts of the recipe rectangle are.
	 */
	public function getIngredient(int $x, int $y) : Item{
		if($this->startX !== null and $this->startY !== null){
			return $this->getItem(($y + $this->startY) * $this->gridWidth + ($x + $this->startX));
		}

		throw new \InvalidStateException("No ingredients found in grid");
	}

	/**
	 * Returns the width of the recipe we're trying to craft, based on items currently in the grid.
	 */
	public function getRecipeWidth() : int{
		return $this->xLen ?? 0;
	}

	/**
	 * Returns the height of the recipe we're trying to craft, based on items currently in the grid.
	 */
	public function getRecipeHeight() : int{
		return $this->yLen ?? 0;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\entity;

use pocketmine\entity\Creature;
use pocketmine\entity\Entity;
use pocketmine\entity\Human;
use pocketmine\entity\object\ItemEntity;
use pocketmine\entity\projectile\Projectile;
use pocketmine\entity\Vehicle;
use pocketmine\level\Position;

/**
 * Called when a entity is spawned
 */
class EntitySpawnEvent extends EntityEvent{
	/** @var int */
	private $entityType;

	public function __construct(Entity $entity){
		$this->entity = $entity;
		$this->entityType = $entity::NETWORK_ID;
	}

	public function getPosition() : Position{
		return $this->entity->getPosition();
	}

	public function getType() : int{
		return $this->entityType;
	}

	public function isCreature() : bool{
		return $this->entity instanceof Creature;
	}

	public function isHuman() : bool{
		return $this->entity instanceof Human;
	}

	public function isProjectile() : bool{
		return $this->entity instanceof Projectile;
	}

	public function isVehicle() : bool{
		return $this->entity instanceof Vehicle;
	}

	public function isItem() : bool{
		return $this->entity instanceof ItemEntity;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\event\Cancellable;
use pocketmine\Player;

/**
 * Called after the player has successfully authenticated, before it spawns. The player is on the loading screen when
 * this is called.
 * Cancelling this event will cause the player to be disconnected with the kick message set.
 */
class PlayerLoginEvent extends PlayerEvent implements Cancellable{
	/** @var string */
	protected $kickMessage;

	public function __construct(Player $player, string $kickMessage){
		$this->player = $player;
		$this->kickMessage = $kickMessage;
	}

	public function setKickMessage(string $kickMessage) : void{
		$this->kickMessage = $kickMessage;
	}

	public function getKickMessage() : string{
		return $this->kickMessage;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

use pocketmine\block\BlockIds;
use pocketmine\nbt\NBT;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use function file_get_contents;
use function getmypid;
use function json_decode;
use function mt_rand;
use function mt_srand;
use function shuffle;

/**
 * @internal
 */
final class RuntimeBlockMapping{

	/** @var int[] */
	private static $legacyToRuntimeMap = [];
	/** @var int[] */
	private static $runtimeToLegacyMap = [];
	/** @var CompoundTag[]|null */
	private static $bedrockKnownStates = null;

	private function __construct(){
		//NOOP
	}

	public static function init() : void{
		$tag = (new NetworkLittleEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/required_block_states.nbt"));
		if(!($tag instanceof ListTag) or $tag->getTagType() !== NBT::TAG_Compound){ //this is a little redundant currently, but good for auto complete and makes phpstan happy
			throw new \RuntimeException("Invalid blockstates table, expected TAG_List<TAG_Compound> root");
		}

		/** @var CompoundTag[] $list */
		$list = $tag->getValue();
		self::$bedrockKnownStates = self::randomizeTable($list);

		self::setupLegacyMappings();
	}

	private static function setupLegacyMappings() : void{
		$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true);
		$legacyStateMap = (new NetworkLittleEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.nbt"));
		if(!($legacyStateMap instanceof ListTag) or $legacyStateMap->getTagType() !== NBT::TAG_Compound){
			throw new \RuntimeException("Invalid legacy states mapping table, expected TAG_List<TAG_Compound> root");
		}

		/**
		 * @var int[][] $idToStatesMap string id -> int[] list of candidate state indices
		 */
		$idToStatesMap = [];
		foreach(self::$bedrockKnownStates as $k => $state){
			$idToStatesMap[$state->getCompoundTag("block")->getString("name")][] = $k;
		}
		/** @var CompoundTag $pair */
		foreach($legacyStateMap as $pair){
			$oldState = $pair->getCompoundTag("old");
			$id = $legacyIdMap[$oldState->getString("name")];
			$data = $oldState->getShort("val");
			if($data > 15){
				//we can't handle metadata with more than 4 bits
				continue;
			}
			$mappedState = $pair->getCompoundTag("new");

			//TODO HACK: idiotic NBT compare behaviour on 3.x compares keys which are stored by values
			$mappedState->setName("block");
			$mappedName = $mappedState->getString("name");
			if(!isset($idToStatesMap[$mappedName])){
				throw new \RuntimeException("Mapped new state does not appear in network table");
			}
			foreach($idToStatesMap[$mappedName] as $k){
				$networkState = self::$bedrockKnownStates[$k];
				if($mappedState->equals($networkState->getCompoundTag("block"))){
					self::registerMapping($k, $id, $data);
					continue 2;
				}
			}
			throw new \RuntimeException("Mapped new state does not appear in network table");
		}
	}

	private static function lazyInit() : void{
		if(self::$bedrockKnownStates === null){
			self::init();
		}
	}

	/**
	 * Randomizes the order of the runtimeID table to prevent plugins relying on them.
	 * Plugins shouldn't use this stuff anyway, but plugin devs have an irritating habit of ignoring what they
	 * aren't supposed to do, so we have to deliberately break it to make them stop.
	 *
	 * @param CompoundTag[] $table
	 *
	 * @return CompoundTag[]
	 */
	private static function randomizeTable(array $table) : array{
		$postSeed = mt_rand(); //save a seed to set afterwards, to avoid poor quality randoms
		mt_srand(getmypid()); //Use a seed which is the same on all threads. This isn't a secure seed, but we don't care.
		shuffle($table);
		mt_srand($postSeed); //restore a good quality seed that isn't dependent on PID
		return $table;
	}

	public static function toStaticRuntimeId(int $id, int $meta = 0) : int{
		self::lazyInit();
		/*
		 * try id+meta first
		 * if not found, try id+0 (strip meta)
		 * if still not found, return update! block
		 */
		return self::$legacyToRuntimeMap[($id << 4) | $meta] ?? self::$legacyToRuntimeMap[$id << 4] ?? self::$legacyToRuntimeMap[BlockIds::INFO_UPDATE << 4];
	}

	/**
	 * @return int[] [id, meta]
	 */
	public static function fromStaticRuntimeId(int $runtimeId) : array{
		self::lazyInit();
		$v = self::$runtimeToLegacyMap[$runtimeId];
		return [$v >> 4, $v & 0xf];
	}

	private static function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{
		self::$legacyToRuntimeMap[($legacyId << 4) | $legacyMeta] = $staticRuntimeId;
		self::$runtimeToLegacyMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta;
	}

	/**
	 * @return CompoundTag[]
	 */
	public static function getBedrockKnownStates() : array{
		self::lazyInit();
		return self::$bedrockKnownStates;
	}
}
	 
0
blocknameminecraft:jungle_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:grindstone
states
attachmentstanding	direction version id 
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:carpet
statescolorlime version id  
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit  version id 
blocknameminecraft:melon_stem
statesgrowth version idi  
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version idG  
blockname minecraft:blue_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3polished_dioritetop_slot_bit  version id 
blocknameminecraft:wheat
statesgrowth  version id;  
blocknameminecraft:stone_slab4
statesstone_slab_type_4cut_red_sandstonetop_slot_bit version id 
blocknameminecraft:birch_door
states	direction door_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:log2
statesnew_log_typedark_oakpillar_axisz version id  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:red_sandstone
statessand_stone_typedefault version id  
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay  version id]  
blocknameminecraft:birch_trapdoor
states	direction open_bitupside_down_bit version id 
blocknameminecraft:quartz_block
stateschisel_typedefaultpillar_axisz version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:andesite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:acacia_wall_sign
statesfacing_direction version id 
blocknameminecraft:red_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:concretePowder
statescolormagenta version id  
blocknameminecraft:trapped_chest
statesfacing_direction version id  
blocknameminecraft:redstone_block
states version id  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:melon_stem
statesgrowth version idi  
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:double_stone_slab
statesstone_slab_typesmooth_stonetop_slot_bit  version id+  
blocknameminecraft:wall_banner
statesfacing_direction version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:bell
states
attachmentmultiple	direction 
toggle_bit  version id 
blocknameminecraft:hopper
statesfacing_direction

toggle_bit  version id  
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version idG  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:grindstone
states
attachmentside	direction version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version idG  
blocknameminecraft:hopper
statesfacing_direction
toggle_bit version id  
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay  version id]  
blocknameminecraft:frosted_ice
statesage version id  
blockname minecraft:pink_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:sweet_berry_bush
statesgrowth version id 
blocknameminecraft:monster_egg
statesmonster_egg_stone_typestone_brick version ida  
blocknameminecraft:beehive
statesfacing_direction honey_level version id 
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blockname
minecraft:bed
states	direction head_piece_bit occupied_bit  version id  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:red_sandstone_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:anvil
statesdamage	undamaged	direction version id  
blocknameminecraft:melon_stem
statesgrowth version idi  
blocknameminecraft:trapdoor
states	directionopen_bitupside_down_bit  version id`  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level  version id 
blocknameminecraft:snow_layer
statescovered_bitheight version idN  
blocknameminecraft:jungle_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction
 version id 
blocknameminecraft:coral_fan
statescoral_coloryellowcoral_fan_direction version id 
blocknameminecraft:beehive
statesfacing_direction
honey_level  version id 
blocknameminecraft:kelp
stateskelp_age( version id 
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:diamond_ore
states version id8  
blocknameminecraft:scaffolding
states	stabilitystability_check  version id 
blocknameminecraft:composter
statescomposter_fill_level version id 
blockname"minecraft:yellow_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:bamboo
statesage_bit bamboo_leaf_sizelarge_leavesbamboo_stalk_thicknessthick version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2purpurtop_slot_bit  version id  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit version id 
blocknameminecraft:colored_torch_bp
states	color_bittorch_facing_directioneast version id  
blocknameminecraft:element_66
states version idL 
blocknameminecraft:andesite_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:stained_glass_pane
statescolorwhite version id  
blocknameminecraft:wooden_slab
statestop_slot_bit	wood_typeoak version id  
blocknameminecraft:monster_egg
statesmonster_egg_stone_typechiseled_stone_brick version ida  
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:jungle_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:unpowered_repeater
states	direction repeater_delay version id]  
blocknameminecraft:ladder
statesfacing_direction  version idA  
blocknameminecraft:underwater_torch
statestorch_facing_directionnorth version id  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:campfire
states	direction extinguished version id 
blockname!minecraft:hard_stained_glass_pane
statescolormagenta version id  
blocknameminecraft:double_plant
statesdouble_plant_typesyringaupper_block_bit version id  
blockname"minecraft:yellow_glazed_terracotta
statesfacing_direction version id  
blockname
minecraft:log
statesold_log_typebirchpillar_axisx version id  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3smooth_red_sandstonetop_slot_bit  version id 
blocknameminecraft:stone_slab3
statesstone_slab_type_3polished_granitetop_slot_bit version id 
blockname
minecraft:bed
states	directionhead_piece_bitoccupied_bit version id  
blocknameminecraft:jigsaw
statesfacing_direction version id 
blocknameminecraft:furnace
statesfacing_direction
 version id=  
blocknameminecraft:fence_gate
states	direction in_wall_bitopen_bit version idk  
blockname!minecraft:polished_diorite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction
 version id 
blocknameminecraft:lit_furnace
statesfacing_direction  version id>  
blocknameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typebirch version id  
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:lava
statesliquid_depth version id  
blockname!minecraft:smooth_sandstone_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typedark_oak version id  
blocknameminecraft:purpur_block
stateschisel_typelinespillar_axisx version id  
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:coral_block
statescoral_colorpurpledead_bit version id 
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blockname!minecraft:polished_granite_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:iron_door
states	direction door_hinge_bit open_bit upper_block_bit version idG  
blocknameminecraft:kelp
stateskelp_age version id 
blockname!minecraft:polished_granite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:spruce_button
statesbutton_pressed_bit facing_direction  version id 
blocknameminecraft:iron_door
states	direction door_hinge_bit open_bitupper_block_bit version idG  
blocknameminecraft:spruce_trapdoor
states	direction open_bitupside_down_bit version id 
blocknameminecraft:element_12
states version id 
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:structure_void
statesstructure_void_typeair version id  
blocknameminecraft:wood
statespillar_axisxstripped_bit 	wood_typejungle version id 
blocknameminecraft:reeds
statesage version idS  
blockname#minecraft:magenta_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:ender_chest
statesfacing_direction
 version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:coral_fan
statescoral_colorpurplecoral_fan_direction  version id 
blocknameminecraft:quartz_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:element_58
states version idD 
blockname!minecraft:repeating_command_block
statesconditional_bitfacing_direction
 version id  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version idG  
blocknameminecraft:element_21
states version id 
blocknameminecraft:wood
statespillar_axisystripped_bit 	wood_typespruce version id 
blocknameminecraft:golden_rail
states
rail_data_bitrail_direction version id  
blocknameminecraft:ladder
statesfacing_direction version idA  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:detector_rail
states
rail_data_bitrail_direction version id  
blocknameminecraft:sea_pickle
states
cluster_countdead_bit version id 
blockname!minecraft:repeating_command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:farmland
statesmoisturized_amount version id<  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit  version id 
blocknameminecraft:chain_command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:bell
states
attachmentmultiple	direction
toggle_bit  version id 
blocknameminecraft:standing_sign
statesground_sign_direction  version id?  
blocknameminecraft:wood
statespillar_axisystripped_bit	wood_typeacacia version id 
blockname minecraft:gray_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:concrete
statescolorblack version id  
blocknameminecraft:light_block
statesblock_light_level  version id 
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:mob_spawner
states version id4  
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit  version id 
blocknameminecraft:daylight_detector
statesredstone_signal  version id  
blocknameminecraft:bamboo_sapling
statesage_bitsapling_typespruce version id 
blockname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:darkoak_wall_sign
statesfacing_direction
 version id 
blocknameminecraft:colored_torch_bp
states	color_bittorch_facing_directionwest version id  
blocknameminecraft:element_67
states version idM 
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:chain_command_block
statesconditional_bitfacing_direction
 version id  
blocknameminecraft:coral_fan_dead
statescoral_colorpurplecoral_fan_direction version id 
blocknameminecraft:beehive
statesfacing_directionhoney_level  version id 
blockname!minecraft:repeating_command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:cobblestone_wall
stateswall_block_typediorite version id  
blocknameminecraft:birch_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:portal
statesportal_axisunknown version idZ  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:potatoes
statesgrowth
 version id  
blocknameminecraft:birch_door
states	direction door_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:dragon_egg
states version idz  
blockname"minecraft:orange_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:stripped_oak_log
statespillar_axisx version id	 
blocknameminecraft:stripped_jungle_log
statespillar_axisz version id 
blockname!minecraft:brown_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:element_49
states version id; 
blocknameminecraft:end_portal_frame
states	direction end_portal_eye_bit  version idx  
blocknameminecraft:element_102
states version idp 
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:stone_button
statesbutton_pressed_bitfacing_direction version idM  
blocknameminecraft:dark_oak_door
states	direction door_hinge_bit open_bit upper_block_bit  version id  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal  version id 
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:spruce_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:sandstone
statessand_stone_typesmooth version id  
blocknameminecraft:jungle_button
statesbutton_pressed_bit facing_direction  version id 
blocknameminecraft:hay_block
states
deprecated pillar_axisx version id  
blocknameminecraft:end_portal_frame
states	directionend_portal_eye_bit  version idx  
blocknameminecraft:normal_stone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:fence
states	wood_typeoak version idU  
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:beehive
statesfacing_directionhoney_level  version id 
blocknameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit version id  
blocknameminecraft:purpur_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:wool
statescolorwhite version id#  
blocknameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:trapdoor
states	directionopen_bit upside_down_bit  version id`  
blocknameminecraft:dark_oak_door
states	direction door_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:birch_fence_gate
states	direction in_wall_bit open_bit version id  
blocknameminecraft:skull
statesfacing_directionno_drop_bit version id  
blocknameminecraft:grindstone
states
attachmentstanding	direction version id 
blocknameminecraft:lever
stateslever_directionnorthopen_bit version idE  
blocknameminecraft:jungle_wall_sign
statesfacing_direction version id 
blocknameminecraft:jungle_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:carved_pumpkin
states	direction  version id 
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:hay_block
states
deprecatedpillar_axisx version id  
blocknameminecraft:cobblestone
states version id  
blocknameminecraft:stone_button
statesbutton_pressed_bit facing_direction version idM  
blocknameminecraft:bell
states
attachmentstanding	direction
toggle_bit  version id 
blocknameminecraft:hopper
statesfacing_direction 
toggle_bit  version id  
blocknameminecraft:iron_trapdoor
states	direction open_bitupside_down_bit version id  
blocknameminecraft:golden_rail
states
rail_data_bit rail_direction version id  
blocknameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:element_15
states version id 
blocknameminecraft:structure_block
statesstructure_block_typeload version id  
blocknameminecraft:coral
statescoral_colorbluedead_bit version id 
blocknameminecraft:trapped_chest
statesfacing_direction
 version id  
blocknameminecraft:stonebrick
statesstone_brick_typecracked version idb  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit version id  
blocknameminecraft:coral_fan_hang3
statescoral_direction coral_hang_type_bit dead_bit  version id 
blocknameminecraft:granite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:wooden_slab
statestop_slot_bit 	wood_typebirch version id  
blocknameminecraft:dropper
statesfacing_direction
triggered_bit version id}  
blocknameminecraft:end_brick_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:end_brick_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:stone_slab3
statesstone_slab_type_3polished_granitetop_slot_bit  version id 
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:composter
statescomposter_fill_level  version id 
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_roughtop_slot_bit  version id  
blocknameminecraft:brick_stairs
statesupside_down_bit weirdo_direction version idl  
blockname!minecraft:polished_diorite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:acacia_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:colored_torch_rg
states	color_bittorch_facing_directionwest version id  
blocknameminecraft:stone_slab
statesstone_slab_typequartztop_slot_bit  version id,  
blocknameminecraft:powered_comparator
states	direction output_lit_bitoutput_subtract_bit  version id  
blocknameminecraft:element_99
states version idm 
blocknameminecraft:sea_pickle
states
cluster_countdead_bit version id 
blockname"minecraft:mossy_cobblestone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit version id 
blocknameminecraft:dropper
statesfacing_direction
triggered_bit version id}  
blocknameminecraft:hard_stained_glass
statescolorblue version id  
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:fence_gate
states	directionin_wall_bit open_bit version idk  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id@  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:red_sandstone_stairs
statesupside_down_bit weirdo_direction version id  
blockname
minecraft:log
statesold_log_typeoakpillar_axisx version id  
blocknameminecraft:colored_torch_rg
states	color_bit torch_facing_directionnorth version id  
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2red_nether_bricktop_slot_bit version id  
blocknameminecraft:birch_trapdoor
states	direction open_bit upside_down_bit version id 
blocknameminecraft:lever
stateslever_directionup_north_southopen_bit version idE  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:shulker_box
statescolorwhite version id  
blocknameminecraft:vine
statesvine_direction_bits
 version idj  
blocknameminecraft:stone_slab2
statesstone_slab_type_2prismarine_darktop_slot_bit version id  
blocknameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:chemistry_table
stateschemistry_table_typecompound_creator	direction  version id  
blocknameminecraft:hard_stained_glass
statescolorsilver version id  
blocknameminecraft:wool
statescolor
light_blue version id#  
blockname!minecraft:repeating_command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:packed_ice
states version id  
blocknameminecraft:fence_gate
states	direction in_wall_bit open_bit version idk  
blocknameminecraft:blast_furnace
statesfacing_direction version id 
blocknameminecraft:scaffolding
states	stabilitystability_check version id 
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit  version id  
blocknameminecraft:cauldron
statescauldron_liquidlava
fill_level version idv  
blockname!minecraft:white_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:hopper
statesfacing_direction 
toggle_bit version id  
blockname!minecraft:smooth_sandstone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:element_86
states version id` 
blocknameminecraft:brick_stairs
statesupside_down_bit weirdo_direction version idl  
blocknameminecraft:brewing_stand
statesbrewing_stand_slot_a_bitbrewing_stand_slot_b_bitbrewing_stand_slot_c_bit version idu  
blocknameminecraft:golden_rail
states
rail_data_bit rail_direction
 version id  
blocknameminecraft:red_flower
statesflower_typetulip_orange version id&  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:brick_stairs
statesupside_down_bitweirdo_direction version idl  
blocknameminecraft:end_bricks
states version id  
blocknameminecraft:sandstone_stairs
statesupside_down_bit weirdo_direction  version id  
blocknameminecraft:jungle_wall_sign
statesfacing_direction version id 
blocknameminecraft:grindstone
states
attachmentside	direction  version id 
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:potatoes
statesgrowth version id  
blocknameminecraft:spruce_fence_gate
states	direction in_wall_bitopen_bit version id  
blocknameminecraft:composter
statescomposter_fill_level version id 
blocknameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction
 version id 
blocknameminecraft:purpur_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:bamboo
statesage_bitbamboo_leaf_size	no_leavesbamboo_stalk_thicknessthin version id 
blocknameminecraft:stone_stairs
statesupside_down_bitweirdo_direction version idC  
blocknameminecraft:cake
statesbite_counter
 version id\  
blocknameminecraft:granite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:jungle_door
states	direction door_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:trapped_chest
statesfacing_direction  version id  
blocknameminecraft:chemistry_table
stateschemistry_table_typematerial_reducer	direction version id  
blockname
minecraft:log
statesold_log_typeoakpillar_axisy version id  
blocknameminecraft:shulker_box
statescolormagenta version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:spruce_button
statesbutton_pressed_bit facing_direction
 version id 
blocknameminecraft:dark_oak_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:stained_glass_pane
statescolorblack version id  
blocknameminecraft:acacia_standing_sign
statesground_sign_direction
 version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blockname"minecraft:prismarine_bricks_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:wood
statespillar_axisxstripped_bit 	wood_typebirch version id 
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits  version idc  
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:red_sandstone_stairs
statesupside_down_bit weirdo_direction  version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:fletching_table
states version id 
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2prismarine_roughtop_slot_bit version id  
blockname!minecraft:polished_diorite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit  version id 
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay version id]  
blocknameminecraft:red_flower
statesflower_typetulip_white version id&  
blocknameminecraft:grass
states version id  
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:hopper
statesfacing_direction
toggle_bit version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id@  
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit version id  
blockname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:carpet
statescolorcyan version id  
blocknameminecraft:element_47
states version id9 
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:bee_nest
statesfacing_direction
honey_level version id 
blocknameminecraft:wither_rose
states version id 
blocknameminecraft:iron_trapdoor
states	direction open_bit upside_down_bit version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version idG  
blocknameminecraft:redstone_torch
statestorch_facing_directionsouth version idL  
blocknameminecraft:tripWire
statesattached_bitdisarmed_bit powered_bit
suspended_bit  version id  
blockname"minecraft:mossy_stone_brick_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:spruce_pressure_plate
statesredstone_signal
 version id 
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit version id 
blocknameminecraft:iron_door
states	direction door_hinge_bitopen_bit upper_block_bit version idG  
blocknameminecraft:sweet_berry_bush
statesgrowth
 version id 
blocknameminecraft:wheat
statesgrowth version id;  
blocknameminecraft:barrel
statesfacing_directionopen_bit  version id 
blocknameminecraft:cauldron
statescauldron_liquidlava
fill_level version idv  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:redstone_torch
statestorch_facing_directionunknown version idL  
blocknameminecraft:birch_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:sandstone_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:turtle_egg
states
cracked_statemax_crackedturtle_egg_countfour_egg version id 
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:chorus_flower
statesage version id  
blocknameminecraft:stone_slab4
statesstone_slab_type_4
cut_sandstonetop_slot_bit  version id 
blocknameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:fence_gate
states	directionin_wall_bitopen_bit  version idk  
blocknameminecraft:barrier
states version id 
blockname minecraft:dark_prismarine_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit  version id  
blocknameminecraft:bee_nest
statesfacing_direction honey_level version id 
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:snow_layer
statescovered_bitheight
 version idN  
blocknameminecraft:turtle_egg
states
cracked_statecrackedturtle_egg_countfour_egg version id 
blocknameminecraft:coral_fan_dead
statescoral_colorredcoral_fan_direction  version id 
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:wall_banner
statesfacing_direction version id  
blocknameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit  version id  
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:beehive
statesfacing_direction honey_level  version id 
blocknameminecraft:coral
statescoral_colorpurpledead_bit version id 
blockname minecraft:gray_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:bell
states
attachmentstanding	direction
toggle_bit  version id 
blocknameminecraft:prismarine_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:double_plant
statesdouble_plant_typegrassupper_block_bit  version id  
blockname minecraft:dark_prismarine_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:bee_nest
statesfacing_direction
honey_level
 version id 
blocknameminecraft:golden_rail
states
rail_data_bitrail_direction
 version id  
blocknameminecraft:bell
states
attachmentside	direction
toggle_bit version id 
blocknameminecraft:campfire
states	directionextinguished  version id 
blocknameminecraft:bell
states
attachmentstanding	direction
toggle_bit version id 
blocknameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit  version id  
blocknameminecraft:dispenser
statesfacing_direction 
triggered_bit  version id  
blocknameminecraft:pumpkin_stem
statesgrowth version idh  
blocknameminecraft:cocoa
statesage	direction version id  
blocknameminecraft:lever
stateslever_directionwestopen_bit version idE  
blocknameminecraft:lit_furnace
statesfacing_direction version id>  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay  version id]  
blocknameminecraft:camera
states version id  
blocknameminecraft:chest
statesfacing_direction version id6  
blockname minecraft:dark_prismarine_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id@  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:wall_sign
statesfacing_direction version idD  
blocknameminecraft:element_78
states version idX 
blocknameminecraft:sandstone_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:stained_glass_pane
statescolorpurple version id  
blocknameminecraft:sea_pickle
states
cluster_countdead_bit  version id 
blocknameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit version id  
blocknameminecraft:sponge
statessponge_typewet version id  
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3dioritetop_slot_bit version id 
blocknameminecraft:stone_slab
statesstone_slab_type	sandstonetop_slot_bit  version id,  
blocknameminecraft:element_64
states version idJ 
blocknameminecraft:dark_oak_trapdoor
states	direction open_bitupside_down_bit  version id 
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3andesitetop_slot_bit  version id 
blocknameminecraft:seagrass
statessea_grass_type
double_bot version id 
blocknameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit  version id 
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blockname!minecraft:polished_granite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:loom
states	direction version id 
blocknameminecraft:oak_stairs
statesupside_down_bitweirdo_direction version id5  
blocknameminecraft:tallgrass
statestall_grass_typedefault version id  
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal  version id  
blocknameminecraft:lit_furnace
statesfacing_direction
 version id>  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3polished_andesitetop_slot_bit version id 
blocknameminecraft:nether_wart
statesage version ids  
blocknameminecraft:chest
statesfacing_direction version id6  
blocknameminecraft:element_36
states version id. 
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:pumpkin
states	direction version idV  
blocknameminecraft:spruce_standing_sign
statesground_sign_direction
 version id 
blocknameminecraft:cauldron
statescauldron_liquidlava
fill_level version idv  
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:end_stone
states version idy  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blockname minecraft:pink_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:light_block
statesblock_light_level version id 
blockname"minecraft:silver_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit version id 
blockname!minecraft:brown_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:grindstone
states
attachmenthanging	direction version id 
blocknameminecraft:diamond_block
states version id9  
blocknameminecraft:dirt
states	dirt_typenormal version id  
blocknameminecraft:birch_fence_gate
states	direction in_wall_bit open_bit  version id  
blocknameminecraft:carpet
statescolorblack version id  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level  version id 
blocknameminecraft:oak_stairs
statesupside_down_bitweirdo_direction version id5  
blocknameminecraft:diorite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:wood
statespillar_axisystripped_bit 	wood_typejungle version id 
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:element_22
states version id  
blocknameminecraft:purpur_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:lit_blast_furnace
statesfacing_direction version id 
blocknameminecraft:loom
states	direction version id 
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:spruce_fence_gate
states	direction in_wall_bit open_bit version id  
blocknameminecraft:portal
statesportal_axisx version idZ  
blocknameminecraft:turtle_egg
states
cracked_statemax_crackedturtle_egg_countone_egg version id 
blocknameminecraft:dispenser
statesfacing_direction

triggered_bit version id  
blocknameminecraft:bone_block
states
deprecatedpillar_axisz version id  
blocknameminecraft:composter
statescomposter_fill_level
 version id 
blocknameminecraft:frame
statesfacing_direction item_frame_map_bit  version id  
blocknameminecraft:campfire
states	directionextinguished version id 
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4
smooth_quartztop_slot_bit version id 
blocknameminecraft:tripWire
statesattached_bit disarmed_bitpowered_bit
suspended_bit version id  
blocknameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:observer
statesfacing_directionpowered_bit  version id  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:kelp
stateskelp_age  version id 
blocknameminecraft:beacon
states version id  
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction  version id 
blocknameminecraft:blast_furnace
statesfacing_direction
 version id 
blocknameminecraft:bee_nest
statesfacing_direction honey_level version id 
blockname"minecraft:prismarine_bricks_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version idG  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:birch_wall_sign
statesfacing_direction  version id 
blocknameminecraft:chorus_flower
statesage version id  
blocknameminecraft:red_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:acacia_door
states	direction door_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:light_block
statesblock_light_level version id 
blockname minecraft:gray_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:seagrass
statessea_grass_type
double_top version id 
blocknameminecraft:trapdoor
states	directionopen_bit upside_down_bit version id`  
blockname"minecraft:stickyPistonArmCollision
statesfacing_direction version id 
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3granitetop_slot_bit version id 
blocknameminecraft:double_plant
statesdouble_plant_typepaeoniaupper_block_bit version id  
blocknameminecraft:dark_oak_door
states	direction door_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:tallgrass
statestall_grass_typefern version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit version idG  
blocknameminecraft:scaffolding
states	stability
stability_check  version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blockname!minecraft:repeating_command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:concretePowder
statescolorbrown version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:wool
statescolorbrown version id#  
blocknameminecraft:cobblestone_wall
stateswall_block_typeandesite version id  
blocknameminecraft:wall_banner
statesfacing_direction  version id  
blocknameminecraft:sticky_piston
statesfacing_direction
 version id  
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit  version id 
blocknameminecraft:spruce_fence_gate
states	direction in_wall_bit open_bit  version id  
blocknameminecraft:stained_hardened_clay
statescolorgray version id  
blocknameminecraft:red_sandstone
statessand_stone_typeheiroglyphs version id  
blocknameminecraft:wheat
statesgrowth
 version id;  
blocknameminecraft:spruce_wall_sign
statesfacing_direction version id 
blocknameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version id 
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay version id]  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:diorite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:bell
states
attachmentmultiple	direction
toggle_bit  version id 
blocknameminecraft:stonebrick
statesstone_brick_typechiseled version idb  
blocknameminecraft:stained_glass
statescolorwhite version id  
blocknameminecraft:pumpkin
states	direction  version idV  
blocknameminecraft:normal_stone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:leaves
states
old_leaf_typesprucepersistent_bit
update_bit version id  
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_roughtop_slot_bit version id  
blocknameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typeoak version id  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:farmland
statesmoisturized_amount version id<  
blocknameminecraft:wood
statespillar_axisystripped_bit 	wood_typebirch version id 
blocknameminecraft:beehive
statesfacing_directionhoney_level
 version id 
blocknameminecraft:wood
statespillar_axisxstripped_bit	wood_typebirch version id 
blockname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:bamboo_sapling
statesage_bitsapling_typebirch version id 
blocknameminecraft:element_75
states version idU 
blocknameminecraft:hay_block
states
deprecatedpillar_axisy version id  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:beehive
statesfacing_direction
honey_level version id 
blocknameminecraft:bamboo_sapling
statesage_bit sapling_typejungle version id 
blocknameminecraft:granite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id@  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:quartz_block
stateschisel_typelinespillar_axisy version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id@  
blocknameminecraft:birch_standing_sign
statesground_sign_direction
 version id 
blocknameminecraft:bamboo
statesage_bitbamboo_leaf_sizelarge_leavesbamboo_stalk_thicknessthin version id 
blocknameminecraft:frame
statesfacing_direction
item_frame_map_bit  version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:wall_sign
statesfacing_direction
 version idD  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:detector_rail
states
rail_data_bit rail_direction
 version id  
blocknameminecraft:frame
statesfacing_directionitem_frame_map_bit version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:stone_slab4
statesstone_slab_type_4
smooth_quartztop_slot_bit  version id 
blocknameminecraft:hard_stained_glass
statescolorgreen version id  
blocknameminecraft:torch
statestorch_facing_directionwest version id2  
blocknameminecraft:colored_torch_bp
states	color_bit torch_facing_directioneast version id  
blocknameminecraft:birch_wall_sign
statesfacing_direction
 version id 
blocknameminecraft:stained_hardened_clay
statescolor
light_blue version id  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blockname
minecraft:ice
states version idO  
blocknameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit version id  
blocknameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:kelp
stateskelp_age
 version id 
blocknameminecraft:wooden_slab
statestop_slot_bit 	wood_typeoak version id  
blocknameminecraft:wood
statespillar_axisystripped_bit 	wood_typedark_oak version id 
blocknameminecraft:carpet
statescolorbrown version id  
blocknameminecraft:colored_torch_bp
states	color_bittorch_facing_directiontop version id  
blocknameminecraft:cocoa
statesage 	direction  version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:beetroot
statesgrowth version id  
blocknameminecraft:end_portal_frame
states	directionend_portal_eye_bit  version idx  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:bamboo_sapling
statesage_bitsapling_typedark_oak version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:spruce_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:wood
statespillar_axisystripped_bit	wood_typespruce version id 
blocknameminecraft:wool
statescoloryellow version id#  
blocknameminecraft:flower_pot
states
update_bit  version id  
blocknameminecraft:acacia_pressure_plate
statesredstone_signal
 version id 
blocknameminecraft:brick_stairs
statesupside_down_bit weirdo_direction  version idl  
blocknameminecraft:darkoak_wall_sign
statesfacing_direction  version id 
blocknameminecraft:stone_pressure_plate
statesredstone_signal
 version idF  
blocknameminecraft:skull
statesfacing_directionno_drop_bit  version id  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:wooden_door
states	direction door_hinge_bit open_bit upper_block_bit version id@  
blocknameminecraft:birch_wall_sign
statesfacing_direction version id 
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit version id  
blockname#minecraft:magenta_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit version id 
blockname"minecraft:mossy_stone_brick_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:element_100
states version idn 
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2mossy_cobblestonetop_slot_bit  version id  
blocknameminecraft:red_flower
statesflower_type	tulip_red version id&  
blocknameminecraft:hopper
statesfacing_direction
toggle_bit version id  
blockname!minecraft:repeating_command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:jungle_door
states	direction door_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:purpur_block
stateschisel_typelinespillar_axisz version id  
blocknameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:dark_oak_door
states	direction door_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:anvil
statesdamage	undamaged	direction  version id  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:end_portal_frame
states	directionend_portal_eye_bit version idx  
blockname#minecraft:magenta_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:dispenser
statesfacing_direction
triggered_bit  version id  
blocknameminecraft:oak_stairs
statesupside_down_bitweirdo_direction version id5  
blocknameminecraft:tallgrass
statestall_grass_typetall version id  
blocknameminecraft:stone_button
statesbutton_pressed_bit facing_direction  version idM  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:leaves
states
old_leaf_typejunglepersistent_bit 
update_bit version id  
blocknameminecraft:unlit_redstone_torch
statestorch_facing_directionsouth version idK  
blocknameminecraft:stone_brick_stairs
statesupside_down_bit weirdo_direction version idm  
blockname
minecraft:log
statesold_log_typeoakpillar_axisz version id  
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:coral_block
statescoral_coloryellowdead_bit  version id 
blocknameminecraft:campfire
states	directionextinguished  version id 
blocknameminecraft:grindstone
states
attachmentside	direction version id 
blocknameminecraft:jungle_door
states	direction door_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:colored_torch_rg
states	color_bit torch_facing_directionwest version id  
blocknameminecraft:beetroot
statesgrowth version id  
blocknameminecraft:bamboo_sapling
statesage_bitsapling_typeacacia version id 
blocknameminecraft:prismarine_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:andesite_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction  version id 
blocknameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction  version id 
blocknameminecraft:prismarine
statesprismarine_block_typebricks version id  
blocknameminecraft:bell
states
attachmentstanding	direction
toggle_bit version id 
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:wooden_slab
statestop_slot_bit	wood_typebirch version id  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit
update_bit  version id  
blocknameminecraft:fence_gate
states	direction in_wall_bitopen_bit  version idk  
blocknameminecraft:command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:bamboo
statesage_bitbamboo_leaf_size	no_leavesbamboo_stalk_thicknessthick version id 
blocknameminecraft:element_92
states version idf 
blocknameminecraft:leaves
states
old_leaf_typebirchpersistent_bit
update_bit  version id  
blocknameminecraft:melon_stem
statesgrowth version idi  
blocknameminecraft:torch
statestorch_facing_directioneast version id2  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:coral_block
statescoral_colorreddead_bit  version id 
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id@  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level
 version id 
blocknameminecraft:bee_nest
statesfacing_direction
honey_level version id 
blocknameminecraft:frame
statesfacing_directionitem_frame_map_bit  version id  
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit version id 
blocknameminecraft:concrete
statescoloryellow version id  
blocknameminecraft:command_block
statesconditional_bitfacing_direction  version id  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:unlit_redstone_torch
statestorch_facing_directionunknown version idK  
blocknameminecraft:element_27
states version id% 
blocknameminecraft:activator_rail
states
rail_data_bitrail_direction version id~  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:birch_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:birch_button
statesbutton_pressed_bit facing_direction version id 
blockname!minecraft:white_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:barrel
statesfacing_directionopen_bit version id 
blocknameminecraft:double_plant
statesdouble_plant_typepaeoniaupper_block_bit  version id  
blocknameminecraft:barrel
statesfacing_direction open_bit  version id 
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:beehive
statesfacing_directionhoney_level
 version id 
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:birch_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version idG  
blocknameminecraft:red_flower
statesflower_type
tulip_pink version id&  
blocknameminecraft:brewing_stand
statesbrewing_stand_slot_a_bit brewing_stand_slot_b_bit brewing_stand_slot_c_bit version idu  
blocknameminecraft:wooden_door
states	direction door_hinge_bitopen_bit upper_block_bit version id@  
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blockname!minecraft:hard_stained_glass_pane
statescolororange version id  
blocknameminecraft:blue_ice
states version id
 
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2purpurtop_slot_bit version id  
blocknameminecraft:element_10
states version id 
blocknameminecraft:acacia_fence_gate
states	direction in_wall_bitopen_bit  version id  
blocknameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit version id  
blocknameminecraft:element_88
states version idb 
blocknameminecraft:ender_chest
statesfacing_direction version id  
blocknameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:carved_pumpkin
states	direction version id 
blocknameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version idG  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:red_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:potatoes
statesgrowth version id  
blocknameminecraft:element_72
states version idR 
blocknameminecraft:potatoes
statesgrowth  version id  
blocknameminecraft:chemistry_table
stateschemistry_table_typematerial_reducer	direction version id  
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:piston
statesfacing_direction version id!  
blocknameminecraft:colored_torch_rg
states	color_bittorch_facing_directiontop version id  
blocknameminecraft:redstone_torch
statestorch_facing_directionwest version idL  
blocknameminecraft:leaves
states
old_leaf_typebirchpersistent_bit 
update_bit  version id  
blocknameminecraft:smooth_quartz_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit version idG  
blocknameminecraft:sapling
statesage_bitsapling_typejungle version id  
blocknameminecraft:dark_oak_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit  version id  
blocknameminecraft:stained_hardened_clay
statescolorred version id  
blocknameminecraft:composter
statescomposter_fill_level version id 
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:birch_door
states	direction door_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction version id  
blocknameminecraft:frame
statesfacing_direction
item_frame_map_bit version id  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:bamboo
statesage_bit bamboo_leaf_sizesmall_leavesbamboo_stalk_thicknessthick version id 
blocknameminecraft:element_105
states version ids 
blocknameminecraft:spruce_wall_sign
statesfacing_direction
 version id 
blocknameminecraft:element_65
states version idK 
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version id 
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:tripwire_hook
statesattached_bit	direction powered_bit  version id  
blocknameminecraft:golden_rail
states
rail_data_bitrail_direction version id  
blockname"minecraft:yellow_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit version id 
blockname!minecraft:red_nether_brick_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2smooth_sandstonetop_slot_bit  version id  
blocknameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_countfour_egg version id 
blocknameminecraft:trapdoor
states	directionopen_bit upside_down_bit  version id`  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:cauldron
statescauldron_liquidlava
fill_level  version idv  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id@  
blocknameminecraft:stripped_acacia_log
statespillar_axisz version id 
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:lit_smoker
statesfacing_direction  version id 
blocknameminecraft:hard_stained_glass
statescolorred version id  
blocknameminecraft:rail
statesrail_direction version idB  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:rail
statesrail_direction version idB  
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:normal_stone_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:jungle_wall_sign
statesfacing_direction  version id 
blocknameminecraft:pistonArmCollision
statesfacing_direction version id"  
blocknameminecraft:bell
states
attachmentside	direction
toggle_bit  version id 
blocknameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit version id  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits  version idd  
blocknameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:kelp
stateskelp_age, version id 
blocknameminecraft:element_57
states version idC 
blocknameminecraft:element_108
states version idv 
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:stone_slab
statesstone_slab_typesmooth_stonetop_slot_bit version id,  
blocknameminecraft:wood
statespillar_axisxstripped_bit	wood_typejungle version id 
blocknameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:dispenser
statesfacing_direction 
triggered_bit version id  
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit version id  
blocknameminecraft:quartz_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:prismarine_stairs
statesupside_down_bit weirdo_direction version id 
blockname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blockname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version id 
blocknameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:leaves
states
old_leaf_typeoakpersistent_bit 
update_bit  version id  
blocknameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction version id  
blocknameminecraft:birch_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:leaves
states
old_leaf_typesprucepersistent_bit
update_bit  version id  
blocknameminecraft:jigsaw
statesfacing_direction
 version id 
blocknameminecraft:snow_layer
statescovered_bit height version idN  
blocknameminecraft:planks
states	wood_typedark_oak version id  
blocknameminecraft:spruce_door
states	direction door_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:planks
states	wood_typespruce version id  
blocknameminecraft:element_31
states version id) 
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blockname"minecraft:prismarine_bricks_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:element_81
states version id[ 
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blockname"minecraft:yellow_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:stained_glass_pane
statescolorblue version id  
blocknameminecraft:dark_oak_door
states	direction door_hinge_bitopen_bitupper_block_bit  version id  
blockname!minecraft:polished_granite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:log2
statesnew_log_typedark_oakpillar_axisy version id  
blocknameminecraft:coral_fan_hang2
statescoral_direction coral_hang_type_bitdead_bit version id 
blocknameminecraft:diorite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:jungle_wall_sign
statesfacing_direction version id 
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:smoker
statesfacing_direction version id 
blocknameminecraft:lit_redstone_ore
states version idJ  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:tripWire
statesattached_bit disarmed_bitpowered_bit
suspended_bit  version id  
blocknameminecraft:concrete
statescolorpurple version id  
blocknameminecraft:element_50
states version id< 
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:wooden_button
statesbutton_pressed_bit facing_direction version id  
blocknameminecraft:element_7
states version id 
blocknameminecraft:stained_hardened_clay
statescolorblue version id  
blocknameminecraft:wall_sign
statesfacing_direction version idD  
blocknameminecraft:melon_stem
statesgrowth version idi  
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:mycelium
states version idn  
blocknameminecraft:bee_nest
statesfacing_direction
honey_level version id 
blocknameminecraft:observer
statesfacing_direction
powered_bit  version id  
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit  version id 
blocknameminecraft:cake
statesbite_counter  version id\  
blocknameminecraft:double_stone_slab
statesstone_slab_typebricktop_slot_bit  version id+  
blockname minecraft:cyan_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:loom
states	direction  version id 
blocknameminecraft:piston
statesfacing_direction version id!  
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:snow_layer
statescovered_bit height
 version idN  
blocknameminecraft:anvil
statesdamagevery_damaged	direction version id  
blocknameminecraft:barrel
statesfacing_direction
open_bit  version id 
blocknameminecraft:sweet_berry_bush
statesgrowth version id 
blockname minecraft:blue_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:hay_block
states
deprecatedpillar_axisy version id  
blocknameminecraft:stone_slab
statesstone_slab_typestone_bricktop_slot_bit version id,  
blocknameminecraft:acacia_wall_sign
statesfacing_direction version id 
blocknameminecraft:red_flower
statesflower_typeorchid version id&  
blocknameminecraft:wood
statespillar_axiszstripped_bit 	wood_typeoak version id 
blocknameminecraft:sea_pickle
states
cluster_count dead_bit version id 
blocknameminecraft:grindstone
states
attachmenthanging	direction  version id 
blocknameminecraft:smoker
statesfacing_direction
 version id 
blocknameminecraft:grindstone
states
attachmentmultiple	direction version id 
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit  version id 
blocknameminecraft:cauldron
statescauldron_liquidlava
fill_level version idv  
blocknameminecraft:trapped_chest
statesfacing_direction version id  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal
 version id  
blocknameminecraft:jungle_fence_gate
states	direction in_wall_bit open_bit version id  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:farmland
statesmoisturized_amount
 version id<  
blockname!minecraft:polished_granite_stairs
statesupside_down_bit weirdo_direction version id 
blockname!minecraft:hard_stained_glass_pane
statescolor
light_blue version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:stone_slab4
statesstone_slab_type_4stonetop_slot_bit version id 
blocknameminecraft:jungle_trapdoor
states	direction open_bit upside_down_bit version id 
blockname"minecraft:yellow_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:bell
states
attachmentmultiple	direction 
toggle_bit version id 
blocknameminecraft:birch_door
states	direction door_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:hard_stained_glass
statescoloryellow version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:bamboo_sapling
statesage_bit sapling_typedark_oak version id 
blocknameminecraft:concrete
statescolorpink version id  
blocknameminecraft:sand
states	sand_typenormal version id  
blockname minecraft:blue_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction
 version id 
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:potatoes
statesgrowth version id  
blocknameminecraft:red_nether_brick
states version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:acacia_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:wood
statespillar_axisxstripped_bit 	wood_typeacacia version id 
blocknameminecraft:dark_oak_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:end_gateway
states version id  
blocknameminecraft:iron_block
states version id*  
blocknameminecraft:planks
states	wood_typejungle version id  
blockname"minecraft:silver_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:hard_glass_pane
states version id  
blocknameminecraft:element_91
states version ide 
blocknameminecraft:golden_rail
states
rail_data_bit rail_direction version id  
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:frame
statesfacing_directionitem_frame_map_bit version id  
blocknameminecraft:wooden_door
states	direction door_hinge_bit open_bitupper_block_bit version id@  
blocknameminecraft:frame
statesfacing_directionitem_frame_map_bit  version id  
blocknameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typeacacia version id  
blocknameminecraft:jigsaw
statesfacing_direction version id 
blockname!minecraft:black_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version id 
blocknameminecraft:bell
states
attachmentstanding	direction 
toggle_bit version id 
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:detector_rail
states
rail_data_bit rail_direction version id  
blocknameminecraft:element_33
states version id+ 
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:tripWire
statesattached_bit disarmed_bit powered_bit 
suspended_bit  version id  
blocknameminecraft:anvil
statesdamagevery_damaged	direction version id  
blocknameminecraft:grindstone
states
attachmentstanding	direction  version id 
blocknameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit  version id  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:element_25
states version id# 
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction version id  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:red_sandstone_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:carpet
statescolorgray version id  
blocknameminecraft:skull
statesfacing_directionno_drop_bit version id  
blocknameminecraft:stained_glass
statescolorgray version id  
blocknameminecraft:structure_block
statesstructure_block_typesave version id  
blocknameminecraft:trapdoor
states	directionopen_bitupside_down_bit  version id`  
blocknameminecraft:fence
states	wood_typeacacia version idU  
blocknameminecraft:hopper
statesfacing_direction

toggle_bit version id  
blocknameminecraft:coral_fan_dead
statescoral_colorredcoral_fan_direction version id 
blocknameminecraft:diorite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits
 version idc  
blocknameminecraft:frame
statesfacing_directionitem_frame_map_bit version id  
blocknameminecraft:trapdoor
states	directionopen_bitupside_down_bit version id`  
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit  version id  
blocknameminecraft:redstone_ore
states version idI  
blocknameminecraft:element_90
states version idd 
blockname!minecraft:red_nether_brick_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:stone_brick_stairs
statesupside_down_bitweirdo_direction version idm  
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:wood
statespillar_axiszstripped_bit	wood_typejungle version id 
blocknameminecraft:stained_hardened_clay
statescolorpurple version id  
blocknameminecraft:daylight_detector
statesredstone_signal
 version id  
blocknameminecraft:element_71
states version idQ 
blocknameminecraft:spruce_door
states	direction door_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:rail
statesrail_direction version idB  
blocknameminecraft:barrel
statesfacing_directionopen_bit version id 
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blockname"minecraft:orange_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:stripped_dark_oak_log
statespillar_axisx version id 
blockname"minecraft:purple_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:wall_sign
statesfacing_direction version idD  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit  version id  
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:birch_button
statesbutton_pressed_bit facing_direction
 version id 
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay version id]  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level
 version id 
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:snow_layer
statescovered_bitheight version idN  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:scaffolding
states	stabilitystability_check  version id 
blockname
minecraft:log
statesold_log_typejunglepillar_axisx version id  
blocknameminecraft:element_62
states version idH 
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit  version id 
blocknameminecraft:fence_gate
states	directionin_wall_bit open_bit  version idk  
blocknameminecraft:fence
states	wood_typespruce version idU  
blocknameminecraft:stone_pressure_plate
statesredstone_signal  version idF  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:shulker_box
statescolorgreen version id  
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay version id]  
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:dropper
statesfacing_direction
triggered_bit  version id}  
blocknameminecraft:leaves
states
old_leaf_typesprucepersistent_bit 
update_bit version id  
blocknameminecraft:powered_repeater
states	direction repeater_delay version id^  
blocknameminecraft:wool
statescolormagenta version id#  
blocknameminecraft:lapis_block
states version id  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3polished_granitetop_slot_bit  version id 
blocknameminecraft:stained_glass
statescolorred version id  
blocknameminecraft:andesite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:smooth_quartz_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2mossy_cobblestonetop_slot_bit version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_counttwo_egg version id 
blocknameminecraft:planks
states	wood_typeacacia version id  
blocknameminecraft:planks
states	wood_typebirch version id  
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:granite_stairs
statesupside_down_bit weirdo_direction version id 
blockname"minecraft:prismarine_bricks_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:snow_layer
statescovered_bitheight  version idN  
blocknameminecraft:coral_fan_hang3
statescoral_direction coral_hang_type_bitdead_bit  version id 
blocknameminecraft:smoker
statesfacing_direction version id 
blocknameminecraft:hard_stained_glass
statescolorblack version id  
blocknameminecraft:scaffolding
states	stabilitystability_check version id 
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:concretePowder
statescolorgreen version id  
blockname!minecraft:white_glazed_terracotta
statesfacing_direction version id  
blockname"minecraft:mossy_cobblestone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:concrete
statescolorred version id  
blocknameminecraft:stained_hardened_clay
statescolorcyan version id  
blocknameminecraft:acacia_pressure_plate
statesredstone_signal  version id 
blocknameminecraft:wool
statescolorgray version id#  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:fence_gate
states	directionin_wall_bitopen_bit version idk  
blocknameminecraft:acacia_stairs
statesupside_down_bit weirdo_direction  version id  
blockname
minecraft:tnt
statesallow_underwater_bitexplode_bit version id.  
blocknameminecraft:turtle_egg
states
cracked_statecrackedturtle_egg_count	three_egg version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version idG  
blocknameminecraft:command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:stained_glass
statescolorpink version id  
blocknameminecraft:bedrock
statesinfiniburn_bit version id  
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blockname!minecraft:red_nether_brick_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:bone_block
states
deprecatedpillar_axisy version id  
blocknameminecraft:stone_slab
statesstone_slab_typestone_bricktop_slot_bit  version id,  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit  version id  
blockname!minecraft:black_glazed_terracotta
statesfacing_direction version id  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:glowingobsidian
states version id  
blocknameminecraft:bell
states
attachmentside	direction
toggle_bit version id 
blockname minecraft:cyan_glazed_terracotta
statesfacing_direction version id  
blockname!minecraft:red_nether_brick_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:snow_layer
statescovered_bitheight version idN  
blocknameminecraft:hard_stained_glass
statescolorpink version id  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:element_107
states version idu 
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:double_plant
statesdouble_plant_type	sunflowerupper_block_bit  version id  
blocknameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:nether_brick_stairs
statesupside_down_bitweirdo_direction  version idr  
blocknameminecraft:element_110
states version idx 
blocknameminecraft:tripWire
statesattached_bitdisarmed_bitpowered_bit 
suspended_bit  version id  
blocknameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version id  
blocknameminecraft:sea_pickle
states
cluster_count dead_bit  version id 
blocknameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit  version id  
blocknameminecraft:stone_slab2
statesstone_slab_type_2purpurtop_slot_bit version id  
blocknameminecraft:soul_sand
states version idX  
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay version id]  
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:stonecutter_block
statesfacing_direction version id 
blockname!minecraft:white_glazed_terracotta
statesfacing_direction  version id  
blockname
minecraft:bed
states	directionhead_piece_bitoccupied_bit version id  
blocknameminecraft:bamboo_sapling
statesage_bit sapling_typespruce version id 
blocknameminecraft:andesite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit  version id 
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:ladder
statesfacing_direction version idA  
blocknameminecraft:anvil
statesdamagebroken	direction version id  
blocknameminecraft:tripWire
statesattached_bitdisarmed_bitpowered_bit 
suspended_bit version id  
blocknameminecraft:piston
statesfacing_direction
 version id!  
blocknameminecraft:wood
statespillar_axisystripped_bit	wood_typebirch version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2mossy_cobblestonetop_slot_bit  version id  
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:torch
statestorch_facing_directionsouth version id2  
blocknameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:smoker
statesfacing_direction  version id 
blocknameminecraft:command_block
statesconditional_bitfacing_direction
 version id  
blocknameminecraft:chain_command_block
statesconditional_bit facing_direction
 version id  
blocknameminecraft:reserved6
states version id  
blocknameminecraft:jigsaw
statesfacing_direction version id 
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:element_55
states version idA 
blocknameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:element_84
states version id^ 
blocknameminecraft:lit_blast_furnace
statesfacing_direction version id 
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction version id  
blocknameminecraft:sticky_piston
statesfacing_direction  version id  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:underwater_torch
statestorch_facing_directiontop version id  
blocknameminecraft:dropper
statesfacing_direction
triggered_bit  version id}  
blocknameminecraft:scaffolding
states	stabilitystability_check version id 
blocknameminecraft:cobblestone_wall
stateswall_block_typebrick version id  
blocknameminecraft:pumpkin_stem
statesgrowth version idh  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:red_mushroom
states version id(  
blocknameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:jungle_trapdoor
states	direction open_bitupside_down_bit  version id 
blocknameminecraft:acacia_door
states	direction door_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:detector_rail
states
rail_data_bitrail_direction version id  
blocknameminecraft:jungle_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:end_portal_frame
states	direction end_portal_eye_bit version idx  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_bricktop_slot_bit version id  
blocknameminecraft:element_11
states version id 
blockname"minecraft:mossy_cobblestone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:end_rod
statesfacing_direction  version id  
blockname!minecraft:repeating_command_block
statesconditional_bit facing_direction
 version id  
blocknameminecraft:pumpkin
states	direction version idV  
blockname minecraft:blue_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:dark_oak_fence_gate
states	direction in_wall_bit open_bit  version id  
blocknameminecraft:end_portal_frame
states	directionend_portal_eye_bit version idx  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:stripped_spruce_log
statespillar_axisx version id 
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:glass
states version id  
blocknameminecraft:element_8
states version id 
blocknameminecraft:frosted_ice
statesage version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit version id  
blockname"minecraft:prismarine_bricks_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:end_brick_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:pistonArmCollision
statesfacing_direction  version id"  
blocknameminecraft:potatoes
statesgrowth version id  
blocknameminecraft:spruce_stairs
statesupside_down_bitweirdo_direction version id  
blockname
minecraft:bed
states	directionhead_piece_bit occupied_bit version id  
blocknameminecraft:bell
states
attachmenthanging	direction
toggle_bit version id 
blocknameminecraft:bell
states
attachmenthanging	direction
toggle_bit  version id 
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit
update_bit version id  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:colored_torch_rg
states	color_bittorch_facing_directionsouth version id  
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id@  
blocknameminecraft:wood
statespillar_axiszstripped_bit 	wood_typebirch version id 
blocknameminecraft:grindstone
states
attachmentmultiple	direction version id 
blocknameminecraft:sandstone
statessand_stone_typedefault version id  
blockname minecraft:dark_prismarine_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:granite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:dropper
statesfacing_direction 
triggered_bit  version id}  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:purpur_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:cake
statesbite_counter version id\  
blocknameminecraft:hopper
statesfacing_direction
toggle_bit  version id  
blocknameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:stone_button
statesbutton_pressed_bitfacing_direction  version idM  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:carrots
statesgrowth version id  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2smooth_sandstonetop_slot_bit version id  
blocknameminecraft:purpur_block
stateschisel_typechiseledpillar_axisx version id  
blocknameminecraft:concretePowder
statescolororange version id  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:acacia_trapdoor
states	direction open_bitupside_down_bit version id 
blocknameminecraft:lever
stateslever_directionup_north_southopen_bit  version idE  
blocknameminecraft:coral_block
statescoral_colorpinkdead_bit version id 
blocknameminecraft:oak_stairs
statesupside_down_bit weirdo_direction version id5  
blocknameminecraft:stained_glass
statescolorsilver version id  
blocknameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:nether_brick_stairs
statesupside_down_bit weirdo_direction  version idr  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:wooden_button
statesbutton_pressed_bit facing_direction version id  
blocknameminecraft:powered_repeater
states	directionrepeater_delay version id^  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:rail
statesrail_direction
 version idB  
blocknameminecraft:snow_layer
statescovered_bitheight version idN  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:wooden_slab
statestop_slot_bit	wood_typejungle version id  
blocknameminecraft:hard_glass
states version id  
blocknameminecraft:furnace
statesfacing_direction version id=  
blocknameminecraft:kelp
stateskelp_age0 version id 
blocknameminecraft:beetroot
statesgrowth version id  
blockname
minecraft:log
statesold_log_typebirchpillar_axisy version id  
blocknameminecraft:quartz_block
stateschisel_typelinespillar_axisz version id  
blockname minecraft:gray_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit version idG  
blocknameminecraft:red_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:lit_furnace
statesfacing_direction version id>  
blocknameminecraft:coral_fan_dead
statescoral_coloryellowcoral_fan_direction  version id 
blocknameminecraft:concretePowder
statescolorblack version id  
blocknameminecraft:beehive
statesfacing_direction honey_level version id 
blocknameminecraft:sponge
statessponge_typedry version id  
blocknameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:jungle_fence_gate
states	direction in_wall_bitopen_bit version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:seagrass
statessea_grass_typedefault version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blockname"minecraft:yellow_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:lit_smoker
statesfacing_direction
 version id 
blocknameminecraft:netherreactor
states version id  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit version id  
blocknameminecraft:unpowered_repeater
states	direction repeater_delay version id]  
blocknameminecraft:double_wooden_slab
statestop_slot_bit	wood_typeoak version id  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:acacia_wall_sign
statesfacing_direction
 version id 
blocknameminecraft:dried_kelp_block
states version id 
blocknameminecraft:trapdoor
states	direction open_bit upside_down_bit version id`  
blockname
minecraft:bed
states	direction head_piece_bit occupied_bit version id  
blocknameminecraft:chest
statesfacing_direction
 version id6  
blocknameminecraft:wooden_slab
statestop_slot_bit 	wood_typeacacia version id  
blockname!minecraft:green_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:wooden_slab
statestop_slot_bit 	wood_typejungle version id  
blocknameminecraft:tripWire
statesattached_bit disarmed_bit powered_bit
suspended_bit  version id  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3polished_granitetop_slot_bit version id 
blocknameminecraft:log2
statesnew_log_typeacaciapillar_axisy version id  
blockname
minecraft:air
states version id   
blocknameminecraft:end_rod
statesfacing_direction
 version id  
blocknameminecraft:smooth_quartz_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:beehive
statesfacing_directionhoney_level  version id 
blocknameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction  version id 
blocknameminecraft:brewing_stand
statesbrewing_stand_slot_a_bit brewing_stand_slot_b_bit brewing_stand_slot_c_bit  version idu  
blocknameminecraft:nether_brick_stairs
statesupside_down_bitweirdo_direction version idr  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:stripped_acacia_log
statespillar_axisy version id 
blocknameminecraft:observer
statesfacing_directionpowered_bit version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction  version id 
blocknameminecraft:double_plant
statesdouble_plant_typeroseupper_block_bit  version id  
blocknameminecraft:normal_stone_stairs
statesupside_down_bitweirdo_direction version id 
blockname"minecraft:stickyPistonArmCollision
statesfacing_direction version id 
blocknameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:stone_slab3
statesstone_slab_type_3polished_andesitetop_slot_bit  version id 
blockname!minecraft:brown_glazed_terracotta
statesfacing_direction version id  
blockname"minecraft:orange_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:activator_rail
states
rail_data_bit rail_direction version id~  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:bee_nest
statesfacing_directionhoney_level  version id 
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:lit_pumpkin
states	direction version id[  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:element_41
states version id3 
blocknameminecraft:concrete
statescolorgreen version id  
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit  version id 
blocknameminecraft:dark_oak_fence_gate
states	direction in_wall_bit open_bit version id  
blocknameminecraft:flowing_water
statesliquid_depth version id  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:carpet
statescolorblue version id  
blocknameminecraft:stone_slab3
statesstone_slab_type_3granitetop_slot_bit version id 
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2
red_sandstonetop_slot_bit  version id  
blocknameminecraft:lever
stateslever_directionwestopen_bit  version idE  
blocknameminecraft:element_45
states version id7 
blocknameminecraft:unpowered_repeater
states	direction repeater_delay  version id]  
blocknameminecraft:nether_wart_block
states version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:log2
statesnew_log_typeacaciapillar_axisz version id  
blocknameminecraft:unlit_redstone_torch
statestorch_facing_directionnorth version idK  
blocknameminecraft:fence_gate
states	directionin_wall_bitopen_bit  version idk  
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction
 version id 
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:wall_banner
statesfacing_direction version id  
blockname!minecraft:green_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:sapling
statesage_bit sapling_typejungle version id  
blocknameminecraft:leaves
states
old_leaf_typejunglepersistent_bit
update_bit  version id  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:stained_glass
statescolorgreen version id  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:dispenser
statesfacing_direction
triggered_bit version id  
blocknameminecraft:shulker_box
statescolororange version id  
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version id  
blocknameminecraft:cocoa
statesage 	direction version id  
blocknameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version id 
blocknameminecraft:element_19
states version id 
blocknameminecraft:wood
statespillar_axisystripped_bit 	wood_typeoak version id 
blocknameminecraft:element_16
states version id 
blocknameminecraft:acacia_fence_gate
states	direction in_wall_bit open_bit  version id  
blocknameminecraft:standing_banner
statesground_sign_direction  version id  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:stone
states
stone_typediorite version id  
blocknameminecraft:bamboo
statesage_bit bamboo_leaf_size	no_leavesbamboo_stalk_thicknessthin version id 
blocknameminecraft:bell
states
attachmenthanging	direction
toggle_bit version id 
blocknameminecraft:stained_glass_pane
statescolorsilver version id  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:bamboo_sapling
statesage_bit sapling_typebirch version id 
blockname!minecraft:repeating_command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:colored_torch_bp
states	color_bit torch_facing_directionwest version id  
blocknameminecraft:leaves2
states
new_leaf_typedark_oakpersistent_bit 
update_bit  version id  
blocknameminecraft:wood
statespillar_axiszstripped_bit 	wood_typeacacia version id 
blocknameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:element_109
states version idw 
blockname!minecraft:hard_stained_glass_pane
statescolorcyan version id  
blocknameminecraft:stone_button
statesbutton_pressed_bit facing_direction version idM  
blocknameminecraft:stained_hardened_clay
statescolorsilver version id  
blocknameminecraft:stone_slab
statesstone_slab_typenether_bricktop_slot_bit version id,  
blocknameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit  version id  
blocknameminecraft:beetroot
statesgrowth version id  
blockname
minecraft:bed
states	directionhead_piece_bitoccupied_bit  version id  
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit version id 
blocknameminecraft:rail
statesrail_direction version idB  
blocknameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version id  
blocknameminecraft:end_rod
statesfacing_direction version id  
blocknameminecraft:observer
statesfacing_directionpowered_bit version id  
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:coral_fan_dead
statescoral_colorpinkcoral_fan_direction version id 
blocknameminecraft:bell
states
attachmentside	direction
toggle_bit  version id 
blocknameminecraft:element_20
states version id 
blocknameminecraft:coral
statescoral_colorreddead_bit version id 
blocknameminecraft:leaves2
states
new_leaf_typedark_oakpersistent_bit 
update_bit version id  
blocknameminecraft:cauldron
statescauldron_liquidlava
fill_level version idv  
blocknameminecraft:concretePowder
statescolorred version id  
blocknameminecraft:sea_pickle
states
cluster_countdead_bit  version id 
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id@  
blocknameminecraft:stained_hardened_clay
statescolorbrown version id  
blocknameminecraft:pistonArmCollision
statesfacing_direction version id"  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:farmland
statesmoisturized_amount version id<  
blocknameminecraft:stone_slab3
statesstone_slab_type_3polished_dioritetop_slot_bit  version id 
blocknameminecraft:stone_slab3
statesstone_slab_type_3polished_andesitetop_slot_bit version id 
blocknameminecraft:stone_button
statesbutton_pressed_bit facing_direction version idM  
blocknameminecraft:iron_door
states	direction door_hinge_bit open_bit upper_block_bit  version idG  
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:carpet
statescolormagenta version id  
blocknameminecraft:stained_glass
statescolorblack version id  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:birch_button
statesbutton_pressed_bitfacing_direction version id 
blockname
minecraft:tnt
statesallow_underwater_bitexplode_bit  version id.  
blocknameminecraft:red_sandstone_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:hay_block
states
deprecatedpillar_axisz version id  
blocknameminecraft:element_13
states version id 
blocknameminecraft:pumpkin_stem
statesgrowth version idh  
blocknameminecraft:smooth_quartz_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:cauldron
statescauldron_liquidlava
fill_level
 version idv  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:powered_repeater
states	directionrepeater_delay version id^  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:lectern
states	direction powered_bit  version id 
blocknameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:turtle_egg
states
cracked_statecrackedturtle_egg_countone_egg version id 
blockname!minecraft:polished_granite_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:golden_rail
states
rail_data_bitrail_direction version id  
blocknameminecraft:quartz_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:jungle_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:powered_comparator
states	direction output_lit_bit output_subtract_bit version id  
blocknameminecraft:sea_pickle
states
cluster_countdead_bit  version id 
blocknameminecraft:wood
statespillar_axisystripped_bit 	wood_typeacacia version id 
blocknameminecraft:acacia_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:acacia_door
states	direction door_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:carpet
statescolorsilver version id  
blocknameminecraft:snow_layer
statescovered_bitheight version idN  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:diorite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:lever
stateslever_directionup_east_westopen_bit  version idE  
blocknameminecraft:water
statesliquid_depth
 version id	  
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:barrel
statesfacing_directionopen_bit  version id 
blocknameminecraft:crafting_table
states version id:  
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay version id]  
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version idG  
blocknameminecraft:lever
stateslever_directioneastopen_bit version idE  
blocknameminecraft:element_14
states version id 
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:spruce_pressure_plate
statesredstone_signal  version id 
blocknameminecraft:sweet_berry_bush
statesgrowth version id 
blocknameminecraft:chorus_flower
statesage version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:concrete
statescolorgray version id  
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:fence_gate
states	directionin_wall_bit open_bit version idk  
blocknameminecraft:colored_torch_bp
states	color_bit torch_facing_directionnorth version id  
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit  version id 
blocknameminecraft:activator_rail
states
rail_data_bitrail_direction
 version id~  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:purpur_block
stateschisel_typesmoothpillar_axisy version id  
blockname!minecraft:black_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:water
statesliquid_depth version id	  
blockname!minecraft:red_nether_brick_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:lava
statesliquid_depth  version id  
blocknameminecraft:element_112
states version idz 
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:redstone_wire
statesredstone_signal  version id7  
blocknameminecraft:pumpkin_stem
statesgrowth
 version idh  
blocknameminecraft:fence_gate
states	directionin_wall_bitopen_bit  version idk  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:iron_door
states	direction door_hinge_bit open_bitupper_block_bit  version idG  
blockname!minecraft:polished_granite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:stone
states
stone_typestone version id  
blocknameminecraft:bamboo
statesage_bitbamboo_leaf_sizelarge_leavesbamboo_stalk_thicknessthick version id 
blocknameminecraft:scaffolding
states	stabilitystability_check  version id 
blocknameminecraft:brown_mushroom
states version id'  
blocknameminecraft:oak_stairs
statesupside_down_bitweirdo_direction  version id5  
blocknameminecraft:smoker
statesfacing_direction version id 
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id@  
blocknameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit version id  
blocknameminecraft:trapdoor
states	direction open_bitupside_down_bit  version id`  
blocknameminecraft:leaves
states
old_leaf_typeoakpersistent_bit 
update_bit version id  
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:golden_rail
states
rail_data_bitrail_direction version id  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2purpurtop_slot_bit  version id  
blocknameminecraft:carpet
statescolorpink version id  
blocknameminecraft:vine
statesvine_direction_bits version idj  
blockname&minecraft:light_blue_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:magma
states version id  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:acacia_wall_sign
statesfacing_direction  version id 
blocknameminecraft:scaffolding
states	stability stability_check version id 
blocknameminecraft:cocoa
statesage	direction version id  
blocknameminecraft:fire
statesage
 version id3  
blocknameminecraft:honey_block
states version id 
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:dark_oak_trapdoor
states	direction open_bitupside_down_bit version id 
blocknameminecraft:chain_command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:activator_rail
states
rail_data_bit rail_direction version id~  
blocknameminecraft:barrel
statesfacing_directionopen_bit  version id 
blockname minecraft:blue_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:stone_button
statesbutton_pressed_bitfacing_direction
 version idM  
blocknameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit  version id 
blockname minecraft:blue_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:cocoa
statesage 	direction version id  
blocknameminecraft:ladder
statesfacing_direction
 version idA  
blocknameminecraft:lit_smoker
statesfacing_direction version id 
blocknameminecraft:double_stone_slab
statesstone_slab_typequartztop_slot_bit  version id+  
blocknameminecraft:trapdoor
states	direction open_bitupside_down_bit version id`  
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:red_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:activator_rail
states
rail_data_bitrail_direction version id~  
blocknameminecraft:wheat
statesgrowth version id;  
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:trapped_chest
statesfacing_direction version id  
blockname minecraft:lime_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:stained_glass
statescolorbrown version id  
blocknameminecraft:hard_stained_glass
statescolorbrown version id  
blocknameminecraft:chorus_flower
statesage version id  
blockname
minecraft:log
statesold_log_typejunglepillar_axisz version id  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:stone_slab
statesstone_slab_typenether_bricktop_slot_bit  version id,  
blocknameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction version id 
blocknameminecraft:bamboo_sapling
statesage_bit sapling_typeacacia version id 
blocknameminecraft:campfire
states	directionextinguished version id 
blockname
minecraft:log
statesold_log_typesprucepillar_axisx version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:bell
states
attachmentstanding	direction
toggle_bit  version id 
blocknameminecraft:end_portal_frame
states	directionend_portal_eye_bit  version idx  
blocknameminecraft:stripped_acacia_log
statespillar_axisx version id 
blocknameminecraft:red_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:powered_repeater
states	direction repeater_delay version id^  
blocknameminecraft:stripped_dark_oak_log
statespillar_axisz version id 
blocknameminecraft:element_69
states version idO 
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:concrete
statescolorbrown version id  
blocknameminecraft:stone_slab3
statesstone_slab_type_3dioritetop_slot_bit version id 
blocknameminecraft:kelp
stateskelp_age" version id 
blocknameminecraft:stone_button
statesbutton_pressed_bitfacing_direction version idM  
blocknameminecraft:prismarine_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:bell
states
attachmenthanging	direction
toggle_bit version id 
blocknameminecraft:concretePowder
statescolor
light_blue version id  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blockname"minecraft:polished_andesite_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:stonecutter_block
statesfacing_direction version id 
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:cauldron
statescauldron_liquidwater
fill_level version idv  
blocknameminecraft:rail
statesrail_direction version idB  
blocknameminecraft:lever
stateslever_directiondown_north_southopen_bit  version idE  
blocknameminecraft:shulker_box
statescolorblack version id  
blocknameminecraft:birch_stairs
statesupside_down_bit weirdo_direction  version id  
blocknameminecraft:stone_stairs
statesupside_down_bit weirdo_direction  version idC  
blocknameminecraft:iron_door
states	direction door_hinge_bitopen_bitupper_block_bit  version idG  
blocknameminecraft:fence_gate
states	directionin_wall_bit open_bit  version idk  
blocknameminecraft:wool
statescolorgreen version id#  
blocknameminecraft:andesite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:fence
states	wood_typebirch version idU  
blocknameminecraft:element_38
states version id0 
blocknameminecraft:powered_repeater
states	directionrepeater_delay version id^  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id@  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:rail
statesrail_direction version idB  
blockname"minecraft:purple_glazed_terracotta
statesfacing_direction version id  
blockname
minecraft:bed
states	directionhead_piece_bit occupied_bit  version id  
blocknameminecraft:pumpkin_stem
statesgrowth version idh  
blocknameminecraft:element_60
states version idF 
blocknameminecraft:pumpkin
states	direction version idV  
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4stonetop_slot_bit version id 
blockname minecraft:lime_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:acacia_door
states	direction door_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:andesite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:dropper
statesfacing_direction
triggered_bit version id}  
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:detector_rail
states
rail_data_bitrail_direction
 version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version idG  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction
 version id 
blocknameminecraft:sapling
statesage_bitsapling_typespruce version id  
blocknameminecraft:lit_smoker
statesfacing_direction version id 
blocknameminecraft:beehive
statesfacing_directionhoney_level
 version id 
blocknameminecraft:stripped_oak_log
statespillar_axisy version id	 
blocknameminecraft:frame
statesfacing_directionitem_frame_map_bit  version id  
blocknameminecraft:double_plant
statesdouble_plant_type	sunflowerupper_block_bit version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:flowing_water
statesliquid_depth  version id  
blocknameminecraft:stonecutter
states version id  
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:beehive
statesfacing_direction
honey_level
 version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2red_nether_bricktop_slot_bit version id  
blocknameminecraft:wooden_door
states	direction door_hinge_bit open_bitupper_block_bit  version id@  
blocknameminecraft:element_18
states version id 
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:bell
states
attachmentside	direction 
toggle_bit version id 
blocknameminecraft:bamboo
statesage_bit bamboo_leaf_sizesmall_leavesbamboo_stalk_thicknessthin version id 
blocknameminecraft:sandstone_stairs
statesupside_down_bitweirdo_direction version id  
blockname!minecraft:black_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:structure_block
statesstructure_block_typedata version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:carrots
statesgrowth  version id  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2
red_sandstonetop_slot_bit  version id  
blockname"minecraft:prismarine_bricks_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:stonecutter_block
statesfacing_direction
 version id 
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:golden_rail
states
rail_data_bit rail_direction version id  
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:colored_torch_bp
states	color_bittorch_facing_directionnorth version id  
blocknameminecraft:sandstone
statessand_stone_typeheiroglyphs version id  
blocknameminecraft:dark_oak_trapdoor
states	direction open_bit upside_down_bit  version id 
blocknameminecraft:wheat
statesgrowth version id;  
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typejungle version id  
blocknameminecraft:dispenser
statesfacing_direction
triggered_bit version id  
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit  version id 
blocknameminecraft:shulker_box
statescolor
light_blue version id  
blocknameminecraft:composter
statescomposter_fill_level version id 
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4stonetop_slot_bit  version id 
blocknameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction  version id 
blockname"minecraft:stickyPistonArmCollision
statesfacing_direction
 version id 
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blockname!minecraft:smooth_sandstone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:wheat
statesgrowth version id;  
blocknameminecraft:skull
statesfacing_direction no_drop_bit version id  
blocknameminecraft:cobblestone_wall
stateswall_block_typenether_brick version id  
blocknameminecraft:dark_oak_door
states	direction door_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:cartography_table
states version id 
blocknameminecraft:kelp
stateskelp_age. version id 
blocknameminecraft:wool
statescolorred version id#  
blockname"minecraft:purple_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:element_76
states version idV 
blocknameminecraft:nether_brick
states version idp  
blocknameminecraft:double_wooden_slab
statestop_slot_bit	wood_typeacacia version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:pumpkin_stem
statesgrowth version idh  
blocknameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:stone_brick_stairs
statesupside_down_bit weirdo_direction  version idm  
blocknameminecraft:grindstone
states
attachmenthanging	direction version id 
blocknameminecraft:element_32
states version id* 
blocknameminecraft:podzol
states version id  
blocknameminecraft:leaves
states
old_leaf_typejunglepersistent_bit 
update_bit  version id  
blocknameminecraft:observer
statesfacing_direction powered_bit version id  
blocknameminecraft:bone_block
states
deprecatedpillar_axisz version id  
blocknameminecraft:element_6
states version id 
blocknameminecraft:lectern
states	directionpowered_bit  version id 
blocknameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version id  
blocknameminecraft:stained_glass_pane
statescolorgreen version id  
blocknameminecraft:lit_furnace
statesfacing_direction version id>  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:purpur_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:lit_pumpkin
states	direction  version id[  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id@  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:bell
states
attachmentmultiple	direction
toggle_bit version id 
blocknameminecraft:stained_glass
statescolororange version id  
blocknameminecraft:tripWire
statesattached_bitdisarmed_bit powered_bit 
suspended_bit  version id  
blocknameminecraft:command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:acacia_wall_sign
statesfacing_direction version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version idG  
blocknameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4
cut_sandstonetop_slot_bit version id 
blocknameminecraft:element_54
states version id@ 
blocknameminecraft:bee_nest
statesfacing_direction honey_level version id 
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version id  
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:chemistry_table
stateschemistry_table_typeelement_constructor	direction version id  
blockname minecraft:pink_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:jungle_stairs
statesupside_down_bitweirdo_direction version id  
blockname
minecraft:bed
states	directionhead_piece_bitoccupied_bit  version id  
blocknameminecraft:colored_torch_rg
states	color_bittorch_facing_directionunknown version id  
blocknameminecraft:dispenser
statesfacing_direction
triggered_bit version id  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blockname"minecraft:silver_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:flowing_lava
statesliquid_depth  version id
  
blocknameminecraft:purpur_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:cocoa
statesage	direction  version id  
blocknameminecraft:structure_block
statesstructure_block_typecorner version id  
blocknameminecraft:carved_pumpkin
states	direction version id 
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:sea_pickle
states
cluster_countdead_bit version id 
blocknameminecraft:lit_pumpkin
states	direction version id[  
blocknameminecraft:birch_wall_sign
statesfacing_direction version id 
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:sapling
statesage_bitsapling_typeacacia version id  
blocknameminecraft:stone_button
statesbutton_pressed_bitfacing_direction version idM  
blocknameminecraft:deadbush
states version id   
blocknameminecraft:wool
statescolorblack version id#  
blocknameminecraft:spruce_door
states	direction door_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:diorite_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:hay_block
states
deprecatedpillar_axisz version id  
blocknameminecraft:dark_oak_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:nether_wart
statesage version ids  
blocknameminecraft:dark_oak_door
states	direction door_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:lectern
states	directionpowered_bit  version id 
blocknameminecraft:chemistry_table
stateschemistry_table_typecompound_creator	direction version id  
blocknameminecraft:coral_fan_hang
statescoral_direction coral_hang_type_bitdead_bit  version id 
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:stone_slab4
statesstone_slab_type_4
smooth_quartztop_slot_bit version id 
blockname!minecraft:hard_stained_glass_pane
statescolorbrown version id  
blocknameminecraft:composter
statescomposter_fill_level version id 
blocknameminecraft:tripwire_hook
statesattached_bit	direction powered_bit version id  
blocknameminecraft:powered_repeater
states	direction repeater_delay version id^  
blocknameminecraft:trapdoor
states	directionopen_bitupside_down_bit version id`  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:beetroot
statesgrowth version id  
blocknameminecraft:purpur_block
stateschisel_typelinespillar_axisy version id  
blocknameminecraft:quartz_ore
states version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:observer
statesfacing_directionpowered_bit version id  
blocknameminecraft:coral_fan_hang2
statescoral_direction coral_hang_type_bitdead_bit  version id 
blocknameminecraft:enchanting_table
states version idt  
blockname
minecraft:bed
states	directionhead_piece_bitoccupied_bit version id  
blocknameminecraft:stained_hardened_clay
statescolororange version id  
blocknameminecraft:bee_nest
statesfacing_direction honey_level
 version id 
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:element_42
states version id4 
blocknameminecraft:glass_pane
states version idf  
blocknameminecraft:nether_brick_stairs
statesupside_down_bit weirdo_direction version idr  
blockname"minecraft:silver_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit 
update_bit  version id  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:stone_brick_stairs
statesupside_down_bitweirdo_direction version idm  
blocknameminecraft:concrete
statescolorwhite version id  
blockname!minecraft:polished_diorite_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:wood
statespillar_axisxstripped_bit 	wood_typedark_oak version id 
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:beehive
statesfacing_direction honey_level
 version id 
blocknameminecraft:stripped_spruce_log
statespillar_axisz version id 
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:quartz_stairs
statesupside_down_bitweirdo_direction  version id  
blocknameminecraft:frosted_ice
statesage  version id  
blocknameminecraft:chemistry_table
stateschemistry_table_typecompound_creator	direction version id  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:spruce_door
states	direction door_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:element_34
states version id, 
blocknameminecraft:wool
statescolorblue version id#  
blocknameminecraft:furnace
statesfacing_direction version id=  
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:water
statesliquid_depth  version id	  
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:melon_stem
statesgrowth  version idi  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2mossy_cobblestonetop_slot_bit version id  
blocknameminecraft:activator_rail
states
rail_data_bit rail_direction version id~  
blocknameminecraft:kelp
stateskelp_age$ version id 
blocknameminecraft:quartz_block
stateschisel_typedefaultpillar_axisx version id  
blocknameminecraft:powered_comparator
states	direction output_lit_bit output_subtract_bit  version id  
blocknameminecraft:snow_layer
statescovered_bit height  version idN  
blocknameminecraft:jigsaw
statesfacing_direction  version id 
blockname!minecraft:hard_stained_glass_pane
statescolorgreen version id  
blocknameminecraft:birch_fence_gate
states	direction in_wall_bitopen_bit version id  
blocknameminecraft:acacia_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:wood
statespillar_axiszstripped_bit	wood_typespruce version id 
blocknameminecraft:quartz_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:acacia_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id@  
blocknameminecraft:powered_repeater
states	directionrepeater_delay  version id^  
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:end_brick_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:prismarine_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit version id  
blockname"minecraft:orange_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:stone
states
stone_typegranite version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:scaffolding
states	stabilitystability_check  version id 
blocknameminecraft:concrete
statescolorlime version id  
blocknameminecraft:kelp
stateskelp_age  version id 
blocknameminecraft:element_1
states version id 
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version idG  
blocknameminecraft:reeds
statesage
 version idS  
blocknameminecraft:jungle_button
statesbutton_pressed_bit facing_direction
 version id 
blocknameminecraft:jungle_fence_gate
states	direction in_wall_bitopen_bit  version id  
blocknameminecraft:element_5
states version id 
blocknameminecraft:sapling
statesage_bit sapling_typedark_oak version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:potatoes
statesgrowth version id  
blocknameminecraft:structure_void
statesstructure_void_typevoid version id  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id@  
blocknameminecraft:coral
statescoral_coloryellowdead_bit  version id 
blocknameminecraft:carrots
statesgrowth version id  
blocknameminecraft:snow_layer
statescovered_bitheight version idN  
blocknameminecraft:purpur_stairs
statesupside_down_bit weirdo_direction  version id  
blocknameminecraft:hard_stained_glass
statescolorpurple version id  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:gravel
states version id
  
blocknameminecraft:water
statesliquid_depth version id	  
blockname
minecraft:bed
states	directionhead_piece_bit occupied_bit  version id  
blocknameminecraft:powered_repeater
states	directionrepeater_delay version id^  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:redstone_torch
statestorch_facing_directioneast version idL  
blocknameminecraft:dispenser
statesfacing_direction
triggered_bit  version id  
blocknameminecraft:portal
statesportal_axisz version idZ  
blocknameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:ladder
statesfacing_direction version idA  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:bell
states
attachmenthanging	direction 
toggle_bit  version id 
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit version id 
blocknameminecraft:normal_stone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:monster_egg
statesmonster_egg_stone_typecracked_stone_brick version ida  
blocknameminecraft:melon_block
states version idg  
blockname"minecraft:polished_andesite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4
cut_sandstonetop_slot_bit  version id 
blockname!minecraft:smooth_sandstone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:coral_fan_hang3
statescoral_direction coral_hang_type_bit dead_bit version id 
blocknameminecraft:powered_repeater
states	directionrepeater_delay version id^  
blockname"minecraft:purple_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2red_nether_bricktop_slot_bit  version id  
blocknameminecraft:coral_fan
statescoral_colorredcoral_fan_direction version id 
blocknameminecraft:bell
states
attachmentside	direction
toggle_bit version id 
blocknameminecraft:chemistry_table
stateschemistry_table_typeelement_constructor	direction version id  
blocknameminecraft:acacia_button
statesbutton_pressed_bit facing_direction  version id 
blocknameminecraft:fence_gate
states	directionin_wall_bitopen_bit version idk  
blocknameminecraft:element_116
states version id~ 
blocknameminecraft:sapling
statesage_bitsapling_typeoak version id  
blocknameminecraft:tripWire
statesattached_bit disarmed_bit powered_bit 
suspended_bit version id  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:brewing_stand
statesbrewing_stand_slot_a_bitbrewing_stand_slot_b_bit brewing_stand_slot_c_bit  version idu  
blocknameminecraft:spruce_wall_sign
statesfacing_direction version id 
blockname
minecraft:bed
states	direction head_piece_bitoccupied_bit version id  
blocknameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:acacia_wall_sign
statesfacing_direction version id 
blocknameminecraft:powered_repeater
states	directionrepeater_delay version id^  
blockname#minecraft:magenta_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:spruce_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_darktop_slot_bit version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:bamboo_sapling
statesage_bitsapling_typeoak version id 
blocknameminecraft:coral_block
statescoral_coloryellowdead_bit version id 
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blockname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:farmland
statesmoisturized_amount version id<  
blocknameminecraft:wool
statescolororange version id#  
blocknameminecraft:cake
statesbite_counter version id\  
blocknameminecraft:quartz_block
stateschisel_typechiseledpillar_axisy version id  
blocknameminecraft:element_117
states version id 
blocknameminecraft:chemistry_table
stateschemistry_table_type	lab_table	direction  version id  
blocknameminecraft:command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:lectern
states	directionpowered_bit  version id 
blocknameminecraft:observer
statesfacing_directionpowered_bit  version id  
blocknameminecraft:gold_block
states version id)  
blocknameminecraft:stripped_birch_log
statespillar_axisz version id 
blocknameminecraft:cocoa
statesage	direction version id  
blocknameminecraft:wooden_slab
statestop_slot_bit	wood_typespruce version id  
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:cauldron
statescauldron_liquidwater
fill_level
 version idv  
blocknameminecraft:cocoa
statesage	direction version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id@  
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:concretePowder
statescolorsilver version id  
blocknameminecraft:element_68
states version idN 
blocknameminecraft:wool
statescolorsilver version id#  
blocknameminecraft:invisibleBedrock
states version id_  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal
 version idH  
blocknameminecraft:glowstone
states version idY  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:darkoak_wall_sign
statesfacing_direction version id 
blocknameminecraft:oak_stairs
statesupside_down_bit weirdo_direction version id5  
blocknameminecraft:quartz_block
stateschisel_typechiseledpillar_axisz version id  
blocknameminecraft:tripwire_hook
statesattached_bit 	direction powered_bit  version id  
blocknameminecraft:end_rod
statesfacing_direction version id  
blocknameminecraft:acacia_door
states	direction door_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction  version id 
blocknameminecraft:jungle_door
states	direction door_hinge_bitopen_bitupper_block_bit  version id  
blockname"minecraft:mossy_stone_brick_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:turtle_egg
states
cracked_statemax_crackedturtle_egg_counttwo_egg version id 
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:wool
statescolorlime version id#  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:element_93
states version idg 
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:wooden_slab
statestop_slot_bit 	wood_typespruce version id  
blockname!minecraft:smooth_sandstone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:double_stone_slab
statesstone_slab_typenether_bricktop_slot_bit version id+  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:bamboo
statesage_bit bamboo_leaf_sizelarge_leavesbamboo_stalk_thicknessthin version id 
blocknameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:concretePowder
statescolorpurple version id  
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:darkoak_wall_sign
statesfacing_direction version id 
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version id  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:rail
statesrail_direction version idB  
blocknameminecraft:hay_block
states
deprecatedpillar_axisx version id  
blocknameminecraft:unpowered_comparator
states	direction output_lit_bitoutput_subtract_bit version id  
blocknameminecraft:element_96
states version idj 
blocknameminecraft:leaves2
states
new_leaf_typedark_oakpersistent_bit
update_bit  version id  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:spruce_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:stained_glass
statescolormagenta version id  
blocknameminecraft:brewing_stand
statesbrewing_stand_slot_a_bit brewing_stand_slot_b_bitbrewing_stand_slot_c_bit version idu  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:sapling
statesage_bit sapling_typespruce version id  
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit version id  
blocknameminecraft:powered_repeater
states	directionrepeater_delay version id^  
blocknameminecraft:carpet
statescolorwhite version id  
blocknameminecraft:detector_rail
states
rail_data_bitrail_direction version id  
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:prismarine
statesprismarine_block_typedefault version id  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blockname
minecraft:bed
states	directionhead_piece_bitoccupied_bit  version id  
blockname"minecraft:stickyPistonArmCollision
statesfacing_direction version id 
blocknameminecraft:iron_trapdoor
states	direction open_bit upside_down_bit  version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:dispenser
statesfacing_direction
triggered_bit version id  
blocknameminecraft:pumpkin_stem
statesgrowth version idh  
blockname"minecraft:purple_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:stone_brick_stairs
statesupside_down_bit weirdo_direction version idm  
blocknameminecraft:nether_brick_stairs
statesupside_down_bitweirdo_direction version idr  
blocknameminecraft:bell
states
attachmentstanding	direction 
toggle_bit  version id 
blockname minecraft:lime_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:element_87
states version ida 
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:leaves
states
old_leaf_typeoakpersistent_bit
update_bit  version id  
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit  version id  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit version idG  
blocknameminecraft:hopper
statesfacing_direction
toggle_bit version id  
blocknameminecraft:lit_blast_furnace
statesfacing_direction  version id 
blocknameminecraft:cauldron
statescauldron_liquidwater
fill_level version idv  
blocknameminecraft:wood
statespillar_axiszstripped_bit	wood_typeoak version id 
blocknameminecraft:jungle_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:colored_torch_rg
states	color_bittorch_facing_directionnorth version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit version idG  
blocknameminecraft:lever
stateslever_directiondown_north_southopen_bit version idE  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blockname!minecraft:polished_diorite_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:lit_blast_furnace
statesfacing_direction version id 
blocknameminecraft:noteblock
states version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blockname!minecraft:brown_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:quartz_block
stateschisel_typesmoothpillar_axisz version id  
blocknameminecraft:coral_fan_hang
statescoral_direction coral_hang_type_bit dead_bit  version id 
blocknameminecraft:detector_rail
states
rail_data_bitrail_direction  version id  
blocknameminecraft:purpur_block
stateschisel_typedefaultpillar_axisy version id  
blocknameminecraft:chemical_heat
states version id  
blocknameminecraft:snow_layer
statescovered_bit height version idN  
blocknameminecraft:scaffolding
states	stabilitystability_check  version id 
blocknameminecraft:stone_slab3
statesstone_slab_type_3smooth_red_sandstonetop_slot_bit version id 
blocknameminecraft:furnace
statesfacing_direction version id=  
blocknameminecraft:quartz_block
stateschisel_typelinespillar_axisx version id  
blockname
minecraft:bed
states	directionhead_piece_bit occupied_bit  version id  
blocknameminecraft:sapling
statesage_bit sapling_typebirch version id  
blocknameminecraft:sandstone_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:double_plant
statesdouble_plant_typefernupper_block_bit  version id  
blocknameminecraft:hard_stained_glass
statescolorgray version id  
blocknameminecraft:element_40
states version id2 
blocknameminecraft:smooth_quartz_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:turtle_egg
states
cracked_statecrackedturtle_egg_counttwo_egg version id 
blocknameminecraft:redstone_torch
statestorch_facing_directionnorth version idL  
blocknameminecraft:birch_pressure_plate
statesredstone_signal  version id 
blocknameminecraft:dropper
statesfacing_direction

triggered_bit  version id}  
blocknameminecraft:chemistry_table
stateschemistry_table_type	lab_table	direction version id  
blocknameminecraft:end_rod
statesfacing_direction version id  
blocknameminecraft:coral_block
statescoral_colorreddead_bit version id 
blocknameminecraft:stone_stairs
statesupside_down_bit weirdo_direction version idC  
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:acacia_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:bell
states
attachmenthanging	direction
toggle_bit  version id 
blocknameminecraft:wood
statespillar_axiszstripped_bit	wood_typebirch version id 
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:jungle_stairs
statesupside_down_bit weirdo_direction  version id  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:carved_pumpkin
states	direction version id 
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:element_51
states version id= 
blocknameminecraft:blast_furnace
statesfacing_direction  version id 
blocknameminecraft:piston
statesfacing_direction  version id!  
blocknameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:concrete
statescolorblue version id  
blocknameminecraft:acacia_trapdoor
states	direction open_bit upside_down_bit version id 
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version id  
blocknameminecraft:barrel
statesfacing_direction open_bit version id 
blocknameminecraft:quartz_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:bedrock
statesinfiniburn_bit  version id  
blocknameminecraft:cactus
statesage
 version idQ  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:underwater_torch
statestorch_facing_directionunknown version id  
blocknameminecraft:conduit
states version id 
blocknameminecraft:hay_block
states
deprecatedpillar_axisx version id  
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:element_56
states version idB 
blocknameminecraft:scaffolding
states	stabilitystability_check version id 
blocknameminecraft:chain_command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:acacia_trapdoor
states	direction open_bit upside_down_bit  version id 
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:stained_hardened_clay
statescoloryellow version id  
blocknameminecraft:observer
statesfacing_directionpowered_bit  version id  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:iron_bars
states version ide  
blocknameminecraft:stone_slab
statesstone_slab_typebricktop_slot_bit version id,  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blockname minecraft:cyan_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:jigsaw
statesfacing_direction version id 
blocknameminecraft:acacia_fence_gate
states	direction in_wall_bit open_bit version id  
blocknameminecraft:jungle_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:bone_block
states
deprecatedpillar_axisy version id  
blocknameminecraft:coral_block
statescoral_colorbluedead_bit version id 
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:bamboo_sapling
statesage_bitsapling_typejungle version id 
blockname!minecraft:hard_stained_glass_pane
statescolorsilver version id  
blocknameminecraft:acacia_stairs
statesupside_down_bitweirdo_direction  version id  
blocknameminecraft:command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:powered_repeater
states	direction repeater_delay  version id^  
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:prismarine_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit version id 
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:shulker_box
statescolorpurple version id  
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:end_brick_stairs
statesupside_down_bit weirdo_direction  version id 
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blocknameminecraft:snow_layer
statescovered_bit height version idN  
blocknameminecraft:unlit_redstone_torch
statestorch_facing_directionwest version idK  
blocknameminecraft:trapped_chest
statesfacing_direction version id  
blocknameminecraft:carpet
statescolor
light_blue version id  
blocknameminecraft:stone_slab2
statesstone_slab_type_2prismarine_darktop_slot_bit  version id  
blocknameminecraft:tripWire
statesattached_bitdisarmed_bit powered_bit 
suspended_bit version id  
blockname!minecraft:brown_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:element_85
states version id_ 
blockname"minecraft:stickyPistonArmCollision
statesfacing_direction version id 
blocknameminecraft:scaffolding
states	stabilitystability_check version id 
blocknameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:element_37
states version id/ 
blocknameminecraft:birch_fence_gate
states	direction in_wall_bitopen_bit  version id  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:stained_glass_pane
statescolorbrown version id  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id@  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3end_stone_bricktop_slot_bit version id 
blocknameminecraft:nether_brick_fence
states version idq  
blocknameminecraft:redstone_lamp
states version id{  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3granitetop_slot_bit  version id 
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal
 version id 
blocknameminecraft:stone
states
stone_typegranite_smooth version id  
blocknameminecraft:bone_block
states
deprecatedpillar_axisx version id  
blocknameminecraft:birch_pressure_plate
statesredstone_signal
 version id 
blocknameminecraft:tallgrass
statestall_grass_typesnow version id  
blocknameminecraft:shulker_box
statescoloryellow version id  
blocknameminecraft:stone_slab2
statesstone_slab_type_2red_nether_bricktop_slot_bit  version id  
blocknameminecraft:wood
statespillar_axiszstripped_bit 	wood_typejungle version id 
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:dark_oak_fence_gate
states	direction in_wall_bitopen_bit version id  
blocknameminecraft:lantern
stateshanging  version id 
blocknameminecraft:powered_repeater
states	directionrepeater_delay version id^  
blocknameminecraft:standing_sign
statesground_sign_direction
 version id?  
blocknameminecraft:beehive
statesfacing_direction honey_level version id 
blocknameminecraft:flowing_water
statesliquid_depth
 version id  
blocknameminecraft:dirt
states	dirt_typecoarse version id  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:flowing_water
statesliquid_depth version id  
blockname"minecraft:polished_andesite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:command_block
statesconditional_bit facing_direction
 version id  
blocknameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level
 version id 
blocknameminecraft:powered_comparator
states	direction output_lit_bitoutput_subtract_bit version id  
blocknameminecraft:honeycomb_block
states version id 
blocknameminecraft:melon_stem
statesgrowth version idi  
blocknameminecraft:unpowered_comparator
states	direction output_lit_bitoutput_subtract_bit  version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:carpet
statescolororange version id  
blocknameminecraft:emerald_block
states version id  
blocknameminecraft:shulker_box
statescolorblue version id  
blocknameminecraft:stone_slab3
statesstone_slab_type_3polished_dioritetop_slot_bit version id 
blocknameminecraft:red_flower
statesflower_typeallium version id&  
blocknameminecraft:anvil
statesdamagebroken	direction  version id  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:element_23
states version id! 
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:anvil
statesdamageslightly_damaged	direction version id  
blockname minecraft:dark_prismarine_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:diorite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:stained_glass_pane
statescolorcyan version id  
blocknameminecraft:end_portal_frame
states	directionend_portal_eye_bit version idx  
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:stonecutter_block
statesfacing_direction version id 
blocknameminecraft:reeds
statesage  version idS  
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit  version id 
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:chorus_flower
statesage
 version id  
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4cut_red_sandstonetop_slot_bit version id 
blocknameminecraft:farmland
statesmoisturized_amount  version id<  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:lever
stateslever_directionsouthopen_bit version idE  
blocknameminecraft:wall_sign
statesfacing_direction  version idD  
blockname"minecraft:mossy_cobblestone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blockname&minecraft:light_blue_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blockname!minecraft:hard_stained_glass_pane
statescolorblack version id  
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:stonecutter_block
statesfacing_direction  version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2prismarine_bricktop_slot_bit version id  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:mossy_cobblestone
states version id0  
blocknameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version id  
blocknameminecraft:spruce_stairs
statesupside_down_bitweirdo_direction  version id  
blocknameminecraft:blast_furnace
statesfacing_direction version id 
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:element_74
states version idT 
blocknameminecraft:coral_fan_hang
statescoral_direction coral_hang_type_bit dead_bit version id 
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit  version id 
blockname
minecraft:log
statesold_log_typebirchpillar_axisz version id  
blocknameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit version id  
blocknameminecraft:colored_torch_rg
states	color_bittorch_facing_directioneast version id  
blocknameminecraft:element_26
states version id$ 
blocknameminecraft:chain_command_block
statesconditional_bit facing_direction version id  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:standing_banner
statesground_sign_direction
 version id  
blocknameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction version id 
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:cauldron
statescauldron_liquidwater
fill_level version idv  
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit version id 
blocknameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typespruce version id  
blocknameminecraft:wood
statespillar_axisxstripped_bit	wood_typeoak version id 
blocknameminecraft:dispenser
statesfacing_direction

triggered_bit  version id  
blocknameminecraft:cake
statesbite_counter version id\  
blocknameminecraft:stone_stairs
statesupside_down_bit weirdo_direction version idC  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:bell
states
attachmentmultiple	direction
toggle_bit version id 
blockname!minecraft:polished_diorite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:double_wooden_slab
statestop_slot_bit	wood_typespruce version id  
blocknameminecraft:bone_block
states
deprecated pillar_axisx version id  
blocknameminecraft:sticky_piston
statesfacing_direction version id  
blocknameminecraft:beehive
statesfacing_directionhoney_level  version id 
blocknameminecraft:sapling
statesage_bit sapling_typeoak version id  
blocknameminecraft:cobblestone_wall
stateswall_block_type	end_brick version id  
blocknameminecraft:purpur_block
stateschisel_typechiseledpillar_axisy version id  
blocknameminecraft:detector_rail
states
rail_data_bit rail_direction version id  
blocknameminecraft:wood
statespillar_axisxstripped_bit	wood_typedark_oak version id 
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit version id 
blocknameminecraft:ender_chest
statesfacing_direction version id  
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit version id 
blocknameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version id 
blocknameminecraft:end_rod
statesfacing_direction version id  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id@  
blocknameminecraft:movingBlock
states version id  
blocknameminecraft:bone_block
states
deprecated pillar_axisz version id  
blocknameminecraft:flowing_water
statesliquid_depth version id  
blockname"minecraft:polished_andesite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:snow_layer
statescovered_bit height version idN  
blocknameminecraft:skull
statesfacing_direction
no_drop_bit  version id  
blocknameminecraft:cocoa
statesage	direction version id  
blocknameminecraft:acacia_door
states	direction door_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:end_brick_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:birch_door
states	direction door_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:birch_wall_sign
statesfacing_direction version id 
blocknameminecraft:chain_command_block
statesconditional_bitfacing_direction  version id  
blockname minecraft:gray_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:hopper
statesfacing_direction
toggle_bit  version id  
blocknameminecraft:double_stone_slab
statesstone_slab_typestone_bricktop_slot_bit  version id+  
blocknameminecraft:stone_slab3
statesstone_slab_type_3end_stone_bricktop_slot_bit  version id 
blocknameminecraft:dropper
statesfacing_direction 
triggered_bit version id}  
blocknameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:element_103
states version idq 
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:redstone_wire
statesredstone_signal
 version id7  
blocknameminecraft:wool
statescolorpink version id#  
blocknameminecraft:beetroot
statesgrowth  version id  
blocknameminecraft:brick_stairs
statesupside_down_bitweirdo_direction version idl  
blocknameminecraft:double_stone_slab
statesstone_slab_typewoodtop_slot_bit version id+  
blocknameminecraft:structure_block
statesstructure_block_typeexport version id  
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4
smooth_quartztop_slot_bit  version id 
blocknameminecraft:stripped_birch_log
statespillar_axisx version id 
blocknameminecraft:double_plant
statesdouble_plant_typegrassupper_block_bit version id  
blocknameminecraft:darkoak_wall_sign
statesfacing_direction version id 
blocknameminecraft:beetroot
statesgrowth
 version id  
blocknameminecraft:smooth_quartz_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:dark_oak_fence_gate
states	direction in_wall_bitopen_bit  version id  
blocknameminecraft:jungle_door
states	direction door_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:bone_block
states
deprecatedpillar_axisz version id  
blocknameminecraft:emerald_ore
states version id  
blocknameminecraft:dropper
statesfacing_direction
triggered_bit  version id}  
blocknameminecraft:lectern
states	directionpowered_bit version id 
blocknameminecraft:grindstone
states
attachmenthanging	direction version id 
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:snow_layer
statescovered_bit height version idN  
blocknameminecraft:bone_block
states
deprecatedpillar_axisy version id  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3dioritetop_slot_bit  version id 
blocknameminecraft:acacia_fence_gate
states	direction in_wall_bitopen_bit version id  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal  version id  
blocknameminecraft:wooden_button
statesbutton_pressed_bit facing_direction
 version id  
blocknameminecraft:birch_wall_sign
statesfacing_direction version id 
blocknameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version id 
blocknameminecraft:stone
states
stone_typediorite_smooth version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:chest
statesfacing_direction version id6  
blocknameminecraft:shulker_box
statescolorcyan version id  
blocknameminecraft:stone_brick_stairs
statesupside_down_bitweirdo_direction version idm  
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blocknameminecraft:snow
states version idP  
blocknameminecraft:stone_slab3
statesstone_slab_type_3end_stone_bricktop_slot_bit version id 
blocknameminecraft:cobblestone_wall
stateswall_block_type
red_sandstone version id  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:quartz_block
stateschisel_typesmoothpillar_axisx version id  
blocknameminecraft:stone_button
statesbutton_pressed_bit facing_direction
 version idM  
blocknameminecraft:anvil
statesdamageslightly_damaged	direction version id  
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blockname"minecraft:polished_andesite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:ender_chest
statesfacing_direction version id  
blocknameminecraft:quartz_stairs
statesupside_down_bit weirdo_direction  version id  
blocknameminecraft:stained_hardened_clay
statescolorwhite version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version idG  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2prismarine_bricktop_slot_bit  version id  
blocknameminecraft:lever
stateslever_directionup_east_westopen_bit version idE  
blocknameminecraft:wooden_door
states	direction door_hinge_bitopen_bitupper_block_bit version id@  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3polished_andesitetop_slot_bit  version id 
blocknameminecraft:light_block
statesblock_light_level
 version id 
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:cake
statesbite_counter version id\  
blocknameminecraft:acacia_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:chorus_flower
statesage  version id  
blockname minecraft:cyan_glazed_terracotta
statesfacing_direction
 version id  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:wood
statespillar_axiszstripped_bit 	wood_typespruce version id 
blocknameminecraft:colored_torch_bp
states	color_bittorch_facing_directionsouth version id  
blocknameminecraft:brewing_stand
statesbrewing_stand_slot_a_bitbrewing_stand_slot_b_bitbrewing_stand_slot_c_bit  version idu  
blocknameminecraft:element_82
states version id\ 
blocknameminecraft:smoker
statesfacing_direction version id 
blocknameminecraft:carpet
statescolorgreen version id  
blocknameminecraft:acacia_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:chest
statesfacing_direction version id6  
blocknameminecraft:element_43
states version id5 
blockname"minecraft:mossy_cobblestone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:underwater_torch
statestorch_facing_directioneast version id  
blocknameminecraft:sapling
statesage_bitsapling_typebirch version id  
blocknameminecraft:element_35
states version id- 
blocknameminecraft:stripped_jungle_log
statespillar_axisy version id 
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blockname&minecraft:light_blue_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version idG  
blocknameminecraft:grindstone
states
attachmentstanding	direction version id 
blocknameminecraft:trapdoor
states	directionopen_bit upside_down_bit  version id`  
blocknameminecraft:stained_glass_pane
statescolorlime version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:coral_fan_hang2
statescoral_direction coral_hang_type_bit dead_bit version id 
blocknameminecraft:stained_glass_pane
statescolormagenta version id  
blocknameminecraft:stripped_birch_log
statespillar_axisy version id 
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:lever
stateslever_directionsouthopen_bit  version idE  
blocknameminecraft:darkoak_wall_sign
statesfacing_direction version id 
blocknameminecraft:wooden_door
states	direction door_hinge_bitopen_bit upper_block_bit  version id@  
blocknameminecraft:stone_stairs
statesupside_down_bitweirdo_direction version idC  
blocknameminecraft:stone_stairs
statesupside_down_bitweirdo_direction version idC  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:carpet
statescolorpurple version id  
blocknameminecraft:piston
statesfacing_direction version id!  
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit version id 
blocknameminecraft:clay
states version idR  
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:brewing_stand
statesbrewing_stand_slot_a_bitbrewing_stand_slot_b_bit brewing_stand_slot_c_bit version idu  
blocknameminecraft:stained_glass_pane
statescolororange version id  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:birch_trapdoor
states	direction open_bit upside_down_bit  version id 
blocknameminecraft:scaffolding
states	stabilitystability_check version id 
blocknameminecraft:stone_slab4
statesstone_slab_type_4cut_red_sandstonetop_slot_bit  version id 
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:normal_stone_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:red_flower
statesflower_typeoxeye version id&  
blocknameminecraft:sweet_berry_bush
statesgrowth version id 
blocknameminecraft:concrete
statescolorsilver version id  
blocknameminecraft:dark_oak_stairs
statesupside_down_bit weirdo_direction  version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:wooden_slab
statestop_slot_bit	wood_typeacacia version id  
blocknameminecraft:bee_nest
statesfacing_direction honey_level  version id 
blocknameminecraft:stone_slab4
statesstone_slab_type_4stonetop_slot_bit  version id 
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:concretePowder
statescolorlime version id  
blocknameminecraft:barrel
statesfacing_direction
open_bit version id 
blocknameminecraft:element_24
states version id" 
blocknameminecraft:colored_torch_rg
states	color_bit torch_facing_directiontop version id  
blockname minecraft:cyan_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:wood
statespillar_axiszstripped_bit	wood_typedark_oak version id 
blocknameminecraft:colored_torch_bp
states	color_bit torch_facing_directiontop version id  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:tripWire
statesattached_bitdisarmed_bitpowered_bit
suspended_bit version id  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:double_stone_slab
statesstone_slab_typequartztop_slot_bit version id+  
blockname"minecraft:mossy_cobblestone_stairs
statesupside_down_bit weirdo_direction version id 
blockname!minecraft:red_nether_brick_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:red_flower
statesflower_type
cornflower version id&  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2
red_sandstonetop_slot_bit version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal  version idH  
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:bell
states
attachmentstanding	direction
toggle_bit version id 
blocknameminecraft:cobblestone_wall
stateswall_block_typered_nether_brick version id  
blocknameminecraft:wooden_button
statesbutton_pressed_bit facing_direction  version id  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:stone_slab
statesstone_slab_typecobblestonetop_slot_bit  version id,  
blocknameminecraft:log2
statesnew_log_typedark_oakpillar_axisx version id  
blocknameminecraft:pistonArmCollision
statesfacing_direction version id"  
blocknameminecraft:observer
statesfacing_direction
powered_bit version id  
blockname"minecraft:orange_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:concretePowder
statescolorgray version id  
blocknameminecraft:sapling
statesage_bitsapling_typedark_oak version id  
blocknameminecraft:activator_rail
states
rail_data_bitrail_direction version id~  
blockname!minecraft:polished_diorite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:birch_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:stone_slab3
statesstone_slab_type_3andesitetop_slot_bit version id 
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blockname"minecraft:polished_andesite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:wood
statespillar_axisxstripped_bit 	wood_typeoak version id 
blocknameminecraft:birch_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:birch_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:bell
states
attachmentmultiple	direction
toggle_bit  version id 
blocknameminecraft:colored_torch_bp
states	color_bit torch_facing_directionunknown version id  
blocknameminecraft:element_118
states version id 
blocknameminecraft:double_plant
statesdouble_plant_typeroseupper_block_bit version id  
blocknameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:coral
statescoral_colorreddead_bit  version id 
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit version id 
blocknameminecraft:composter
statescomposter_fill_level version id 
blocknameminecraft:stained_glass
statescolorblue version id  
blocknameminecraft:shulker_box
statescolorred version id  
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay version id]  
blocknameminecraft:bone_block
states
deprecated pillar_axisy version id  
blocknameminecraft:trapdoor
states	directionopen_bitupside_down_bit  version id`  
blocknameminecraft:piston
statesfacing_direction version id!  
blocknameminecraft:leaves
states
old_leaf_typejunglepersistent_bit
update_bit version id  
blocknameminecraft:coral_block
statescoral_colorpurpledead_bit  version id 
blocknameminecraft:coral_fan
statescoral_colorpinkcoral_fan_direction  version id 
blocknameminecraft:wood
statespillar_axisystripped_bit	wood_typedark_oak version id 
blocknameminecraft:stone
states
stone_typeandesite version id  
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:stone_slab3
statesstone_slab_type_3andesitetop_slot_bit  version id 
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit  version id 
blocknameminecraft:kelp
stateskelp_age2 version id 
blocknameminecraft:powered_repeater
states	directionrepeater_delay  version id^  
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit version id 
blocknameminecraft:lectern
states	direction powered_bit version id 
blocknameminecraft:stained_glass_pane
statescolor
light_blue version id  
blocknameminecraft:nether_wart
statesage  version ids  
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:observer
statesfacing_directionpowered_bit version id  
blocknameminecraft:trapdoor
states	directionopen_bit upside_down_bit version id`  
blocknameminecraft:nether_brick_stairs
statesupside_down_bit weirdo_direction version idr  
blocknameminecraft:activator_rail
states
rail_data_bit rail_direction
 version id~  
blocknameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version id 
blocknameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:hard_stained_glass
statescolormagenta version id  
blocknameminecraft:bell
states
attachmentside	direction 
toggle_bit  version id 
blocknameminecraft:monster_egg
statesmonster_egg_stone_typestone version ida  
blocknameminecraft:yellow_flower
states version id%  
blocknameminecraft:concrete
statescolorcyan version id  
blocknameminecraft:tripWire
statesattached_bitdisarmed_bit powered_bit
suspended_bit version id  
blocknameminecraft:trapdoor
states	directionopen_bit upside_down_bit version id`  
blocknameminecraft:campfire
states	directionextinguished version id 
blocknameminecraft:bell
states
attachmenthanging	direction 
toggle_bit version id 
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:tripWire
statesattached_bit disarmed_bitpowered_bit 
suspended_bit  version id  
blocknameminecraft:stone_slab
statesstone_slab_typewoodtop_slot_bit  version id,  
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:kelp
stateskelp_age version id 
blockname minecraft:gray_glazed_terracotta
statesfacing_direction version id  
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level  version id 
blocknameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit version id 
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:command_block
statesconditional_bit facing_direction  version id  
blocknameminecraft:netherrack
states version idW  
blocknameminecraft:concrete
statescolor
light_blue version id  
blocknameminecraft:carpet
statescoloryellow version id  
blocknameminecraft:grindstone
states
attachmentside	direction version id 
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:double_wooden_slab
statestop_slot_bit	wood_typedark_oak version id  
blockname!minecraft:black_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:anvil
statesdamagevery_damaged	direction version id  
blocknameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:spruce_pressure_plate
statesredstone_signal version id 
blocknameminecraft:stone_stairs
statesupside_down_bitweirdo_direction  version idC  
blocknameminecraft:element_111
states version idy 
blocknameminecraft:chain_command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:dropper
statesfacing_direction
triggered_bit  version id}  
blocknameminecraft:beehive
statesfacing_direction honey_level version id 
blocknameminecraft:seaLantern
states version id  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:stained_glass
statescolor
light_blue version id  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:carrots
statesgrowth version id  
blocknameminecraft:birch_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:hard_stained_glass
statescolorcyan version id  
blocknameminecraft:stone_slab3
statesstone_slab_type_3smooth_red_sandstonetop_slot_bit  version id 
blocknameminecraft:chemistry_table
stateschemistry_table_type	lab_table	direction version id  
blockname
minecraft:bed
states	directionhead_piece_bit occupied_bit version id  
blocknameminecraft:granite_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:element_28
states version id& 
blocknameminecraft:bee_nest
statesfacing_direction honey_level version id 
blocknameminecraft:fire
statesage  version id3  
blocknameminecraft:blast_furnace
statesfacing_direction version id 
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:concretePowder
statescoloryellow version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id@  
blocknameminecraft:element_89
states version idc 
blockname!minecraft:repeating_command_block
statesconditional_bit facing_direction  version id  
blocknameminecraft:end_brick_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:wooden_button
statesbutton_pressed_bit facing_direction version id  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:jungle_trapdoor
states	direction open_bit upside_down_bit  version id 
blocknameminecraft:andesite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:double_stone_slab
statesstone_slab_type	sandstonetop_slot_bit version id+  
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:coal_block
states version id  
blocknameminecraft:smooth_stone
states version id 
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal  version id  
blocknameminecraft:jungle_fence_gate
states	direction in_wall_bit open_bit  version id  
blockname!minecraft:polished_granite_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blockname minecraft:pink_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:grass_path
states version id  
blocknameminecraft:acacia_trapdoor
states	direction open_bitupside_down_bit  version id 
blocknameminecraft:turtle_egg
states
cracked_statemax_crackedturtle_egg_count	three_egg version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:sandstone_stairs
statesupside_down_bitweirdo_direction  version id  
blocknameminecraft:ender_chest
statesfacing_direction version id  
blocknameminecraft:brick_block
states version id-  
blocknameminecraft:coral_fan_dead
statescoral_colorpinkcoral_fan_direction  version id 
blockname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:iron_ore
states version id  
blocknameminecraft:detector_rail
states
rail_data_bit rail_direction version id  
blocknameminecraft:golden_rail
states
rail_data_bit rail_direction version id  
blocknameminecraft:structure_block
statesstructure_block_typeinvalid version id  
blocknameminecraft:element_101
states version ido 
blocknameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:slime
states version id  
blockname!minecraft:black_glazed_terracotta
statesfacing_direction version id  
blockname!minecraft:green_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:potatoes
statesgrowth version id  
blocknameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit  version id  
blocknameminecraft:jungle_standing_sign
statesground_sign_direction version id 
blockname!minecraft:hard_stained_glass_pane
statescolorpink version id  
blocknameminecraft:dropper
statesfacing_direction

triggered_bit version id}  
blocknameminecraft:cauldron
statescauldron_liquidwater
fill_level version idv  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:tripwire_hook
statesattached_bit 	direction powered_bit version id  
blocknameminecraft:purpur_block
stateschisel_typechiseledpillar_axisz version id  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:spruce_stairs
statesupside_down_bit weirdo_direction  version id  
blocknameminecraft:anvil
statesdamageslightly_damaged	direction  version id  
blocknameminecraft:tripWire
statesattached_bit disarmed_bit powered_bit
suspended_bit version id  
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:stained_glass
statescolorpurple version id  
blocknameminecraft:purpur_block
stateschisel_typedefaultpillar_axisz version id  
blocknameminecraft:lit_blast_furnace
statesfacing_direction version id 
blocknameminecraft:leaves
states
old_leaf_typeoakpersistent_bit
update_bit version id  
blocknameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level  version id 
blockname&minecraft:light_blue_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:element_115
states version id} 
blockname
minecraft:tnt
statesallow_underwater_bit explode_bit version id.  
blocknameminecraft:normal_stone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:cobblestone_wall
stateswall_block_typecobblestone version id  
blocknameminecraft:colored_torch_rg
states	color_bit torch_facing_directioneast version id  
blocknameminecraft:coral
statescoral_colorbluedead_bit  version id 
blocknameminecraft:scaffolding
states	stability
stability_check version id 
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay version id]  
blocknameminecraft:coral_fan_hang2
statescoral_direction coral_hang_type_bit dead_bit  version id 
blockname"minecraft:mossy_stone_brick_stairs
statesupside_down_bit weirdo_direction version id 
blockname"minecraft:mossy_stone_brick_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:quartz_block
stateschisel_typesmoothpillar_axisy version id  
blocknameminecraft:brick_stairs
statesupside_down_bit weirdo_direction version idl  
blocknameminecraft:birch_stairs
statesupside_down_bitweirdo_direction  version id  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version id 
blocknameminecraft:element_30
states version id( 
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3end_stone_bricktop_slot_bit  version id 
blocknameminecraft:spruce_door
states	direction door_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version id 
blocknameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction  version id  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:beehive
statesfacing_directionhoney_level
 version id 
blocknameminecraft:bubble_column
states	drag_down  version id 
blocknameminecraft:melon_stem
statesgrowth
 version idi  
blockname!minecraft:hard_stained_glass_pane
statescolorlime version id  
blockname"minecraft:polished_andesite_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:element_48
states version id: 
blocknameminecraft:sticky_piston
statesfacing_direction version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:grindstone
states
attachmentmultiple	direction  version id 
blocknameminecraft:coral_fan_dead
statescoral_colorpurplecoral_fan_direction  version id 
blocknameminecraft:double_stone_slab
statesstone_slab_type	sandstonetop_slot_bit  version id+  
blocknameminecraft:spruce_stairs
statesupside_down_bitweirdo_direction version id  
blockname minecraft:dark_prismarine_stairs
statesupside_down_bit weirdo_direction  version id 
blockname"minecraft:mossy_cobblestone_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version id 
blocknameminecraft:lit_pumpkin
states	direction version id[  
blocknameminecraft:spruce_trapdoor
states	direction open_bit upside_down_bit version id 
blocknameminecraft:element_73
states version idS 
blocknameminecraft:birch_button
statesbutton_pressed_bitfacing_direction
 version id 
blocknameminecraft:jungle_pressure_plate
statesredstone_signal
 version id 
blocknameminecraft:cobblestone_wall
stateswall_block_typemossy_stone_brick version id  
blocknameminecraft:wall_banner
statesfacing_direction version id  
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:bubble_column
states	drag_down version id 
blocknameminecraft:quartz_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:prismarine
statesprismarine_block_typedark version id  
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:double_stone_slab
statesstone_slab_typebricktop_slot_bit version id+  
blocknameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:sticky_piston
statesfacing_direction version id  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:birch_door
states	direction door_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit 
update_bit version id  
blockname&minecraft:light_blue_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:brick_stairs
statesupside_down_bitweirdo_direction  version idl  
blocknameminecraft:wooden_door
states	direction door_hinge_bitopen_bitupper_block_bit  version id@  
blocknameminecraft:planks
states	wood_typeoak version id  
blocknameminecraft:sandstone_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:barrel
statesfacing_directionopen_bit  version id 
blocknameminecraft:shulker_box
statescolorsilver version id  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:element_39
states version id1 
blocknameminecraft:bookshelf
states version id/  
blocknameminecraft:stained_glass_pane
statescoloryellow version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:double_stone_slab
statesstone_slab_typewoodtop_slot_bit  version id+  
blocknameminecraft:concretePowder
statescolorpink version id  
blocknameminecraft:concrete
statescolororange version id  
blocknameminecraft:detector_rail
states
rail_data_bitrail_direction version id  
blocknameminecraft:sandstone_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:skull
statesfacing_direction
no_drop_bit version id  
blocknameminecraft:double_stone_slab
statesstone_slab_typecobblestonetop_slot_bit  version id+  
blocknameminecraft:fence_gate
states	directionin_wall_bit open_bit version idk  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:double_wooden_slab
statestop_slot_bit	wood_typebirch version id  
blocknameminecraft:stone_button
statesbutton_pressed_bit facing_direction version idM  
blocknameminecraft:coral_fan
statescoral_coloryellowcoral_fan_direction  version id 
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id@  
blocknameminecraft:coral_fan_dead
statescoral_coloryellowcoral_fan_direction version id 
blocknameminecraft:normal_stone_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:stained_glass_pane
statescolorpink version id  
blocknameminecraft:info_update2
states version id  
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:gold_ore
states version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id@  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level
 version id 
blockname
minecraft:tnt
statesallow_underwater_bit explode_bit  version id.  
blockname!minecraft:smooth_sandstone_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:undyed_shulker_box
states version id  
blocknameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:stonecutter_block
statesfacing_direction version id 
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:fence_gate
states	direction in_wall_bit open_bit  version idk  
blocknameminecraft:shulker_box
statescolorgray version id  
blocknameminecraft:sand
states	sand_typered version id  
blocknameminecraft:jungle_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version id  
blocknameminecraft:hay_block
states
deprecated pillar_axisy version id  
blocknameminecraft:wooden_slab
statestop_slot_bit 	wood_typedark_oak version id  
blocknameminecraft:double_stone_slab
statesstone_slab_typecobblestonetop_slot_bit version id+  
blocknameminecraft:sweet_berry_bush
statesgrowth version id 
blocknameminecraft:shulker_box
statescolorlime version id  
blocknameminecraft:carrots
statesgrowth
 version id  
blocknameminecraft:element_77
states version idW 
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit version id 
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit version id  
blockname minecraft:lime_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit version id  
blockname!minecraft:green_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:oak_stairs
statesupside_down_bit weirdo_direction version id5  
blocknameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_count	three_egg version id 
blocknameminecraft:stained_glass
statescoloryellow version id  
blocknameminecraft:red_flower
statesflower_typelily_of_the_valley version id&  
blocknameminecraft:red_sandstone
statessand_stone_typecut version id  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:fence
states	wood_typedark_oak version idU  
blocknameminecraft:activator_rail
states
rail_data_bitrail_direction  version id~  
blocknameminecraft:jungle_pressure_plate
statesredstone_signal  version id 
blocknameminecraft:wood
statespillar_axisxstripped_bit	wood_typespruce version id 
blocknameminecraft:jungle_door
states	direction door_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:element_59
states version idE 
blocknameminecraft:lit_smoker
statesfacing_direction version id 
blocknameminecraft:composter
statescomposter_fill_level version id 
blocknameminecraft:stone_brick_stairs
statesupside_down_bitweirdo_direction  version idm  
blocknameminecraft:bell
states
attachmenthanging	direction
toggle_bit  version id 
blockname"minecraft:silver_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:vine
statesvine_direction_bits  version idj  
blocknameminecraft:cocoa
statesage	direction version id  
blocknameminecraft:wood
statespillar_axisxstripped_bit 	wood_typespruce version id 
blocknameminecraft:info_update
states version id  
blocknameminecraft:carrots
statesgrowth version id  
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:unpowered_repeater
states	direction repeater_delay version id]  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit version id  
blockname minecraft:pink_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit version id 
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2smooth_sandstonetop_slot_bit version id  
blocknameminecraft:shulker_box
statescolorbrown version id  
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:scaffolding
states	stability stability_check  version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:tripWire
statesattached_bit disarmed_bitpowered_bit 
suspended_bit version id  
blocknameminecraft:acacia_standing_sign
statesground_sign_direction  version id 
blocknameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version id 
blockname!minecraft:red_nether_brick_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:element_79
states version idY 
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:coral_block
statescoral_colorbluedead_bit  version id 
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:redstone_wire
statesredstone_signal version id7  
blocknameminecraft:redstone_torch
statestorch_facing_directiontop version idL  
blocknameminecraft:coral_fan
statescoral_colorredcoral_fan_direction  version id 
blocknameminecraft:end_portal
states version idw  
blocknameminecraft:hay_block
states
deprecatedpillar_axisy version id  
blockname"minecraft:orange_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version id  
blocknameminecraft:spruce_door
states	direction door_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:stone_button
statesbutton_pressed_bitfacing_direction version idM  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:frame
statesfacing_direction item_frame_map_bit version id  
blocknameminecraft:stained_glass
statescolorcyan version id  
blocknameminecraft:stone_slab
statesstone_slab_typewoodtop_slot_bit version id,  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit version id  
blocknameminecraft:hard_stained_glass
statescolorwhite version id  
blocknameminecraft:bamboo
statesage_bitbamboo_leaf_sizesmall_leavesbamboo_stalk_thicknessthin version id 
blocknameminecraft:dark_oak_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:brewing_stand
statesbrewing_stand_slot_a_bit brewing_stand_slot_b_bitbrewing_stand_slot_c_bit  version idu  
blocknameminecraft:trapdoor
states	direction open_bit upside_down_bit  version id`  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:lectern
states	directionpowered_bit version id 
blocknameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:wheat
statesgrowth version id;  
blockname
minecraft:log
statesold_log_typesprucepillar_axisz version id  
blocknameminecraft:stained_hardened_clay
statescolorgreen version id  
blocknameminecraft:snow_layer
statescovered_bit height version idN  
blocknameminecraft:furnace
statesfacing_direction  version id=  
blocknameminecraft:iron_door
states	direction door_hinge_bitopen_bit upper_block_bit  version idG  
blocknameminecraft:golden_rail
states
rail_data_bit rail_direction  version id  
blocknameminecraft:lapis_ore
states version id  
blocknameminecraft:hopper
statesfacing_direction
toggle_bit  version id  
blocknameminecraft:element_0
states version id$  
blocknameminecraft:chemistry_table
stateschemistry_table_typeelement_constructor	direction  version id  
blocknameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version idG  
blocknameminecraft:red_sandstone_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:campfire
states	directionextinguished  version id 
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:sweet_berry_bush
statesgrowth version id 
blocknameminecraft:hopper
statesfacing_direction
toggle_bit  version id  
blocknameminecraft:detector_rail
states
rail_data_bit rail_direction  version id  
blocknameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_countone_egg version id 
blocknameminecraft:double_wooden_slab
statestop_slot_bit	wood_typejungle version id  
blocknameminecraft:jungle_wall_sign
statesfacing_direction
 version id 
blocknameminecraft:stained_hardened_clay
statescolorblack version id  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:smithing_table
states version id 
blocknameminecraft:wool
statescolorpurple version id#  
blocknameminecraft:underwater_torch
statestorch_facing_directionwest version id  
blocknameminecraft:beehive
statesfacing_direction
honey_level version id 
blocknameminecraft:bamboo_sapling
statesage_bit sapling_typeoak version id 
blocknameminecraft:smooth_quartz_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:bamboo
statesage_bitbamboo_leaf_sizesmall_leavesbamboo_stalk_thicknessthick version id 
blocknameminecraft:element_29
states version id' 
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blockname"minecraft:mossy_cobblestone_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit version id 
blocknameminecraft:spruce_wall_sign
statesfacing_direction version id 
blocknameminecraft:stripped_spruce_log
statespillar_axisy version id 
blocknameminecraft:torch
statestorch_facing_directionunknown version id2  
blocknameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version id 
blocknameminecraft:coral
statescoral_colorpinkdead_bit  version id 
blocknameminecraft:carrots
statesgrowth version id  
blocknameminecraft:double_plant
statesdouble_plant_typesyringaupper_block_bit  version id  
blocknameminecraft:element_53
states version id? 
blocknameminecraft:golden_rail
states
rail_data_bitrail_direction  version id  
blocknameminecraft:barrel
statesfacing_directionopen_bit version id 
blocknameminecraft:purpur_block
stateschisel_typesmoothpillar_axisx version id  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3andesitetop_slot_bit version id 
blocknameminecraft:double_stone_slab
statesstone_slab_typesmooth_stonetop_slot_bit version id+  
blocknameminecraft:log2
statesnew_log_typeacaciapillar_axisx version id  
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:element_95
states version idi 
blocknameminecraft:hard_stained_glass
statescolor
light_blue version id  
blocknameminecraft:spruce_fence_gate
states	direction in_wall_bitopen_bit  version id  
blockname!minecraft:hard_stained_glass_pane
statescolorpurple version id  
blocknameminecraft:kelp
stateskelp_age* version id 
blocknameminecraft:spruce_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:trapdoor
states	directionopen_bitupside_down_bit version id`  
blocknameminecraft:lava
statesliquid_depth
 version id  
blocknameminecraft:flower_pot
states
update_bit version id  
blocknameminecraft:cocoa
statesage 	direction version id  
blocknameminecraft:skull
statesfacing_direction no_drop_bit  version id  
blocknameminecraft:stone_slab3
statesstone_slab_type_3dioritetop_slot_bit  version id 
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction
 version id 
blocknameminecraft:stonebrick
statesstone_brick_typedefault version idb  
blocknameminecraft:spruce_wall_sign
statesfacing_direction  version id 
blocknameminecraft:wood
statespillar_axisystripped_bit	wood_typeoak version id 
blocknameminecraft:chemistry_table
stateschemistry_table_typematerial_reducer	direction  version id  
blocknameminecraft:birch_trapdoor
states	direction open_bitupside_down_bit  version id 
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit version id 
blockname#minecraft:magenta_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:wooden_door
states	direction door_hinge_bit open_bit upper_block_bit  version id@  
blocknameminecraft:end_brick_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:purpur_stairs
statesupside_down_bitweirdo_direction  version id  
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit  version id 
blocknameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version id 
blocknameminecraft:anvil
statesdamagebroken	direction version id  
blocknameminecraft:concretePowder
statescolorblue version id  
blocknameminecraft:element_9
states version id 
blocknameminecraft:anvil
statesdamagevery_damaged	direction  version id  
blockname!minecraft:brown_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit  version id  
blocknameminecraft:dark_oak_door
states	direction door_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:birch_button
statesbutton_pressed_bit facing_direction  version id 
blocknameminecraft:iron_trapdoor
states	direction open_bitupside_down_bit  version id  
blocknameminecraft:lectern
states	directionpowered_bit version id 
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:bell
states
attachmentside	direction
toggle_bit  version id 
blocknameminecraft:monster_egg
statesmonster_egg_stone_typemossy_stone_brick version ida  
blocknameminecraft:flowing_lava
statesliquid_depth version id
  
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:element_83
states version id] 
blocknameminecraft:double_stone_slab4
statesstone_slab_type_4cut_red_sandstonetop_slot_bit  version id 
blocknameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:dark_oak_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blocknameminecraft:chorus_plant
states version id  
blocknameminecraft:unpowered_repeater
states	directionrepeater_delay version id]  
blocknameminecraft:element_94
states version idh 
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:unpowered_comparator
states	direction output_lit_bit output_subtract_bit version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id@  
blocknameminecraft:element_106
states version idt 
blocknameminecraft:anvil
statesdamagebroken	direction version id  
blocknameminecraft:anvil
statesdamageslightly_damaged	direction version id  
blocknameminecraft:birch_button
statesbutton_pressed_bitfacing_direction  version id 
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal
 version id  
blocknameminecraft:prismarine_stairs
statesupside_down_bitweirdo_direction version id 
blockname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit version id 
blocknameminecraft:observer
statesfacing_direction powered_bit  version id  
blocknameminecraft:element_61
states version idG 
blocknameminecraft:wood
statespillar_axiszstripped_bit	wood_typeacacia version id 
blocknameminecraft:sapling
statesage_bit sapling_typeacacia version id  
blocknameminecraft:element_114
states version id| 
blocknameminecraft:lit_furnace
statesfacing_direction version id>  
blocknameminecraft:light_block
statesblock_light_level version id 
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blocknameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction  version id 
blocknameminecraft:lever
stateslever_directioneastopen_bit  version idE  
blocknameminecraft:carpet
statescolorred version id  
blocknameminecraft:skull
statesfacing_directionno_drop_bit version id  
blocknameminecraft:furnace
statesfacing_direction version id=  
blocknameminecraft:fire
statesage version id3  
blockname&minecraft:light_blue_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:unlit_redstone_torch
statestorch_facing_directiontop version idK  
blocknameminecraft:nether_brick_stairs
statesupside_down_bit weirdo_direction version idr  
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version id  
blockname!minecraft:smooth_sandstone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:element_63
states version idI 
blocknameminecraft:flowing_water
statesliquid_depth version id  
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:spruce_door
states	direction door_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:leaves
states
old_leaf_typebirchpersistent_bit 
update_bit version id  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:bee_nest
statesfacing_direction
honey_level  version id 
blocknameminecraft:element_70
states version idP 
blocknameminecraft:cake
statesbite_counter version id\  
blocknameminecraft:wooden_slab
statestop_slot_bit	wood_typedark_oak version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:beehive
statesfacing_direction
honey_level version id 
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:powered_repeater
states	directionrepeater_delay version id^  
blocknameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit version id  
blockname
minecraft:bed
states	direction head_piece_bitoccupied_bit  version id  
blocknameminecraft:acacia_door
states	direction door_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2smooth_sandstonetop_slot_bit  version id  
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit  version id  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:stone_slab
statesstone_slab_typebricktop_slot_bit  version id,  
blocknameminecraft:anvil
statesdamage	undamaged	direction version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:ladder
statesfacing_direction version idA  
blockname"minecraft:prismarine_bricks_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:purpur_block
stateschisel_typesmoothpillar_axisz version id  
blocknameminecraft:skull
statesfacing_directionno_drop_bit  version id  
blocknameminecraft:quartz_block
stateschisel_typechiseledpillar_axisx version id  
blocknameminecraft:element_46
states version id8 
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:stained_hardened_clay
statescolorpink version id  
blocknameminecraft:chain_command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3polished_dioritetop_slot_bit version id 
blocknameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction version id 
blockname
minecraft:bed
states	directionhead_piece_bit occupied_bit version id  
blocknameminecraft:wall_banner
statesfacing_direction
 version id  
blocknameminecraft:unlit_redstone_torch
statestorch_facing_directioneast version idK  
blocknameminecraft:detector_rail
states
rail_data_bit rail_direction version id  
blocknameminecraft:coral
statescoral_colorpinkdead_bit version id 
blocknameminecraft:bone_block
states
deprecatedpillar_axisx version id  
blocknameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit version id  
blocknameminecraft:red_flower
statesflower_type	houstonia version id&  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blocknameminecraft:nether_wart
statesage version ids  
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:obsidian
states version id1  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit version id 
blocknameminecraft:powered_repeater
states	directionrepeater_delay  version id^  
blocknameminecraft:stained_glass_pane
statescolorred version id  
blocknameminecraft:red_sandstone
statessand_stone_typesmooth version id  
blocknameminecraft:acacia_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:element_52
states version id> 
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:cactus
statesage  version idQ  
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:colored_torch_bp
states	color_bittorch_facing_directionunknown version id  
blocknameminecraft:concretePowder
statescolorwhite version id  
blocknameminecraft:stonebrick
statesstone_brick_typesmooth version idb  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:stonebrick
statesstone_brick_typemossy version idb  
blocknameminecraft:lit_blast_furnace
statesfacing_direction
 version id 
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:element_4
states version id 
blocknameminecraft:stone_slab
statesstone_slab_typesmooth_stonetop_slot_bit  version id,  
blockname minecraft:dark_prismarine_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:tripWire
statesattached_bitdisarmed_bitpowered_bit
suspended_bit  version id  
blocknameminecraft:nether_brick_stairs
statesupside_down_bitweirdo_direction version idr  
blocknameminecraft:chemistry_table
stateschemistry_table_type	lab_table	direction version id  
blockname!minecraft:repeating_command_block
statesconditional_bitfacing_direction  version id  
blocknameminecraft:concretePowder
statescolorcyan version id  
blocknameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level  version id 
blocknameminecraft:blast_furnace
statesfacing_direction version id 
blocknameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:concrete
statescolormagenta version id  
blocknameminecraft:stone_brick_stairs
statesupside_down_bit weirdo_direction version idm  
blocknameminecraft:torch
statestorch_facing_directionnorth version id2  
blockname!minecraft:hard_stained_glass_pane
statescolorblue version id  
blocknameminecraft:unpowered_comparator
states	direction output_lit_bit output_subtract_bit  version id  
blockname!minecraft:smooth_sandstone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:reeds
statesage version idS  
blocknameminecraft:wall_sign
statesfacing_direction version idD  
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit version idG  
blocknameminecraft:birch_door
states	direction door_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:colored_torch_rg
states	color_bit torch_facing_directionsouth version id  
blocknameminecraft:campfire
states	direction extinguished  version id 
blocknameminecraft:stone_stairs
statesupside_down_bit weirdo_direction version idC  
blocknameminecraft:dispenser
statesfacing_direction
triggered_bit  version id  
blockname"minecraft:stickyPistonArmCollision
statesfacing_direction  version id 
blocknameminecraft:dark_oak_stairs
statesupside_down_bitweirdo_direction  version id  
blocknameminecraft:double_stone_slab3
statesstone_slab_type_3smooth_red_sandstonetop_slot_bit version id 
blocknameminecraft:stone_slab
statesstone_slab_type	sandstonetop_slot_bit version id,  
blocknameminecraft:chain_command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:cobblestone_wall
stateswall_block_type	sandstone version id  
blocknameminecraft:barrel
statesfacing_directionopen_bit version id 
blocknameminecraft:birch_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:bee_nest
statesfacing_directionhoney_level
 version id 
blocknameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit version id  
blocknameminecraft:granite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:cauldron
statescauldron_liquidwater
fill_level version idv  
blocknameminecraft:red_sandstone_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:sticky_piston
statesfacing_direction version id  
blocknameminecraft:cauldron
statescauldron_liquidwater
fill_level  version idv  
blocknameminecraft:hay_block
states
deprecatedpillar_axisz version id  
blocknameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit  version id  
blocknameminecraft:red_sandstone_stairs
statesupside_down_bitweirdo_direction  version id  
blocknameminecraft:wool
statescolorcyan version id#  
blockname minecraft:lime_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id@  
blockname!minecraft:red_nether_brick_stairs
statesupside_down_bit weirdo_direction  version id 
blockname!minecraft:polished_diorite_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:bamboo
statesage_bit bamboo_leaf_size	no_leavesbamboo_stalk_thicknessthick version id 
blockname
minecraft:log
statesold_log_typejunglepillar_axisy version id  
blocknameminecraft:fire
statesage version id3  
blocknameminecraft:cobblestone_wall
stateswall_block_typestone_brick version id  
blocknameminecraft:frame
statesfacing_directionitem_frame_map_bit  version id  
blocknameminecraft:bee_nest
statesfacing_direction
honey_level version id 
blocknameminecraft:stone_slab
statesstone_slab_typecobblestonetop_slot_bit version id,  
blocknameminecraft:element_104
states version idr 
blocknameminecraft:cobblestone_wall
stateswall_block_typemossy_cobblestone version id  
blocknameminecraft:stripped_dark_oak_log
statespillar_axisy version id 
blocknameminecraft:granite_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:smooth_quartz_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:pistonArmCollision
statesfacing_direction version id"  
blocknameminecraft:sandstone
statessand_stone_typecut version id  
blocknameminecraft:lever
stateslever_directiondown_east_westopen_bit version idE  
blocknameminecraft:red_flower
statesflower_typepoppy version id&  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version idG  
blocknameminecraft:brick_stairs
statesupside_down_bitweirdo_direction version idl  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:stone_slab4
statesstone_slab_type_4
cut_sandstonetop_slot_bit version id 
blocknameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version idG  
blocknameminecraft:spruce_trapdoor
states	direction open_bit upside_down_bit  version id 
blocknameminecraft:shulker_box
statescolorpink version id  
blocknameminecraft:flowing_lava
statesliquid_depth
 version id
  
blocknameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit  version id  
blocknameminecraft:element_3
states version id
 
blocknameminecraft:lantern
stateshanging version id 
blockname"minecraft:purple_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:bone_block
states
deprecatedpillar_axisx version id  
blocknameminecraft:quartz_block
stateschisel_typedefaultpillar_axisy version id  
blockname#minecraft:magenta_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:kelp
stateskelp_age& version id 
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal
 version id  
blockname minecraft:pink_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:frame
statesfacing_directionitem_frame_map_bit version id  
blocknameminecraft:fence_gate
states	directionin_wall_bit open_bit  version idk  
blocknameminecraft:cocoa
statesage	direction  version id  
blocknameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:lit_smoker
statesfacing_direction version id 
blocknameminecraft:skull
statesfacing_directionno_drop_bit  version id  
blockname"minecraft:mossy_stone_brick_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit  version id  
blockname!minecraft:hard_stained_glass_pane
statescolorgray version id  
blocknameminecraft:hardened_clay
states version id  
blocknameminecraft:coral_fan
statescoral_colorpurplecoral_fan_direction version id 
blocknameminecraft:dropper
statesfacing_direction
triggered_bit version id}  
blocknameminecraft:element_97
states version idk 
blocknameminecraft:dark_oak_trapdoor
states	direction open_bit upside_down_bit version id 
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:wheat
statesgrowth version id;  
blocknameminecraft:chemistry_table
stateschemistry_table_typematerial_reducer	direction version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:ender_chest
statesfacing_direction  version id  
blocknameminecraft:coral
statescoral_coloryellowdead_bit version id 
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:birch_door
states	direction door_hinge_bit open_bit upper_block_bit version id  
blockname!minecraft:repeating_command_block
statesconditional_bit facing_direction version id  
blocknameminecraft:colored_torch_bp
states	color_bit torch_facing_directionsouth version id  
blocknameminecraft:pistonArmCollision
statesfacing_direction
 version id"  
blocknameminecraft:coral_fan_hang
statescoral_direction coral_hang_type_bitdead_bit version id 
blocknameminecraft:diorite_stairs
statesupside_down_bit weirdo_direction  version id 
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:carrots
statesgrowth version id  
blocknameminecraft:leaves
states
old_leaf_typebirchpersistent_bit
update_bit version id  
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:observer
statesfacing_directionpowered_bit  version id  
blocknameminecraft:birch_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit  version id 
blockname!minecraft:repeating_command_block
statesconditional_bit facing_direction version id  
blockname"minecraft:polished_andesite_stairs
statesupside_down_bitweirdo_direction version id 
blockname minecraft:dark_prismarine_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:spruce_standing_sign
statesground_sign_direction  version id 
blocknameminecraft:cactus
statesage version idQ  
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:coal_ore
states version id  
blocknameminecraft:jukebox
states version idT  
blocknameminecraft:kelp
stateskelp_age version id 
blocknameminecraft:spruce_door
states	direction door_hinge_bit open_bitupper_block_bit  version id  
blockname!minecraft:white_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:wooden_pressure_plate
statesredstone_signal version idH  
blockname$minecraft:daylight_detector_inverted
statesredstone_signal version id  
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:prismarine_stairs
statesupside_down_bitweirdo_direction  version id 
blocknameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit version id  
blocknameminecraft:stained_hardened_clay
statescolormagenta version id  
blocknameminecraft:rail
statesrail_direction  version idB  
blocknameminecraft:leaves
states
old_leaf_typesprucepersistent_bit 
update_bit  version id  
blocknameminecraft:hay_block
states
deprecated pillar_axisz version id  
blocknameminecraft:iron_door
states	direction door_hinge_bitopen_bitupper_block_bit version idG  
blockname!minecraft:green_glazed_terracotta
statesfacing_direction  version id  
blocknameminecraft:jungle_stairs
statesupside_down_bitweirdo_direction  version id  
blocknameminecraft:spruce_stairs
statesupside_down_bitweirdo_direction version id  
blocknameminecraft:chemistry_table
stateschemistry_table_typecompound_creator	direction version id  
blockname
minecraft:log
statesold_log_typesprucepillar_axisy version id  
blocknameminecraft:waterlily
states version ido  
blocknameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit  version id 
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:standing_sign
statesground_sign_direction version id?  
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:element_80
states version idZ 
blocknameminecraft:stone_slab
statesstone_slab_typequartztop_slot_bit version id,  
blockname!minecraft:green_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit version id  
blocknameminecraft:birch_stairs
statesupside_down_bit weirdo_direction version id  
blocknameminecraft:leaves2
states
new_leaf_typedark_oakpersistent_bit
update_bit version id  
blocknameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit version id  
blocknameminecraft:coral_block
statescoral_colorpinkdead_bit  version id 
blocknameminecraft:chemistry_table
stateschemistry_table_typeelement_constructor	direction version id  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_bricktop_slot_bit  version id  
blocknameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:sweet_berry_bush
statesgrowth  version id 
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version id  
blocknameminecraft:cobblestone_wall
stateswall_block_typegranite version id  
blocknameminecraft:jungle_door
states	direction door_hinge_bit open_bitupper_block_bit  version id  
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version id  
blocknameminecraft:beehive
statesfacing_directionhoney_level version id 
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blockname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id@  
blockname minecraft:cyan_glazed_terracotta
statesfacing_direction version id  
blocknameminecraft:activator_rail
states
rail_data_bit rail_direction  version id~  
blocknameminecraft:double_plant
statesdouble_plant_typefernupper_block_bit version id  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits
 version idd  
blocknameminecraft:dispenser
statesfacing_direction
triggered_bit  version id  
blockname
minecraft:web
states version id  
blocknameminecraft:fence
states	wood_typejungle version idU  
blocknameminecraft:stained_glass
statescolorlime version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:bell
states
attachmentmultiple	direction
toggle_bit version id 
blocknameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id@  
blocknameminecraft:stained_hardened_clay
statescolorlime version id  
blockname'minecraft:light_weighted_pressure_plate
statesredstone_signal version id  
blocknameminecraft:element_2
states version id 
blocknameminecraft:coral_fan
statescoral_colorpinkcoral_fan_direction version id 
blocknameminecraft:stone_slab2
statesstone_slab_type_2prismarine_roughtop_slot_bit  version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:purpur_block
stateschisel_typedefaultpillar_axisx version id  
blocknameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_darktop_slot_bit  version id  
blocknameminecraft:bee_nest
statesfacing_directionhoney_level version id 
blocknameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit  version id  
blocknameminecraft:acacia_pressure_plate
statesredstone_signal version id 
blocknameminecraft:stripped_jungle_log
statespillar_axisx version id 
blocknameminecraft:stained_glass_pane
statescolorgray version id  
blocknameminecraft:frosted_ice
statesage version id  
blockname!minecraft:hard_stained_glass_pane
statescolorwhite version id  
blocknameminecraft:water
statesliquid_depth version id	  
blocknameminecraft:wooden_button
statesbutton_pressed_bit facing_direction version id  
blocknameminecraft:spruce_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:hard_stained_glass
statescolororange version id  
blocknameminecraft:lava
statesliquid_depth version id  
blocknameminecraft:darkoak_standing_sign
statesground_sign_direction version id 
blocknameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction  version id 
blocknameminecraft:element_113
states version id{ 
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:rail
statesrail_direction version idB  
blocknameminecraft:daylight_detector
statesredstone_signal version id  
blocknameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit  version id  
blocknameminecraft:stone
states
stone_typeandesite_smooth version id  
blocknameminecraft:chest
statesfacing_direction  version id6  
blockname minecraft:lime_glazed_terracotta
statesfacing_direction version id  
blockname"minecraft:prismarine_bricks_stairs
statesupside_down_bitweirdo_direction version id 
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:loom
states	direction version id 
blocknameminecraft:activator_rail
states
rail_data_bit rail_direction version id~  
blocknameminecraft:hard_stained_glass
statescolorlime version id  
blocknameminecraft:fence_gate
states	directionin_wall_bitopen_bit version idk  
blocknameminecraft:jungle_wall_sign
statesfacing_direction version id 
blocknameminecraft:coral_fan_hang3
statescoral_direction coral_hang_type_bitdead_bit version id 
blocknameminecraft:wood
statespillar_axisystripped_bit	wood_typejungle version id 
blockname!minecraft:white_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:acacia_stairs
statesupside_down_bitweirdo_direction version id  
blockname!minecraft:dark_oak_pressure_plate
statesredstone_signal version id 
blocknameminecraft:colored_torch_rg
states	color_bit torch_facing_directionunknown version id  
blocknameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version idc  
blocknameminecraft:wood
statespillar_axisxstripped_bit	wood_typeacacia version id 
blocknameminecraft:jungle_pressure_plate
statesredstone_signal version id 
blocknameminecraft:acacia_door
states	direction door_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:chain_command_block
statesconditional_bit facing_direction  version id  
blocknameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit  version id 
blocknameminecraft:anvil
statesdamage	undamaged	direction version id  
blocknameminecraft:wood
statespillar_axiszstripped_bit 	wood_typedark_oak version id 
blocknameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit  version id 
blocknameminecraft:element_44
states version id6 
blocknameminecraft:spruce_button
statesbutton_pressed_bit facing_direction version id 
blocknameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version id  
blocknameminecraft:spruce_standing_sign
statesground_sign_direction version id 
blocknameminecraft:coral
statescoral_colorpurpledead_bit  version id 
blocknameminecraft:acacia_standing_sign
statesground_sign_direction version id 
blocknameminecraft:standing_banner
statesground_sign_direction version id  
blocknameminecraft:spruce_trapdoor
states	direction open_bitupside_down_bit  version id 
blocknameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit  version id  
blockname!minecraft:hard_stained_glass_pane
statescolorred version id  
blocknameminecraft:skull
statesfacing_directionno_drop_bit version id  
blocknameminecraft:beetroot
statesgrowth version id  
blocknameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit  version id  
blocknameminecraft:skull
statesfacing_directionno_drop_bit  version id  
blocknameminecraft:oak_stairs
statesupside_down_bit weirdo_direction  version id5  
blocknameminecraft:farmland
statesmoisturized_amount version id<  
blockname"minecraft:mossy_stone_brick_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:activator_rail
states
rail_data_bitrail_direction version id~  
blockname"minecraft:silver_glazed_terracotta
statesfacing_direction
 version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit version id  
blocknameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:vine
statesvine_direction_bits version idj  
blocknameminecraft:lit_redstone_lamp
states version id|  
blocknameminecraft:lever
stateslever_directiondown_east_westopen_bit  version idE  
blocknameminecraft:birch_standing_sign
statesground_sign_direction version id 
blocknameminecraft:jungle_door
states	direction door_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:birch_pressure_plate
statesredstone_signal version id 
blocknameminecraft:element_17
states version id 
blocknameminecraft:underwater_torch
statestorch_facing_directionsouth version id  
blocknameminecraft:birch_standing_sign
statesground_sign_direction  version id 
blocknameminecraft:lever
stateslever_directionnorthopen_bit  version idE  
blocknameminecraft:stripped_oak_log
statespillar_axisz version id	 
blocknameminecraft:pumpkin_stem
statesgrowth  version idh  
blocknameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit version id  
blocknameminecraft:monster_egg
statesmonster_egg_stone_typecobblestone version ida  
blocknameminecraft:double_stone_slab
statesstone_slab_typestone_bricktop_slot_bit version id+  
blocknameminecraft:stone_pressure_plate
statesredstone_signal version idF  
blocknameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version id  
blocknameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit  version id 
blocknameminecraft:farmland
statesmoisturized_amount version id<  
blocknameminecraft:element_98
states version idl 
blocknameminecraft:stone_slab2
statesstone_slab_type_2
red_sandstonetop_slot_bit version id  
blocknameminecraft:acacia_button
statesbutton_pressed_bit facing_direction
 version id 
blocknameminecraft:chain_command_block
statesconditional_bitfacing_direction version id  
blocknameminecraft:red_mushroom_block
stateshuge_mushroom_bits version idd  
blockname!minecraft:hard_stained_glass_pane
statescoloryellow version id  
blocknameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version id  
blocknameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction
 version id  
blocknameminecraft:scaffolding
states	stabilitystability_check  version id 
blocknameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit  version id  
blockname"minecraft:mossy_stone_brick_stairs
statesupside_down_bit weirdo_direction version id 
blocknameminecraft:grindstone
states
attachmentmultiple	direction version id 
blocknameminecraft:spruce_wall_sign
statesfacing_direction version id 
blocknameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction version id 
blocknameminecraft:torch
statestorch_facing_directiontop version id2  
blocknameminecraft:beehive
statesfacing_direction
honey_level version id 
blocknameminecraft:cobblestone_wall
stateswall_block_type
prismarine version id  
blocknameminecraft:jungle_trapdoor
states	direction open_bitupside_down_bit version id 
blocknameminecraft:stone_slab3
statesstone_slab_type_3granitetop_slot_bit  version id 
blocknameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level
 version id 
blocknameminecraft:double_stone_slab
statesstone_slab_typenether_bricktop_slot_bit  version id+  {"minecraft:air":0,"minecraft:stone":1,"minecraft:grass":2,"minecraft:dirt":3,"minecraft:cobblestone":4,"minecraft:planks":5,"minecraft:sapling":6,"minecraft:bedrock":7,"minecraft:flowing_water":8,"minecraft:water":9,"minecraft:flowing_lava":10,"minecraft:lava":11,"minecraft:sand":12,"minecraft:gravel":13,"minecraft:gold_ore":14,"minecraft:iron_ore":15,"minecraft:coal_ore":16,"minecraft:log":17,"minecraft:leaves":18,"minecraft:sponge":19,"minecraft:glass":20,"minecraft:lapis_ore":21,"minecraft:lapis_block":22,"minecraft:dispenser":23,"minecraft:sandstone":24,"minecraft:noteblock":25,"minecraft:bed":26,"minecraft:golden_rail":27,"minecraft:detector_rail":28,"minecraft:sticky_piston":29,"minecraft:web":30,"minecraft:tallgrass":31,"minecraft:deadbush":32,"minecraft:piston":33,"minecraft:pistonArmCollision":34,"minecraft:wool":35,"minecraft:element_0":36,"minecraft:yellow_flower":37,"minecraft:red_flower":38,"minecraft:brown_mushroom":39,"minecraft:red_mushroom":40,"minecraft:gold_block":41,"minecraft:iron_block":42,"minecraft:double_stone_slab":43,"minecraft:stone_slab":44,"minecraft:brick_block":45,"minecraft:tnt":46,"minecraft:bookshelf":47,"minecraft:mossy_cobblestone":48,"minecraft:obsidian":49,"minecraft:torch":50,"minecraft:fire":51,"minecraft:mob_spawner":52,"minecraft:oak_stairs":53,"minecraft:chest":54,"minecraft:redstone_wire":55,"minecraft:diamond_ore":56,"minecraft:diamond_block":57,"minecraft:crafting_table":58,"minecraft:wheat":59,"minecraft:farmland":60,"minecraft:furnace":61,"minecraft:lit_furnace":62,"minecraft:standing_sign":63,"minecraft:wooden_door":64,"minecraft:ladder":65,"minecraft:rail":66,"minecraft:stone_stairs":67,"minecraft:wall_sign":68,"minecraft:lever":69,"minecraft:stone_pressure_plate":70,"minecraft:iron_door":71,"minecraft:wooden_pressure_plate":72,"minecraft:redstone_ore":73,"minecraft:lit_redstone_ore":74,"minecraft:unlit_redstone_torch":75,"minecraft:redstone_torch":76,"minecraft:stone_button":77,"minecraft:snow_layer":78,"minecraft:ice":79,"minecraft:snow":80,"minecraft:cactus":81,"minecraft:clay":82,"minecraft:reeds":83,"minecraft:jukebox":84,"minecraft:fence":85,"minecraft:pumpkin":86,"minecraft:netherrack":87,"minecraft:soul_sand":88,"minecraft:glowstone":89,"minecraft:portal":90,"minecraft:lit_pumpkin":91,"minecraft:cake":92,"minecraft:unpowered_repeater":93,"minecraft:powered_repeater":94,"minecraft:invisibleBedrock":95,"minecraft:trapdoor":96,"minecraft:monster_egg":97,"minecraft:stonebrick":98,"minecraft:brown_mushroom_block":99,"minecraft:red_mushroom_block":100,"minecraft:iron_bars":101,"minecraft:glass_pane":102,"minecraft:melon_block":103,"minecraft:pumpkin_stem":104,"minecraft:melon_stem":105,"minecraft:vine":106,"minecraft:fence_gate":107,"minecraft:brick_stairs":108,"minecraft:stone_brick_stairs":109,"minecraft:mycelium":110,"minecraft:waterlily":111,"minecraft:nether_brick":112,"minecraft:nether_brick_fence":113,"minecraft:nether_brick_stairs":114,"minecraft:nether_wart":115,"minecraft:enchanting_table":116,"minecraft:brewing_stand":117,"minecraft:cauldron":118,"minecraft:end_portal":119,"minecraft:end_portal_frame":120,"minecraft:end_stone":121,"minecraft:dragon_egg":122,"minecraft:redstone_lamp":123,"minecraft:lit_redstone_lamp":124,"minecraft:dropper":125,"minecraft:activator_rail":126,"minecraft:cocoa":127,"minecraft:sandstone_stairs":128,"minecraft:emerald_ore":129,"minecraft:ender_chest":130,"minecraft:tripwire_hook":131,"minecraft:tripWire":132,"minecraft:emerald_block":133,"minecraft:spruce_stairs":134,"minecraft:birch_stairs":135,"minecraft:jungle_stairs":136,"minecraft:command_block":137,"minecraft:beacon":138,"minecraft:cobblestone_wall":139,"minecraft:flower_pot":140,"minecraft:carrots":141,"minecraft:potatoes":142,"minecraft:wooden_button":143,"minecraft:skull":144,"minecraft:anvil":145,"minecraft:trapped_chest":146,"minecraft:light_weighted_pressure_plate":147,"minecraft:heavy_weighted_pressure_plate":148,"minecraft:unpowered_comparator":149,"minecraft:powered_comparator":150,"minecraft:daylight_detector":151,"minecraft:redstone_block":152,"minecraft:quartz_ore":153,"minecraft:hopper":154,"minecraft:quartz_block":155,"minecraft:quartz_stairs":156,"minecraft:double_wooden_slab":157,"minecraft:wooden_slab":158,"minecraft:stained_hardened_clay":159,"minecraft:stained_glass_pane":160,"minecraft:leaves2":161,"minecraft:log2":162,"minecraft:acacia_stairs":163,"minecraft:dark_oak_stairs":164,"minecraft:slime":165,"minecraft:iron_trapdoor":167,"minecraft:prismarine":168,"minecraft:seaLantern":169,"minecraft:hay_block":170,"minecraft:carpet":171,"minecraft:hardened_clay":172,"minecraft:coal_block":173,"minecraft:packed_ice":174,"minecraft:double_plant":175,"minecraft:standing_banner":176,"minecraft:wall_banner":177,"minecraft:daylight_detector_inverted":178,"minecraft:red_sandstone":179,"minecraft:red_sandstone_stairs":180,"minecraft:double_stone_slab2":181,"minecraft:stone_slab2":182,"minecraft:spruce_fence_gate":183,"minecraft:birch_fence_gate":184,"minecraft:jungle_fence_gate":185,"minecraft:dark_oak_fence_gate":186,"minecraft:acacia_fence_gate":187,"minecraft:repeating_command_block":188,"minecraft:chain_command_block":189,"minecraft:hard_glass_pane":190,"minecraft:hard_stained_glass_pane":191,"minecraft:chemical_heat":192,"minecraft:spruce_door":193,"minecraft:birch_door":194,"minecraft:jungle_door":195,"minecraft:acacia_door":196,"minecraft:dark_oak_door":197,"minecraft:grass_path":198,"minecraft:frame":199,"minecraft:chorus_flower":200,"minecraft:purpur_block":201,"minecraft:colored_torch_rg":202,"minecraft:purpur_stairs":203,"minecraft:colored_torch_bp":204,"minecraft:undyed_shulker_box":205,"minecraft:end_bricks":206,"minecraft:frosted_ice":207,"minecraft:end_rod":208,"minecraft:end_gateway":209,"minecraft:magma":213,"minecraft:nether_wart_block":214,"minecraft:red_nether_brick":215,"minecraft:bone_block":216,"minecraft:structure_void":217,"minecraft:shulker_box":218,"minecraft:purple_glazed_terracotta":219,"minecraft:white_glazed_terracotta":220,"minecraft:orange_glazed_terracotta":221,"minecraft:magenta_glazed_terracotta":222,"minecraft:light_blue_glazed_terracotta":223,"minecraft:yellow_glazed_terracotta":224,"minecraft:lime_glazed_terracotta":225,"minecraft:pink_glazed_terracotta":226,"minecraft:gray_glazed_terracotta":227,"minecraft:silver_glazed_terracotta":228,"minecraft:cyan_glazed_terracotta":229,"minecraft:blue_glazed_terracotta":231,"minecraft:brown_glazed_terracotta":232,"minecraft:green_glazed_terracotta":233,"minecraft:red_glazed_terracotta":234,"minecraft:black_glazed_terracotta":235,"minecraft:concrete":236,"minecraft:concretePowder":237,"minecraft:chemistry_table":238,"minecraft:underwater_torch":239,"minecraft:chorus_plant":240,"minecraft:stained_glass":241,"minecraft:camera":242,"minecraft:podzol":243,"minecraft:beetroot":244,"minecraft:stonecutter":245,"minecraft:glowingobsidian":246,"minecraft:netherreactor":247,"minecraft:info_update":248,"minecraft:info_update2":249,"minecraft:movingBlock":250,"minecraft:observer":251,"minecraft:structure_block":252,"minecraft:hard_glass":253,"minecraft:hard_stained_glass":254,"minecraft:reserved6":255,"minecraft:prismarine_stairs":257,"minecraft:dark_prismarine_stairs":258,"minecraft:prismarine_bricks_stairs":259,"minecraft:stripped_spruce_log":260,"minecraft:stripped_birch_log":261,"minecraft:stripped_jungle_log":262,"minecraft:stripped_acacia_log":263,"minecraft:stripped_dark_oak_log":264,"minecraft:stripped_oak_log":265,"minecraft:blue_ice":266,"minecraft:element_1":267,"minecraft:element_2":268,"minecraft:element_3":269,"minecraft:element_4":270,"minecraft:element_5":271,"minecraft:element_6":272,"minecraft:element_7":273,"minecraft:element_8":274,"minecraft:element_9":275,"minecraft:element_10":276,"minecraft:element_11":277,"minecraft:element_12":278,"minecraft:element_13":279,"minecraft:element_14":280,"minecraft:element_15":281,"minecraft:element_16":282,"minecraft:element_17":283,"minecraft:element_18":284,"minecraft:element_19":285,"minecraft:element_20":286,"minecraft:element_21":287,"minecraft:element_22":288,"minecraft:element_23":289,"minecraft:element_24":290,"minecraft:element_25":291,"minecraft:element_26":292,"minecraft:element_27":293,"minecraft:element_28":294,"minecraft:element_29":295,"minecraft:element_30":296,"minecraft:element_31":297,"minecraft:element_32":298,"minecraft:element_33":299,"minecraft:element_34":300,"minecraft:element_35":301,"minecraft:element_36":302,"minecraft:element_37":303,"minecraft:element_38":304,"minecraft:element_39":305,"minecraft:element_40":306,"minecraft:element_41":307,"minecraft:element_42":308,"minecraft:element_43":309,"minecraft:element_44":310,"minecraft:element_45":311,"minecraft:element_46":312,"minecraft:element_47":313,"minecraft:element_48":314,"minecraft:element_49":315,"minecraft:element_50":316,"minecraft:element_51":317,"minecraft:element_52":318,"minecraft:element_53":319,"minecraft:element_54":320,"minecraft:element_55":321,"minecraft:element_56":322,"minecraft:element_57":323,"minecraft:element_58":324,"minecraft:element_59":325,"minecraft:element_60":326,"minecraft:element_61":327,"minecraft:element_62":328,"minecraft:element_63":329,"minecraft:element_64":330,"minecraft:element_65":331,"minecraft:element_66":332,"minecraft:element_67":333,"minecraft:element_68":334,"minecraft:element_69":335,"minecraft:element_70":336,"minecraft:element_71":337,"minecraft:element_72":338,"minecraft:element_73":339,"minecraft:element_74":340,"minecraft:element_75":341,"minecraft:element_76":342,"minecraft:element_77":343,"minecraft:element_78":344,"minecraft:element_79":345,"minecraft:element_80":346,"minecraft:element_81":347,"minecraft:element_82":348,"minecraft:element_83":349,"minecraft:element_84":350,"minecraft:element_85":351,"minecraft:element_86":352,"minecraft:element_87":353,"minecraft:element_88":354,"minecraft:element_89":355,"minecraft:element_90":356,"minecraft:element_91":357,"minecraft:element_92":358,"minecraft:element_93":359,"minecraft:element_94":360,"minecraft:element_95":361,"minecraft:element_96":362,"minecraft:element_97":363,"minecraft:element_98":364,"minecraft:element_99":365,"minecraft:element_100":366,"minecraft:element_101":367,"minecraft:element_102":368,"minecraft:element_103":369,"minecraft:element_104":370,"minecraft:element_105":371,"minecraft:element_106":372,"minecraft:element_107":373,"minecraft:element_108":374,"minecraft:element_109":375,"minecraft:element_110":376,"minecraft:element_111":377,"minecraft:element_112":378,"minecraft:element_113":379,"minecraft:element_114":380,"minecraft:element_115":381,"minecraft:element_116":382,"minecraft:element_117":383,"minecraft:element_118":384,"minecraft:seagrass":385,"minecraft:coral":386,"minecraft:coral_block":387,"minecraft:coral_fan":388,"minecraft:coral_fan_dead":389,"minecraft:coral_fan_hang":390,"minecraft:coral_fan_hang2":391,"minecraft:coral_fan_hang3":392,"minecraft:kelp":393,"minecraft:dried_kelp_block":394,"minecraft:acacia_button":395,"minecraft:birch_button":396,"minecraft:dark_oak_button":397,"minecraft:jungle_button":398,"minecraft:spruce_button":399,"minecraft:acacia_trapdoor":400,"minecraft:birch_trapdoor":401,"minecraft:dark_oak_trapdoor":402,"minecraft:jungle_trapdoor":403,"minecraft:spruce_trapdoor":404,"minecraft:acacia_pressure_plate":405,"minecraft:birch_pressure_plate":406,"minecraft:dark_oak_pressure_plate":407,"minecraft:jungle_pressure_plate":408,"minecraft:spruce_pressure_plate":409,"minecraft:carved_pumpkin":410,"minecraft:sea_pickle":411,"minecraft:conduit":412,"minecraft:turtle_egg":414,"minecraft:bubble_column":415,"minecraft:barrier":416,"minecraft:stone_slab3":417,"minecraft:bamboo":418,"minecraft:bamboo_sapling":419,"minecraft:scaffolding":420,"minecraft:stone_slab4":421,"minecraft:double_stone_slab3":422,"minecraft:double_stone_slab4":423,"minecraft:granite_stairs":424,"minecraft:diorite_stairs":425,"minecraft:andesite_stairs":426,"minecraft:polished_granite_stairs":427,"minecraft:polished_diorite_stairs":428,"minecraft:polished_andesite_stairs":429,"minecraft:mossy_stone_brick_stairs":430,"minecraft:smooth_red_sandstone_stairs":431,"minecraft:smooth_sandstone_stairs":432,"minecraft:end_brick_stairs":433,"minecraft:mossy_cobblestone_stairs":434,"minecraft:normal_stone_stairs":435,"minecraft:spruce_standing_sign":436,"minecraft:spruce_wall_sign":437,"minecraft:smooth_stone":438,"minecraft:red_nether_brick_stairs":439,"minecraft:smooth_quartz_stairs":440,"minecraft:birch_standing_sign":441,"minecraft:birch_wall_sign":442,"minecraft:jungle_standing_sign":443,"minecraft:jungle_wall_sign":444,"minecraft:acacia_standing_sign":445,"minecraft:acacia_wall_sign":446,"minecraft:darkoak_standing_sign":447,"minecraft:darkoak_wall_sign":448,"minecraft:lectern":449,"minecraft:grindstone":450,"minecraft:blast_furnace":451,"minecraft:stonecutter_block":452,"minecraft:smoker":453,"minecraft:lit_smoker":454,"minecraft:cartography_table":455,"minecraft:fletching_table":456,"minecraft:smithing_table":457,"minecraft:barrel":458,"minecraft:loom":459,"minecraft:bell":461,"minecraft:sweet_berry_bush":462,"minecraft:lantern":463,"minecraft:campfire":464,"minecraft:lava_cauldron":465,"minecraft:jigsaw":466,"minecraft:wood":467,"minecraft:composter":468,"minecraft:lit_blast_furnace":469,"minecraft:light_block":470,"minecraft:wither_rose":471,"minecraft:stickyPistonArmCollision":472,"minecraft:bee_nest":473,"minecraft:beehive":474,"minecraft:honey_block":475,"minecraft:honeycomb_block":476}	 
3
oldnameminecraft:acacia_buttonval   
newnameminecraft:acacia_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bit facing_direction
 version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:acacia_buttonval	  
newnameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:acacia_buttonval
  
newnameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:acacia_buttonval
  
newnameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction
 version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:acacia_buttonval  
newnameminecraft:acacia_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:acacia_doorval   
newnameminecraft:acacia_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:acacia_doorval	  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:acacia_doorval
  
newnameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:acacia_doorval
  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:acacia_doorval  
newnameminecraft:acacia_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:acacia_fence_gateval   
newnameminecraft:acacia_fence_gate
states	direction in_wall_bit open_bit  version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	direction in_wall_bit open_bit version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	direction in_wall_bitopen_bit  version  
oldnameminecraft:acacia_fence_gateval	  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:acacia_fence_gateval
  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	direction in_wall_bitopen_bit version  
oldnameminecraft:acacia_fence_gateval
  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:acacia_fence_gateval  
newnameminecraft:acacia_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:acacia_pressure_plateval   
newnameminecraft:acacia_pressure_plate
statesredstone_signal  version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal
 version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval	  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval
  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval
  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_pressure_plateval  
newnameminecraft:acacia_pressure_plate
statesredstone_signal version  
oldnameminecraft:acacia_stairsval   
newnameminecraft:acacia_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:acacia_stairsval  
newnameminecraft:acacia_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:acacia_stairsval  
newnameminecraft:acacia_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:acacia_stairsval  
newnameminecraft:acacia_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:acacia_stairsval  
newnameminecraft:acacia_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:acacia_stairsval  
newnameminecraft:acacia_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:acacia_stairsval  
newnameminecraft:acacia_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:acacia_stairsval  
newnameminecraft:acacia_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:acacia_standing_signval   
newnameminecraft:acacia_standing_sign
statesground_sign_direction  version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction
 version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval	  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval
  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval
  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_standing_signval  
newnameminecraft:acacia_standing_sign
statesground_sign_direction version  
oldnameminecraft:acacia_trapdoorval   
newnameminecraft:acacia_trapdoor
states	direction open_bit upside_down_bit  version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	direction open_bit upside_down_bit version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	direction open_bitupside_down_bit  version  
oldnameminecraft:acacia_trapdoorval	  
newnameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:acacia_trapdoorval
  
newnameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	direction open_bitupside_down_bit version  
oldnameminecraft:acacia_trapdoorval
  
newnameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:acacia_trapdoorval  
newnameminecraft:acacia_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:acacia_wall_signval   
newnameminecraft:acacia_wall_sign
statesfacing_direction  version  
oldnameminecraft:acacia_wall_signval  
newnameminecraft:acacia_wall_sign
statesfacing_direction version  
oldnameminecraft:acacia_wall_signval  
newnameminecraft:acacia_wall_sign
statesfacing_direction version  
oldnameminecraft:acacia_wall_signval  
newnameminecraft:acacia_wall_sign
statesfacing_direction version  
oldnameminecraft:acacia_wall_signval  
newnameminecraft:acacia_wall_sign
statesfacing_direction version  
oldnameminecraft:acacia_wall_signval  
newnameminecraft:acacia_wall_sign
statesfacing_direction
 version  
oldnameminecraft:acacia_wall_signval  
newnameminecraft:acacia_wall_sign
statesfacing_direction  version  
oldnameminecraft:acacia_wall_signval  
newnameminecraft:acacia_wall_sign
statesfacing_direction  version  
oldnameminecraft:activator_railval   
newnameminecraft:activator_rail
states
rail_data_bit rail_direction  version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bit rail_direction
 version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bit rail_direction  version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bit rail_direction  version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bitrail_direction  version  
oldnameminecraft:activator_railval	  
newnameminecraft:activator_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:activator_railval
  
newnameminecraft:activator_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:activator_railval
  
newnameminecraft:activator_rail
states
rail_data_bitrail_direction
 version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bitrail_direction  version  
oldnameminecraft:activator_railval  
newnameminecraft:activator_rail
states
rail_data_bitrail_direction  version  
oldname
minecraft:airval   
newname
minecraft:air
states version  
oldnameminecraft:andesite_stairsval   
newnameminecraft:andesite_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:andesite_stairsval  
newnameminecraft:andesite_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:andesite_stairsval  
newnameminecraft:andesite_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:andesite_stairsval  
newnameminecraft:andesite_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:andesite_stairsval  
newnameminecraft:andesite_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:andesite_stairsval  
newnameminecraft:andesite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:andesite_stairsval  
newnameminecraft:andesite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:andesite_stairsval  
newnameminecraft:andesite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:anvilval   
newnameminecraft:anvil
statesdamage	undamaged	direction  version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamage	undamaged	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamage	undamaged	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamage	undamaged	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamageslightly_damaged	direction  version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamageslightly_damaged	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamageslightly_damaged	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamageslightly_damaged	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamagevery_damaged	direction  version  
oldnameminecraft:anvilval	  
newnameminecraft:anvil
statesdamagevery_damaged	direction version  
oldnameminecraft:anvilval
  
newnameminecraft:anvil
statesdamagevery_damaged	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamagevery_damaged	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamagebroken	direction  version  
oldnameminecraft:anvilval
  
newnameminecraft:anvil
statesdamagebroken	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamagebroken	direction version  
oldnameminecraft:anvilval  
newnameminecraft:anvil
statesdamagebroken	direction version  
oldnameminecraft:bambooval   
newnameminecraft:bamboo
statesage_bit bamboo_leaf_size	no_leavesbamboo_stalk_thicknessthin version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bit bamboo_leaf_size	no_leavesbamboo_stalk_thicknessthick version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bit bamboo_leaf_sizesmall_leavesbamboo_stalk_thicknessthin version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bit bamboo_leaf_sizesmall_leavesbamboo_stalk_thicknessthick version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bit bamboo_leaf_sizelarge_leavesbamboo_stalk_thicknessthin version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bit bamboo_leaf_sizelarge_leavesbamboo_stalk_thicknessthick version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bit bamboo_leaf_size	no_leavesbamboo_stalk_thicknessthin version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bit bamboo_leaf_size	no_leavesbamboo_stalk_thicknessthick version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bitbamboo_leaf_size	no_leavesbamboo_stalk_thicknessthin version  
oldnameminecraft:bambooval	  
newnameminecraft:bamboo
statesage_bitbamboo_leaf_size	no_leavesbamboo_stalk_thicknessthick version  
oldnameminecraft:bambooval
  
newnameminecraft:bamboo
statesage_bitbamboo_leaf_sizesmall_leavesbamboo_stalk_thicknessthin version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bitbamboo_leaf_sizesmall_leavesbamboo_stalk_thicknessthick version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bitbamboo_leaf_sizelarge_leavesbamboo_stalk_thicknessthin version  
oldnameminecraft:bambooval
  
newnameminecraft:bamboo
statesage_bitbamboo_leaf_sizelarge_leavesbamboo_stalk_thicknessthick version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bitbamboo_leaf_size	no_leavesbamboo_stalk_thicknessthin version  
oldnameminecraft:bambooval  
newnameminecraft:bamboo
statesage_bitbamboo_leaf_size	no_leavesbamboo_stalk_thicknessthick version  
oldnameminecraft:bamboo_saplingval   
newnameminecraft:bamboo_sapling
statesage_bit sapling_typeoak version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bitsapling_typeoak version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bit sapling_typespruce version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bitsapling_typespruce version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bit sapling_typebirch version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bitsapling_typebirch version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bit sapling_typejungle version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bitsapling_typejungle version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bit sapling_typeacacia version  
oldnameminecraft:bamboo_saplingval	  
newnameminecraft:bamboo_sapling
statesage_bitsapling_typeacacia version  
oldnameminecraft:bamboo_saplingval
  
newnameminecraft:bamboo_sapling
statesage_bit sapling_typedark_oak version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bitsapling_typedark_oak version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bit sapling_typeoak version  
oldnameminecraft:bamboo_saplingval
  
newnameminecraft:bamboo_sapling
statesage_bitsapling_typeoak version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bit sapling_typeoak version  
oldnameminecraft:bamboo_saplingval  
newnameminecraft:bamboo_sapling
statesage_bitsapling_typeoak version  
oldnameminecraft:barrelval   
newnameminecraft:barrel
statesfacing_direction open_bit  version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_directionopen_bit  version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_directionopen_bit  version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_directionopen_bit  version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_directionopen_bit  version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_direction
open_bit  version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_direction open_bit  version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_direction open_bit  version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_direction open_bit version  
oldnameminecraft:barrelval	  
newnameminecraft:barrel
statesfacing_directionopen_bit version  
oldnameminecraft:barrelval
  
newnameminecraft:barrel
statesfacing_directionopen_bit version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_directionopen_bit version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_directionopen_bit version  
oldnameminecraft:barrelval
  
newnameminecraft:barrel
statesfacing_direction
open_bit version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_direction open_bit version  
oldnameminecraft:barrelval  
newnameminecraft:barrel
statesfacing_direction open_bit version  
oldnameminecraft:barrierval   
newnameminecraft:barrier
states version  
oldnameminecraft:beaconval   
newnameminecraft:beacon
states version  
oldname
minecraft:bedval   
newname
minecraft:bed
states	direction head_piece_bit occupied_bit  version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	directionhead_piece_bit occupied_bit  version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	directionhead_piece_bit occupied_bit  version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	directionhead_piece_bit occupied_bit  version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	direction head_piece_bit occupied_bit version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	directionhead_piece_bit occupied_bit version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	directionhead_piece_bit occupied_bit version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	directionhead_piece_bit occupied_bit version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	direction head_piece_bitoccupied_bit  version  
oldname
minecraft:bedval	  
newname
minecraft:bed
states	directionhead_piece_bitoccupied_bit  version  
oldname
minecraft:bedval
  
newname
minecraft:bed
states	directionhead_piece_bitoccupied_bit  version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	directionhead_piece_bitoccupied_bit  version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	direction head_piece_bitoccupied_bit version  
oldname
minecraft:bedval
  
newname
minecraft:bed
states	directionhead_piece_bitoccupied_bit version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	directionhead_piece_bitoccupied_bit version  
oldname
minecraft:bedval  
newname
minecraft:bed
states	directionhead_piece_bitoccupied_bit version  
oldnameminecraft:bedrockval   
newnameminecraft:bedrock
statesinfiniburn_bit  version  
oldnameminecraft:bedrockval  
newnameminecraft:bedrock
statesinfiniburn_bit version  
oldnameminecraft:beetrootval   
newnameminecraft:beetroot
statesgrowth  version  
oldnameminecraft:beetrootval  
newnameminecraft:beetroot
statesgrowth version  
oldnameminecraft:beetrootval  
newnameminecraft:beetroot
statesgrowth version  
oldnameminecraft:beetrootval  
newnameminecraft:beetroot
statesgrowth version  
oldnameminecraft:beetrootval  
newnameminecraft:beetroot
statesgrowth version  
oldnameminecraft:beetrootval  
newnameminecraft:beetroot
statesgrowth
 version  
oldnameminecraft:beetrootval  
newnameminecraft:beetroot
statesgrowth version  
oldnameminecraft:beetrootval  
newnameminecraft:beetroot
statesgrowth version  
oldnameminecraft:bellval   
newnameminecraft:bell
states
attachmentstanding	direction 
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentstanding	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentstanding	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentstanding	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmenthanging	direction 
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmenthanging	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmenthanging	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmenthanging	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentside	direction 
toggle_bit  version  
oldnameminecraft:bellval	  
newnameminecraft:bell
states
attachmentside	direction
toggle_bit  version  
oldnameminecraft:bellval
  
newnameminecraft:bell
states
attachmentside	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentside	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentmultiple	direction 
toggle_bit  version  
oldnameminecraft:bellval
  
newnameminecraft:bell
states
attachmentmultiple	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentmultiple	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentmultiple	direction
toggle_bit  version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentstanding	direction 
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentstanding	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentstanding	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentstanding	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmenthanging	direction 
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmenthanging	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmenthanging	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmenthanging	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentside	direction 
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentside	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentside	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentside	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentmultiple	direction 
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentmultiple	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentmultiple	direction
toggle_bit version  
oldnameminecraft:bellval  
newnameminecraft:bell
states
attachmentmultiple	direction
toggle_bit version  
oldnameminecraft:birch_buttonval   
newnameminecraft:birch_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bit facing_direction
 version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:birch_buttonval	  
newnameminecraft:birch_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:birch_buttonval
  
newnameminecraft:birch_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:birch_buttonval
  
newnameminecraft:birch_button
statesbutton_pressed_bitfacing_direction
 version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:birch_buttonval  
newnameminecraft:birch_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:birch_doorval   
newnameminecraft:birch_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:birch_doorval	  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:birch_doorval
  
newnameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:birch_doorval
  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:birch_doorval  
newnameminecraft:birch_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:birch_fence_gateval   
newnameminecraft:birch_fence_gate
states	direction in_wall_bit open_bit  version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	direction in_wall_bit open_bit version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	direction in_wall_bitopen_bit  version  
oldnameminecraft:birch_fence_gateval	  
newnameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:birch_fence_gateval
  
newnameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	direction in_wall_bitopen_bit version  
oldnameminecraft:birch_fence_gateval
  
newnameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:birch_fence_gateval  
newnameminecraft:birch_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:birch_pressure_plateval   
newnameminecraft:birch_pressure_plate
statesredstone_signal  version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal
 version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval	  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval
  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval
  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_pressure_plateval  
newnameminecraft:birch_pressure_plate
statesredstone_signal version  
oldnameminecraft:birch_stairsval   
newnameminecraft:birch_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:birch_stairsval  
newnameminecraft:birch_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:birch_stairsval  
newnameminecraft:birch_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:birch_stairsval  
newnameminecraft:birch_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:birch_stairsval  
newnameminecraft:birch_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:birch_stairsval  
newnameminecraft:birch_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:birch_stairsval  
newnameminecraft:birch_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:birch_stairsval  
newnameminecraft:birch_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:birch_standing_signval   
newnameminecraft:birch_standing_sign
statesground_sign_direction  version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction
 version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval	  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval
  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval
  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_standing_signval  
newnameminecraft:birch_standing_sign
statesground_sign_direction version  
oldnameminecraft:birch_trapdoorval   
newnameminecraft:birch_trapdoor
states	direction open_bit upside_down_bit  version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	direction open_bit upside_down_bit version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	direction open_bitupside_down_bit  version  
oldnameminecraft:birch_trapdoorval	  
newnameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:birch_trapdoorval
  
newnameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	direction open_bitupside_down_bit version  
oldnameminecraft:birch_trapdoorval
  
newnameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:birch_trapdoorval  
newnameminecraft:birch_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:birch_wall_signval   
newnameminecraft:birch_wall_sign
statesfacing_direction  version  
oldnameminecraft:birch_wall_signval  
newnameminecraft:birch_wall_sign
statesfacing_direction version  
oldnameminecraft:birch_wall_signval  
newnameminecraft:birch_wall_sign
statesfacing_direction version  
oldnameminecraft:birch_wall_signval  
newnameminecraft:birch_wall_sign
statesfacing_direction version  
oldnameminecraft:birch_wall_signval  
newnameminecraft:birch_wall_sign
statesfacing_direction version  
oldnameminecraft:birch_wall_signval  
newnameminecraft:birch_wall_sign
statesfacing_direction
 version  
oldnameminecraft:birch_wall_signval  
newnameminecraft:birch_wall_sign
statesfacing_direction  version  
oldnameminecraft:birch_wall_signval  
newnameminecraft:birch_wall_sign
statesfacing_direction  version  
oldname!minecraft:black_glazed_terracottaval   
newname!minecraft:black_glazed_terracotta
statesfacing_direction  version  
oldname!minecraft:black_glazed_terracottaval  
newname!minecraft:black_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:black_glazed_terracottaval  
newname!minecraft:black_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:black_glazed_terracottaval  
newname!minecraft:black_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:black_glazed_terracottaval  
newname!minecraft:black_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:black_glazed_terracottaval  
newname!minecraft:black_glazed_terracotta
statesfacing_direction
 version  
oldname!minecraft:black_glazed_terracottaval  
newname!minecraft:black_glazed_terracotta
statesfacing_direction  version  
oldname!minecraft:black_glazed_terracottaval  
newname!minecraft:black_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:blast_furnaceval   
newnameminecraft:blast_furnace
statesfacing_direction  version  
oldnameminecraft:blast_furnaceval  
newnameminecraft:blast_furnace
statesfacing_direction version  
oldnameminecraft:blast_furnaceval  
newnameminecraft:blast_furnace
statesfacing_direction version  
oldnameminecraft:blast_furnaceval  
newnameminecraft:blast_furnace
statesfacing_direction version  
oldnameminecraft:blast_furnaceval  
newnameminecraft:blast_furnace
statesfacing_direction version  
oldnameminecraft:blast_furnaceval  
newnameminecraft:blast_furnace
statesfacing_direction
 version  
oldnameminecraft:blast_furnaceval  
newnameminecraft:blast_furnace
statesfacing_direction  version  
oldnameminecraft:blast_furnaceval  
newnameminecraft:blast_furnace
statesfacing_direction  version  
oldname minecraft:blue_glazed_terracottaval   
newname minecraft:blue_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:blue_glazed_terracottaval  
newname minecraft:blue_glazed_terracotta
statesfacing_direction version  
oldname minecraft:blue_glazed_terracottaval  
newname minecraft:blue_glazed_terracotta
statesfacing_direction version  
oldname minecraft:blue_glazed_terracottaval  
newname minecraft:blue_glazed_terracotta
statesfacing_direction version  
oldname minecraft:blue_glazed_terracottaval  
newname minecraft:blue_glazed_terracotta
statesfacing_direction version  
oldname minecraft:blue_glazed_terracottaval  
newname minecraft:blue_glazed_terracotta
statesfacing_direction
 version  
oldname minecraft:blue_glazed_terracottaval  
newname minecraft:blue_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:blue_glazed_terracottaval  
newname minecraft:blue_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:blue_iceval   
newnameminecraft:blue_ice
states version  
oldnameminecraft:bone_blockval   
newnameminecraft:bone_block
states
deprecated pillar_axisy version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecatedpillar_axisy version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecatedpillar_axisy version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecatedpillar_axisy version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecated pillar_axisx version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecatedpillar_axisx version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecatedpillar_axisx version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecatedpillar_axisx version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecated pillar_axisz version  
oldnameminecraft:bone_blockval	  
newnameminecraft:bone_block
states
deprecatedpillar_axisz version  
oldnameminecraft:bone_blockval
  
newnameminecraft:bone_block
states
deprecatedpillar_axisz version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecatedpillar_axisz version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecated pillar_axisy version  
oldnameminecraft:bone_blockval
  
newnameminecraft:bone_block
states
deprecatedpillar_axisy version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecatedpillar_axisy version  
oldnameminecraft:bone_blockval  
newnameminecraft:bone_block
states
deprecatedpillar_axisy version  
oldnameminecraft:bookshelfval   
newnameminecraft:bookshelf
states version  
oldnameminecraft:brewing_standval   
newnameminecraft:brewing_stand
statesbrewing_stand_slot_a_bit brewing_stand_slot_b_bit brewing_stand_slot_c_bit  version  
oldnameminecraft:brewing_standval  
newnameminecraft:brewing_stand
statesbrewing_stand_slot_a_bitbrewing_stand_slot_b_bit brewing_stand_slot_c_bit  version  
oldnameminecraft:brewing_standval  
newnameminecraft:brewing_stand
statesbrewing_stand_slot_a_bit brewing_stand_slot_b_bitbrewing_stand_slot_c_bit  version  
oldnameminecraft:brewing_standval  
newnameminecraft:brewing_stand
statesbrewing_stand_slot_a_bitbrewing_stand_slot_b_bitbrewing_stand_slot_c_bit  version  
oldnameminecraft:brewing_standval  
newnameminecraft:brewing_stand
statesbrewing_stand_slot_a_bit brewing_stand_slot_b_bit brewing_stand_slot_c_bit version  
oldnameminecraft:brewing_standval  
newnameminecraft:brewing_stand
statesbrewing_stand_slot_a_bitbrewing_stand_slot_b_bit brewing_stand_slot_c_bit version  
oldnameminecraft:brewing_standval  
newnameminecraft:brewing_stand
statesbrewing_stand_slot_a_bit brewing_stand_slot_b_bitbrewing_stand_slot_c_bit version  
oldnameminecraft:brewing_standval  
newnameminecraft:brewing_stand
statesbrewing_stand_slot_a_bitbrewing_stand_slot_b_bitbrewing_stand_slot_c_bit version  
oldnameminecraft:brick_blockval   
newnameminecraft:brick_block
states version  
oldnameminecraft:brick_stairsval   
newnameminecraft:brick_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:brick_stairsval  
newnameminecraft:brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:brick_stairsval  
newnameminecraft:brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:brick_stairsval  
newnameminecraft:brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:brick_stairsval  
newnameminecraft:brick_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:brick_stairsval  
newnameminecraft:brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:brick_stairsval  
newnameminecraft:brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:brick_stairsval  
newnameminecraft:brick_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:brown_glazed_terracottaval   
newname!minecraft:brown_glazed_terracotta
statesfacing_direction  version  
oldname!minecraft:brown_glazed_terracottaval  
newname!minecraft:brown_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:brown_glazed_terracottaval  
newname!minecraft:brown_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:brown_glazed_terracottaval  
newname!minecraft:brown_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:brown_glazed_terracottaval  
newname!minecraft:brown_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:brown_glazed_terracottaval  
newname!minecraft:brown_glazed_terracotta
statesfacing_direction
 version  
oldname!minecraft:brown_glazed_terracottaval  
newname!minecraft:brown_glazed_terracotta
statesfacing_direction  version  
oldname!minecraft:brown_glazed_terracottaval  
newname!minecraft:brown_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:brown_mushroomval   
newnameminecraft:brown_mushroom
states version  
oldnameminecraft:brown_mushroom_blockval   
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits  version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits
 version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval	  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval
  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval
  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:brown_mushroom_blockval  
newnameminecraft:brown_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:bubble_columnval   
newnameminecraft:bubble_column
states	drag_down  version  
oldnameminecraft:bubble_columnval  
newnameminecraft:bubble_column
states	drag_down version  
oldnameminecraft:cactusval   
newnameminecraft:cactus
statesage  version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage
 version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval	  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval
  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval
  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cactusval  
newnameminecraft:cactus
statesage version  
oldnameminecraft:cakeval   
newnameminecraft:cake
statesbite_counter  version  
oldnameminecraft:cakeval  
newnameminecraft:cake
statesbite_counter version  
oldnameminecraft:cakeval  
newnameminecraft:cake
statesbite_counter version  
oldnameminecraft:cakeval  
newnameminecraft:cake
statesbite_counter version  
oldnameminecraft:cakeval  
newnameminecraft:cake
statesbite_counter version  
oldnameminecraft:cakeval  
newnameminecraft:cake
statesbite_counter
 version  
oldnameminecraft:cakeval  
newnameminecraft:cake
statesbite_counter version  
oldnameminecraft:cakeval  
newnameminecraft:cake
statesbite_counter  version  
oldnameminecraft:campfireval   
newnameminecraft:campfire
states	direction extinguished  version  
oldnameminecraft:campfireval  
newnameminecraft:campfire
states	directionextinguished  version  
oldnameminecraft:campfireval  
newnameminecraft:campfire
states	directionextinguished  version  
oldnameminecraft:campfireval  
newnameminecraft:campfire
states	directionextinguished  version  
oldnameminecraft:campfireval  
newnameminecraft:campfire
states	direction extinguished version  
oldnameminecraft:campfireval  
newnameminecraft:campfire
states	directionextinguished version  
oldnameminecraft:campfireval  
newnameminecraft:campfire
states	directionextinguished version  
oldnameminecraft:campfireval  
newnameminecraft:campfire
states	directionextinguished version  
oldnameminecraft:carpetval   
newnameminecraft:carpet
statescolorwhite version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolororange version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolormagenta version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolor
light_blue version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescoloryellow version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolorlime version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolorpink version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolorgray version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolorsilver version  
oldnameminecraft:carpetval	  
newnameminecraft:carpet
statescolorcyan version  
oldnameminecraft:carpetval
  
newnameminecraft:carpet
statescolorpurple version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolorblue version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolorbrown version  
oldnameminecraft:carpetval
  
newnameminecraft:carpet
statescolorgreen version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolorred version  
oldnameminecraft:carpetval  
newnameminecraft:carpet
statescolorblack version  
oldnameminecraft:carrotsval   
newnameminecraft:carrots
statesgrowth  version  
oldnameminecraft:carrotsval  
newnameminecraft:carrots
statesgrowth version  
oldnameminecraft:carrotsval  
newnameminecraft:carrots
statesgrowth version  
oldnameminecraft:carrotsval  
newnameminecraft:carrots
statesgrowth version  
oldnameminecraft:carrotsval  
newnameminecraft:carrots
statesgrowth version  
oldnameminecraft:carrotsval  
newnameminecraft:carrots
statesgrowth
 version  
oldnameminecraft:carrotsval  
newnameminecraft:carrots
statesgrowth version  
oldnameminecraft:carrotsval  
newnameminecraft:carrots
statesgrowth version  
oldnameminecraft:cartography_tableval   
newnameminecraft:cartography_table
states version  
oldnameminecraft:carved_pumpkinval   
newnameminecraft:carved_pumpkin
states	direction  version  
oldnameminecraft:carved_pumpkinval  
newnameminecraft:carved_pumpkin
states	direction version  
oldnameminecraft:carved_pumpkinval  
newnameminecraft:carved_pumpkin
states	direction version  
oldnameminecraft:carved_pumpkinval  
newnameminecraft:carved_pumpkin
states	direction version  
oldnameminecraft:cauldronval   
newnameminecraft:cauldron
statescauldron_liquidwater
fill_level  version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidwater
fill_level
 version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidlava
fill_level  version  
oldnameminecraft:cauldronval	  
newnameminecraft:cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:cauldronval
  
newnameminecraft:cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:cauldronval
  
newnameminecraft:cauldron
statescauldron_liquidlava
fill_level
 version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:cauldronval  
newnameminecraft:cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:chain_command_blockval   
newnameminecraft:chain_command_block
statesconditional_bit facing_direction  version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bit facing_direction version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bit facing_direction version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bit facing_direction version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bit facing_direction version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bit facing_direction
 version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bit facing_direction  version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bit facing_direction  version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bitfacing_direction  version  
oldnameminecraft:chain_command_blockval	  
newnameminecraft:chain_command_block
statesconditional_bitfacing_direction version  
oldnameminecraft:chain_command_blockval
  
newnameminecraft:chain_command_block
statesconditional_bitfacing_direction version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bitfacing_direction version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bitfacing_direction version  
oldnameminecraft:chain_command_blockval
  
newnameminecraft:chain_command_block
statesconditional_bitfacing_direction
 version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bitfacing_direction  version  
oldnameminecraft:chain_command_blockval  
newnameminecraft:chain_command_block
statesconditional_bitfacing_direction  version  
oldnameminecraft:chemical_heatval   
newnameminecraft:chemical_heat
states version  
oldnameminecraft:chemistry_tableval   
newnameminecraft:chemistry_table
stateschemistry_table_typecompound_creator	direction  version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_typecompound_creator	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_typecompound_creator	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_typecompound_creator	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_typematerial_reducer	direction  version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_typematerial_reducer	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_typematerial_reducer	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_typematerial_reducer	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_typeelement_constructor	direction  version  
oldnameminecraft:chemistry_tableval	  
newnameminecraft:chemistry_table
stateschemistry_table_typeelement_constructor	direction version  
oldnameminecraft:chemistry_tableval
  
newnameminecraft:chemistry_table
stateschemistry_table_typeelement_constructor	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_typeelement_constructor	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_type	lab_table	direction  version  
oldnameminecraft:chemistry_tableval
  
newnameminecraft:chemistry_table
stateschemistry_table_type	lab_table	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_type	lab_table	direction version  
oldnameminecraft:chemistry_tableval  
newnameminecraft:chemistry_table
stateschemistry_table_type	lab_table	direction version  
oldnameminecraft:chestval   
newnameminecraft:chest
statesfacing_direction  version  
oldnameminecraft:chestval  
newnameminecraft:chest
statesfacing_direction version  
oldnameminecraft:chestval  
newnameminecraft:chest
statesfacing_direction version  
oldnameminecraft:chestval  
newnameminecraft:chest
statesfacing_direction version  
oldnameminecraft:chestval  
newnameminecraft:chest
statesfacing_direction version  
oldnameminecraft:chestval  
newnameminecraft:chest
statesfacing_direction
 version  
oldnameminecraft:chestval  
newnameminecraft:chest
statesfacing_direction  version  
oldnameminecraft:chestval  
newnameminecraft:chest
statesfacing_direction  version  
oldnameminecraft:chorus_flowerval   
newnameminecraft:chorus_flower
statesage  version  
oldnameminecraft:chorus_flowerval  
newnameminecraft:chorus_flower
statesage version  
oldnameminecraft:chorus_flowerval  
newnameminecraft:chorus_flower
statesage version  
oldnameminecraft:chorus_flowerval  
newnameminecraft:chorus_flower
statesage version  
oldnameminecraft:chorus_flowerval  
newnameminecraft:chorus_flower
statesage version  
oldnameminecraft:chorus_flowerval  
newnameminecraft:chorus_flower
statesage
 version  
oldnameminecraft:chorus_flowerval  
newnameminecraft:chorus_flower
statesage  version  
oldnameminecraft:chorus_flowerval  
newnameminecraft:chorus_flower
statesage  version  
oldnameminecraft:chorus_plantval   
newnameminecraft:chorus_plant
states version  
oldnameminecraft:clayval   
newnameminecraft:clay
states version  
oldnameminecraft:coal_blockval   
newnameminecraft:coal_block
states version  
oldnameminecraft:coal_oreval   
newnameminecraft:coal_ore
states version  
oldnameminecraft:cobblestoneval   
newnameminecraft:cobblestone
states version  
oldnameminecraft:cobblestone_wallval   
newnameminecraft:cobblestone_wall
stateswall_block_typecobblestone version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_typemossy_cobblestone version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_typegranite version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_typediorite version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_typeandesite version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_type	sandstone version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_typebrick version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_typestone_brick version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_typemossy_stone_brick version  
oldnameminecraft:cobblestone_wallval	  
newnameminecraft:cobblestone_wall
stateswall_block_typenether_brick version  
oldnameminecraft:cobblestone_wallval
  
newnameminecraft:cobblestone_wall
stateswall_block_type	end_brick version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_type
prismarine version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_type
red_sandstone version  
oldnameminecraft:cobblestone_wallval
  
newnameminecraft:cobblestone_wall
stateswall_block_typered_nether_brick version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_typecobblestone version  
oldnameminecraft:cobblestone_wallval  
newnameminecraft:cobblestone_wall
stateswall_block_typecobblestone version  
oldnameminecraft:cocoaval   
newnameminecraft:cocoa
statesage 	direction  version  
oldnameminecraft:cocoaval  
newnameminecraft:cocoa
statesage 	direction version  
oldnameminecraft:cocoaval  
newnameminecraft:cocoa
statesage 	direction version  
oldnameminecraft:cocoaval  
newnameminecraft:cocoa
statesage 	direction version  
oldnameminecraft:cocoaval  
newnameminecraft:cocoa
statesage	direction  version  
oldnameminecraft:cocoaval  
newnameminecraft:cocoa
statesage	direction version  
oldnameminecraft:cocoaval  
newnameminecraft:cocoa
statesage	direction version  
oldnameminecraft:cocoaval  
newnameminecraft:cocoa
statesage	direction version  
oldnameminecraft:cocoaval  
newnameminecraft:cocoa
statesage	direction  version  
oldnameminecraft:cocoaval	  
newnameminecraft:cocoa
statesage	direction version  
oldnameminecraft:cocoaval
  
newnameminecraft:cocoa
statesage	direction version  
oldnameminecraft:cocoaval  
newnameminecraft:cocoa
statesage	direction version  
oldnameminecraft:colored_torch_bpval   
newnameminecraft:colored_torch_bp
states	color_bit torch_facing_directionunknown version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bit torch_facing_directionwest version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bit torch_facing_directioneast version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bit torch_facing_directionnorth version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bit torch_facing_directionsouth version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bit torch_facing_directiontop version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bit torch_facing_directionunknown version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bit torch_facing_directionunknown version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bittorch_facing_directionunknown version  
oldnameminecraft:colored_torch_bpval	  
newnameminecraft:colored_torch_bp
states	color_bittorch_facing_directionwest version  
oldnameminecraft:colored_torch_bpval
  
newnameminecraft:colored_torch_bp
states	color_bittorch_facing_directioneast version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bittorch_facing_directionnorth version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bittorch_facing_directionsouth version  
oldnameminecraft:colored_torch_bpval
  
newnameminecraft:colored_torch_bp
states	color_bittorch_facing_directiontop version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bittorch_facing_directionunknown version  
oldnameminecraft:colored_torch_bpval  
newnameminecraft:colored_torch_bp
states	color_bittorch_facing_directionunknown version  
oldnameminecraft:colored_torch_rgval   
newnameminecraft:colored_torch_rg
states	color_bit torch_facing_directionunknown version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bit torch_facing_directionwest version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bit torch_facing_directioneast version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bit torch_facing_directionnorth version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bit torch_facing_directionsouth version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bit torch_facing_directiontop version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bit torch_facing_directionunknown version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bit torch_facing_directionunknown version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bittorch_facing_directionunknown version  
oldnameminecraft:colored_torch_rgval	  
newnameminecraft:colored_torch_rg
states	color_bittorch_facing_directionwest version  
oldnameminecraft:colored_torch_rgval
  
newnameminecraft:colored_torch_rg
states	color_bittorch_facing_directioneast version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bittorch_facing_directionnorth version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bittorch_facing_directionsouth version  
oldnameminecraft:colored_torch_rgval
  
newnameminecraft:colored_torch_rg
states	color_bittorch_facing_directiontop version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bittorch_facing_directionunknown version  
oldnameminecraft:colored_torch_rgval  
newnameminecraft:colored_torch_rg
states	color_bittorch_facing_directionunknown version  
oldnameminecraft:command_blockval   
newnameminecraft:command_block
statesconditional_bit facing_direction  version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bit facing_direction version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bit facing_direction version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bit facing_direction version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bit facing_direction version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bit facing_direction
 version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bit facing_direction  version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bit facing_direction  version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bitfacing_direction  version  
oldnameminecraft:command_blockval	  
newnameminecraft:command_block
statesconditional_bitfacing_direction version  
oldnameminecraft:command_blockval
  
newnameminecraft:command_block
statesconditional_bitfacing_direction version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bitfacing_direction version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bitfacing_direction version  
oldnameminecraft:command_blockval
  
newnameminecraft:command_block
statesconditional_bitfacing_direction
 version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bitfacing_direction  version  
oldnameminecraft:command_blockval  
newnameminecraft:command_block
statesconditional_bitfacing_direction  version  
oldnameminecraft:composterval   
newnameminecraft:composter
statescomposter_fill_level  version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level
 version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level version  
oldnameminecraft:composterval	  
newnameminecraft:composter
statescomposter_fill_level  version  
oldnameminecraft:composterval
  
newnameminecraft:composter
statescomposter_fill_level  version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level  version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level  version  
oldnameminecraft:composterval
  
newnameminecraft:composter
statescomposter_fill_level  version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level  version  
oldnameminecraft:composterval  
newnameminecraft:composter
statescomposter_fill_level  version  
oldnameminecraft:concreteval   
newnameminecraft:concrete
statescolorwhite version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolororange version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolormagenta version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolor
light_blue version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescoloryellow version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolorlime version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolorpink version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolorgray version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolorsilver version  
oldnameminecraft:concreteval	  
newnameminecraft:concrete
statescolorcyan version  
oldnameminecraft:concreteval
  
newnameminecraft:concrete
statescolorpurple version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolorblue version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolorbrown version  
oldnameminecraft:concreteval
  
newnameminecraft:concrete
statescolorgreen version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolorred version  
oldnameminecraft:concreteval  
newnameminecraft:concrete
statescolorblack version  
oldnameminecraft:concretePowderval   
newnameminecraft:concretePowder
statescolorwhite version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolororange version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolormagenta version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolor
light_blue version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescoloryellow version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolorlime version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolorpink version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolorgray version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolorsilver version  
oldnameminecraft:concretePowderval	  
newnameminecraft:concretePowder
statescolorcyan version  
oldnameminecraft:concretePowderval
  
newnameminecraft:concretePowder
statescolorpurple version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolorblue version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolorbrown version  
oldnameminecraft:concretePowderval
  
newnameminecraft:concretePowder
statescolorgreen version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolorred version  
oldnameminecraft:concretePowderval  
newnameminecraft:concretePowder
statescolorblack version  
oldnameminecraft:conduitval   
newnameminecraft:conduit
states version  
oldnameminecraft:coralval   
newnameminecraft:coral
statescoral_colorbluedead_bit  version  
oldnameminecraft:coralval  
newnameminecraft:coral
statescoral_colorpinkdead_bit  version  
oldnameminecraft:coralval  
newnameminecraft:coral
statescoral_colorpurpledead_bit  version  
oldnameminecraft:coralval  
newnameminecraft:coral
statescoral_colorreddead_bit  version  
oldnameminecraft:coralval  
newnameminecraft:coral
statescoral_coloryellowdead_bit  version  
oldnameminecraft:coralval  
newnameminecraft:coral
statescoral_colorbluedead_bit  version  
oldnameminecraft:coralval  
newnameminecraft:coral
statescoral_colorbluedead_bit  version  
oldnameminecraft:coralval  
newnameminecraft:coral
statescoral_colorbluedead_bit  version  
oldnameminecraft:coral_blockval   
newnameminecraft:coral_block
statescoral_colorbluedead_bit  version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorpinkdead_bit  version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorpurpledead_bit  version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorreddead_bit  version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_coloryellowdead_bit  version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorbluedead_bit  version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorbluedead_bit  version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorbluedead_bit  version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorbluedead_bit version  
oldnameminecraft:coral_blockval	  
newnameminecraft:coral_block
statescoral_colorpinkdead_bit version  
oldnameminecraft:coral_blockval
  
newnameminecraft:coral_block
statescoral_colorpurpledead_bit version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorreddead_bit version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_coloryellowdead_bit version  
oldnameminecraft:coral_blockval
  
newnameminecraft:coral_block
statescoral_colorbluedead_bit version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorbluedead_bit version  
oldnameminecraft:coral_blockval  
newnameminecraft:coral_block
statescoral_colorbluedead_bit version  
oldnameminecraft:coral_fanval   
newnameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction  version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorpinkcoral_fan_direction  version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorpurplecoral_fan_direction  version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorredcoral_fan_direction  version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_coloryellowcoral_fan_direction  version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction  version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction  version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction  version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction version  
oldnameminecraft:coral_fanval	  
newnameminecraft:coral_fan
statescoral_colorpinkcoral_fan_direction version  
oldnameminecraft:coral_fanval
  
newnameminecraft:coral_fan
statescoral_colorpurplecoral_fan_direction version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorredcoral_fan_direction version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_coloryellowcoral_fan_direction version  
oldnameminecraft:coral_fanval
  
newnameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction version  
oldnameminecraft:coral_fanval  
newnameminecraft:coral_fan
statescoral_colorbluecoral_fan_direction version  
oldnameminecraft:coral_fan_deadval   
newnameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction  version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorpinkcoral_fan_direction  version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorpurplecoral_fan_direction  version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorredcoral_fan_direction  version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_coloryellowcoral_fan_direction  version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction  version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction  version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction  version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction version  
oldnameminecraft:coral_fan_deadval	  
newnameminecraft:coral_fan_dead
statescoral_colorpinkcoral_fan_direction version  
oldnameminecraft:coral_fan_deadval
  
newnameminecraft:coral_fan_dead
statescoral_colorpurplecoral_fan_direction version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorredcoral_fan_direction version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_coloryellowcoral_fan_direction version  
oldnameminecraft:coral_fan_deadval
  
newnameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction version  
oldnameminecraft:coral_fan_deadval  
newnameminecraft:coral_fan_dead
statescoral_colorbluecoral_fan_direction version  
oldnameminecraft:coral_fan_hangval   
newnameminecraft:coral_fan_hang
statescoral_direction coral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_direction coral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_direction coral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_direction coral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hangval	  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hangval
  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hangval
  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hangval  
newnameminecraft:coral_fan_hang
statescoral_directioncoral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hang2val   
newnameminecraft:coral_fan_hang2
statescoral_direction coral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_direction coral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_direction coral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_direction coral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hang2val	  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hang2val
  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hang2val
  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hang2val  
newnameminecraft:coral_fan_hang2
statescoral_directioncoral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hang3val   
newnameminecraft:coral_fan_hang3
statescoral_direction coral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_direction coral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_direction coral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_direction coral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hang3val	  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hang3val
  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit  version  
oldnameminecraft:coral_fan_hang3val
  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit  version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bit dead_bit version  
oldnameminecraft:coral_fan_hang3val  
newnameminecraft:coral_fan_hang3
statescoral_directioncoral_hang_type_bitdead_bit version  
oldnameminecraft:crafting_tableval   
newnameminecraft:crafting_table
states version  
oldname minecraft:cyan_glazed_terracottaval   
newname minecraft:cyan_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:cyan_glazed_terracottaval  
newname minecraft:cyan_glazed_terracotta
statesfacing_direction version  
oldname minecraft:cyan_glazed_terracottaval  
newname minecraft:cyan_glazed_terracotta
statesfacing_direction version  
oldname minecraft:cyan_glazed_terracottaval  
newname minecraft:cyan_glazed_terracotta
statesfacing_direction version  
oldname minecraft:cyan_glazed_terracottaval  
newname minecraft:cyan_glazed_terracotta
statesfacing_direction version  
oldname minecraft:cyan_glazed_terracottaval  
newname minecraft:cyan_glazed_terracotta
statesfacing_direction
 version  
oldname minecraft:cyan_glazed_terracottaval  
newname minecraft:cyan_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:cyan_glazed_terracottaval  
newname minecraft:cyan_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:dark_oak_buttonval   
newnameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction
 version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:dark_oak_buttonval	  
newnameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:dark_oak_buttonval
  
newnameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:dark_oak_buttonval
  
newnameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction
 version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:dark_oak_buttonval  
newnameminecraft:dark_oak_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:dark_oak_doorval   
newnameminecraft:dark_oak_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:dark_oak_doorval	  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:dark_oak_doorval
  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:dark_oak_doorval
  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:dark_oak_doorval  
newnameminecraft:dark_oak_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:dark_oak_fence_gateval   
newnameminecraft:dark_oak_fence_gate
states	direction in_wall_bit open_bit  version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	direction in_wall_bit open_bit version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	direction in_wall_bitopen_bit  version  
oldnameminecraft:dark_oak_fence_gateval	  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:dark_oak_fence_gateval
  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	direction in_wall_bitopen_bit version  
oldnameminecraft:dark_oak_fence_gateval
  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:dark_oak_fence_gateval  
newnameminecraft:dark_oak_fence_gate
states	directionin_wall_bitopen_bit version  
oldname!minecraft:dark_oak_pressure_plateval   
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal  version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal
 version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval	  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval
  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval
  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldname!minecraft:dark_oak_pressure_plateval  
newname!minecraft:dark_oak_pressure_plate
statesredstone_signal version  
oldnameminecraft:dark_oak_stairsval   
newnameminecraft:dark_oak_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:dark_oak_stairsval  
newnameminecraft:dark_oak_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:dark_oak_stairsval  
newnameminecraft:dark_oak_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:dark_oak_stairsval  
newnameminecraft:dark_oak_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:dark_oak_stairsval  
newnameminecraft:dark_oak_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:dark_oak_stairsval  
newnameminecraft:dark_oak_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:dark_oak_stairsval  
newnameminecraft:dark_oak_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:dark_oak_stairsval  
newnameminecraft:dark_oak_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:dark_oak_trapdoorval   
newnameminecraft:dark_oak_trapdoor
states	direction open_bit upside_down_bit  version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	direction open_bit upside_down_bit version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	direction open_bitupside_down_bit  version  
oldnameminecraft:dark_oak_trapdoorval	  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:dark_oak_trapdoorval
  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	direction open_bitupside_down_bit version  
oldnameminecraft:dark_oak_trapdoorval
  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:dark_oak_trapdoorval  
newnameminecraft:dark_oak_trapdoor
states	directionopen_bitupside_down_bit version  
oldname minecraft:dark_prismarine_stairsval   
newname minecraft:dark_prismarine_stairs
statesupside_down_bit weirdo_direction  version  
oldname minecraft:dark_prismarine_stairsval  
newname minecraft:dark_prismarine_stairs
statesupside_down_bit weirdo_direction version  
oldname minecraft:dark_prismarine_stairsval  
newname minecraft:dark_prismarine_stairs
statesupside_down_bit weirdo_direction version  
oldname minecraft:dark_prismarine_stairsval  
newname minecraft:dark_prismarine_stairs
statesupside_down_bit weirdo_direction version  
oldname minecraft:dark_prismarine_stairsval  
newname minecraft:dark_prismarine_stairs
statesupside_down_bitweirdo_direction  version  
oldname minecraft:dark_prismarine_stairsval  
newname minecraft:dark_prismarine_stairs
statesupside_down_bitweirdo_direction version  
oldname minecraft:dark_prismarine_stairsval  
newname minecraft:dark_prismarine_stairs
statesupside_down_bitweirdo_direction version  
oldname minecraft:dark_prismarine_stairsval  
newname minecraft:dark_prismarine_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:darkoak_standing_signval   
newnameminecraft:darkoak_standing_sign
statesground_sign_direction  version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction
 version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval	  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval
  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval
  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_standing_signval  
newnameminecraft:darkoak_standing_sign
statesground_sign_direction version  
oldnameminecraft:darkoak_wall_signval   
newnameminecraft:darkoak_wall_sign
statesfacing_direction  version  
oldnameminecraft:darkoak_wall_signval  
newnameminecraft:darkoak_wall_sign
statesfacing_direction version  
oldnameminecraft:darkoak_wall_signval  
newnameminecraft:darkoak_wall_sign
statesfacing_direction version  
oldnameminecraft:darkoak_wall_signval  
newnameminecraft:darkoak_wall_sign
statesfacing_direction version  
oldnameminecraft:darkoak_wall_signval  
newnameminecraft:darkoak_wall_sign
statesfacing_direction version  
oldnameminecraft:darkoak_wall_signval  
newnameminecraft:darkoak_wall_sign
statesfacing_direction
 version  
oldnameminecraft:darkoak_wall_signval  
newnameminecraft:darkoak_wall_sign
statesfacing_direction  version  
oldnameminecraft:darkoak_wall_signval  
newnameminecraft:darkoak_wall_sign
statesfacing_direction  version  
oldnameminecraft:daylight_detectorval   
newnameminecraft:daylight_detector
statesredstone_signal  version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal
 version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval	  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval
  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval
  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldnameminecraft:daylight_detectorval  
newnameminecraft:daylight_detector
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval   
newname$minecraft:daylight_detector_inverted
statesredstone_signal  version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal
 version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval	  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval
  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval
  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldname$minecraft:daylight_detector_invertedval  
newname$minecraft:daylight_detector_inverted
statesredstone_signal version  
oldnameminecraft:deadbushval   
newnameminecraft:deadbush
states version  
oldnameminecraft:detector_railval   
newnameminecraft:detector_rail
states
rail_data_bit rail_direction  version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bit rail_direction
 version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bit rail_direction  version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bit rail_direction  version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bitrail_direction  version  
oldnameminecraft:detector_railval	  
newnameminecraft:detector_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:detector_railval
  
newnameminecraft:detector_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:detector_railval
  
newnameminecraft:detector_rail
states
rail_data_bitrail_direction
 version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bitrail_direction  version  
oldnameminecraft:detector_railval  
newnameminecraft:detector_rail
states
rail_data_bitrail_direction  version  
oldnameminecraft:diamond_blockval   
newnameminecraft:diamond_block
states version  
oldnameminecraft:diamond_oreval   
newnameminecraft:diamond_ore
states version  
oldnameminecraft:diorite_stairsval   
newnameminecraft:diorite_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:diorite_stairsval  
newnameminecraft:diorite_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:diorite_stairsval  
newnameminecraft:diorite_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:diorite_stairsval  
newnameminecraft:diorite_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:diorite_stairsval  
newnameminecraft:diorite_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:diorite_stairsval  
newnameminecraft:diorite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:diorite_stairsval  
newnameminecraft:diorite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:diorite_stairsval  
newnameminecraft:diorite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:dirtval   
newnameminecraft:dirt
states	dirt_typenormal version  
oldnameminecraft:dirtval  
newnameminecraft:dirt
states	dirt_typecoarse version  
oldnameminecraft:dispenserval   
newnameminecraft:dispenser
statesfacing_direction 
triggered_bit  version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction
triggered_bit  version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction
triggered_bit  version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction
triggered_bit  version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction
triggered_bit  version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction

triggered_bit  version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction 
triggered_bit  version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction 
triggered_bit  version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction 
triggered_bit version  
oldnameminecraft:dispenserval	  
newnameminecraft:dispenser
statesfacing_direction
triggered_bit version  
oldnameminecraft:dispenserval
  
newnameminecraft:dispenser
statesfacing_direction
triggered_bit version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction
triggered_bit version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction
triggered_bit version  
oldnameminecraft:dispenserval
  
newnameminecraft:dispenser
statesfacing_direction

triggered_bit version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction 
triggered_bit version  
oldnameminecraft:dispenserval  
newnameminecraft:dispenser
statesfacing_direction 
triggered_bit version  
oldnameminecraft:double_plantval   
newnameminecraft:double_plant
statesdouble_plant_type	sunflowerupper_block_bit  version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_typesyringaupper_block_bit  version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_typegrassupper_block_bit  version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_typefernupper_block_bit  version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_typeroseupper_block_bit  version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_typepaeoniaupper_block_bit  version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_type	sunflowerupper_block_bit  version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_type	sunflowerupper_block_bit  version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_type	sunflowerupper_block_bit version  
oldnameminecraft:double_plantval	  
newnameminecraft:double_plant
statesdouble_plant_typesyringaupper_block_bit version  
oldnameminecraft:double_plantval
  
newnameminecraft:double_plant
statesdouble_plant_typegrassupper_block_bit version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_typefernupper_block_bit version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_typeroseupper_block_bit version  
oldnameminecraft:double_plantval
  
newnameminecraft:double_plant
statesdouble_plant_typepaeoniaupper_block_bit version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_type	sunflowerupper_block_bit version  
oldnameminecraft:double_plantval  
newnameminecraft:double_plant
statesdouble_plant_type	sunflowerupper_block_bit version  
oldnameminecraft:double_stone_slabval   
newnameminecraft:double_stone_slab
statesstone_slab_typesmooth_stonetop_slot_bit  version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_type	sandstonetop_slot_bit  version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typewoodtop_slot_bit  version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typecobblestonetop_slot_bit  version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typebricktop_slot_bit  version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typestone_bricktop_slot_bit  version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typequartztop_slot_bit  version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typenether_bricktop_slot_bit  version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typesmooth_stonetop_slot_bit version  
oldnameminecraft:double_stone_slabval	  
newnameminecraft:double_stone_slab
statesstone_slab_type	sandstonetop_slot_bit version  
oldnameminecraft:double_stone_slabval
  
newnameminecraft:double_stone_slab
statesstone_slab_typewoodtop_slot_bit version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typecobblestonetop_slot_bit version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typebricktop_slot_bit version  
oldnameminecraft:double_stone_slabval
  
newnameminecraft:double_stone_slab
statesstone_slab_typestone_bricktop_slot_bit version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typequartztop_slot_bit version  
oldnameminecraft:double_stone_slabval  
newnameminecraft:double_stone_slab
statesstone_slab_typenether_bricktop_slot_bit version  
oldnameminecraft:double_stone_slab2val   
newnameminecraft:double_stone_slab2
statesstone_slab_type_2
red_sandstonetop_slot_bit  version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2purpurtop_slot_bit  version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_roughtop_slot_bit  version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_darktop_slot_bit  version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_bricktop_slot_bit  version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2mossy_cobblestonetop_slot_bit  version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2smooth_sandstonetop_slot_bit  version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2red_nether_bricktop_slot_bit  version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2
red_sandstonetop_slot_bit version  
oldnameminecraft:double_stone_slab2val	  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2purpurtop_slot_bit version  
oldnameminecraft:double_stone_slab2val
  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_roughtop_slot_bit version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_darktop_slot_bit version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2prismarine_bricktop_slot_bit version  
oldnameminecraft:double_stone_slab2val
  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2mossy_cobblestonetop_slot_bit version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2smooth_sandstonetop_slot_bit version  
oldnameminecraft:double_stone_slab2val  
newnameminecraft:double_stone_slab2
statesstone_slab_type_2red_nether_bricktop_slot_bit version  
oldnameminecraft:double_stone_slab3val   
newnameminecraft:double_stone_slab3
statesstone_slab_type_3end_stone_bricktop_slot_bit  version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3smooth_red_sandstonetop_slot_bit  version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3polished_andesitetop_slot_bit  version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3andesitetop_slot_bit  version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3dioritetop_slot_bit  version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3polished_dioritetop_slot_bit  version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3granitetop_slot_bit  version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3polished_granitetop_slot_bit  version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3end_stone_bricktop_slot_bit version  
oldnameminecraft:double_stone_slab3val	  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3smooth_red_sandstonetop_slot_bit version  
oldnameminecraft:double_stone_slab3val
  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3polished_andesitetop_slot_bit version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3andesitetop_slot_bit version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3dioritetop_slot_bit version  
oldnameminecraft:double_stone_slab3val
  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3polished_dioritetop_slot_bit version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3granitetop_slot_bit version  
oldnameminecraft:double_stone_slab3val  
newnameminecraft:double_stone_slab3
statesstone_slab_type_3polished_granitetop_slot_bit version  
oldnameminecraft:double_stone_slab4val   
newnameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4
smooth_quartztop_slot_bit  version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4stonetop_slot_bit  version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4
cut_sandstonetop_slot_bit  version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4cut_red_sandstonetop_slot_bit  version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version  
oldnameminecraft:double_stone_slab4val	  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4
smooth_quartztop_slot_bit version  
oldnameminecraft:double_stone_slab4val
  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4stonetop_slot_bit version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4
cut_sandstonetop_slot_bit version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4cut_red_sandstonetop_slot_bit version  
oldnameminecraft:double_stone_slab4val
  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version  
oldnameminecraft:double_stone_slab4val  
newnameminecraft:double_stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version  
oldnameminecraft:double_wooden_slabval   
newnameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typeoak version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typespruce version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typebirch version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typejungle version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typeacacia version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typedark_oak version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typeoak version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit 	wood_typeoak version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit	wood_typeoak version  
oldnameminecraft:double_wooden_slabval	  
newnameminecraft:double_wooden_slab
statestop_slot_bit	wood_typespruce version  
oldnameminecraft:double_wooden_slabval
  
newnameminecraft:double_wooden_slab
statestop_slot_bit	wood_typebirch version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit	wood_typejungle version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit	wood_typeacacia version  
oldnameminecraft:double_wooden_slabval
  
newnameminecraft:double_wooden_slab
statestop_slot_bit	wood_typedark_oak version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit	wood_typeoak version  
oldnameminecraft:double_wooden_slabval  
newnameminecraft:double_wooden_slab
statestop_slot_bit	wood_typeoak version  
oldnameminecraft:dragon_eggval   
newnameminecraft:dragon_egg
states version  
oldnameminecraft:dried_kelp_blockval   
newnameminecraft:dried_kelp_block
states version  
oldnameminecraft:dropperval   
newnameminecraft:dropper
statesfacing_direction 
triggered_bit  version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction
triggered_bit  version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction
triggered_bit  version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction
triggered_bit  version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction
triggered_bit  version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction

triggered_bit  version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction 
triggered_bit  version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction 
triggered_bit  version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction 
triggered_bit version  
oldnameminecraft:dropperval	  
newnameminecraft:dropper
statesfacing_direction
triggered_bit version  
oldnameminecraft:dropperval
  
newnameminecraft:dropper
statesfacing_direction
triggered_bit version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction
triggered_bit version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction
triggered_bit version  
oldnameminecraft:dropperval
  
newnameminecraft:dropper
statesfacing_direction

triggered_bit version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction 
triggered_bit version  
oldnameminecraft:dropperval  
newnameminecraft:dropper
statesfacing_direction 
triggered_bit version  
oldnameminecraft:element_0val   
newnameminecraft:element_0
states version  
oldnameminecraft:element_1val   
newnameminecraft:element_1
states version  
oldnameminecraft:element_10val   
newnameminecraft:element_10
states version  
oldnameminecraft:element_100val   
newnameminecraft:element_100
states version  
oldnameminecraft:element_101val   
newnameminecraft:element_101
states version  
oldnameminecraft:element_102val   
newnameminecraft:element_102
states version  
oldnameminecraft:element_103val   
newnameminecraft:element_103
states version  
oldnameminecraft:element_104val   
newnameminecraft:element_104
states version  
oldnameminecraft:element_105val   
newnameminecraft:element_105
states version  
oldnameminecraft:element_106val   
newnameminecraft:element_106
states version  
oldnameminecraft:element_107val   
newnameminecraft:element_107
states version  
oldnameminecraft:element_108val   
newnameminecraft:element_108
states version  
oldnameminecraft:element_109val   
newnameminecraft:element_109
states version  
oldnameminecraft:element_11val   
newnameminecraft:element_11
states version  
oldnameminecraft:element_110val   
newnameminecraft:element_110
states version  
oldnameminecraft:element_111val   
newnameminecraft:element_111
states version  
oldnameminecraft:element_112val   
newnameminecraft:element_112
states version  
oldnameminecraft:element_113val   
newnameminecraft:element_113
states version  
oldnameminecraft:element_114val   
newnameminecraft:element_114
states version  
oldnameminecraft:element_115val   
newnameminecraft:element_115
states version  
oldnameminecraft:element_116val   
newnameminecraft:element_116
states version  
oldnameminecraft:element_117val   
newnameminecraft:element_117
states version  
oldnameminecraft:element_118val   
newnameminecraft:element_118
states version  
oldnameminecraft:element_12val   
newnameminecraft:element_12
states version  
oldnameminecraft:element_13val   
newnameminecraft:element_13
states version  
oldnameminecraft:element_14val   
newnameminecraft:element_14
states version  
oldnameminecraft:element_15val   
newnameminecraft:element_15
states version  
oldnameminecraft:element_16val   
newnameminecraft:element_16
states version  
oldnameminecraft:element_17val   
newnameminecraft:element_17
states version  
oldnameminecraft:element_18val   
newnameminecraft:element_18
states version  
oldnameminecraft:element_19val   
newnameminecraft:element_19
states version  
oldnameminecraft:element_2val   
newnameminecraft:element_2
states version  
oldnameminecraft:element_20val   
newnameminecraft:element_20
states version  
oldnameminecraft:element_21val   
newnameminecraft:element_21
states version  
oldnameminecraft:element_22val   
newnameminecraft:element_22
states version  
oldnameminecraft:element_23val   
newnameminecraft:element_23
states version  
oldnameminecraft:element_24val   
newnameminecraft:element_24
states version  
oldnameminecraft:element_25val   
newnameminecraft:element_25
states version  
oldnameminecraft:element_26val   
newnameminecraft:element_26
states version  
oldnameminecraft:element_27val   
newnameminecraft:element_27
states version  
oldnameminecraft:element_28val   
newnameminecraft:element_28
states version  
oldnameminecraft:element_29val   
newnameminecraft:element_29
states version  
oldnameminecraft:element_3val   
newnameminecraft:element_3
states version  
oldnameminecraft:element_30val   
newnameminecraft:element_30
states version  
oldnameminecraft:element_31val   
newnameminecraft:element_31
states version  
oldnameminecraft:element_32val   
newnameminecraft:element_32
states version  
oldnameminecraft:element_33val   
newnameminecraft:element_33
states version  
oldnameminecraft:element_34val   
newnameminecraft:element_34
states version  
oldnameminecraft:element_35val   
newnameminecraft:element_35
states version  
oldnameminecraft:element_36val   
newnameminecraft:element_36
states version  
oldnameminecraft:element_37val   
newnameminecraft:element_37
states version  
oldnameminecraft:element_38val   
newnameminecraft:element_38
states version  
oldnameminecraft:element_39val   
newnameminecraft:element_39
states version  
oldnameminecraft:element_4val   
newnameminecraft:element_4
states version  
oldnameminecraft:element_40val   
newnameminecraft:element_40
states version  
oldnameminecraft:element_41val   
newnameminecraft:element_41
states version  
oldnameminecraft:element_42val   
newnameminecraft:element_42
states version  
oldnameminecraft:element_43val   
newnameminecraft:element_43
states version  
oldnameminecraft:element_44val   
newnameminecraft:element_44
states version  
oldnameminecraft:element_45val   
newnameminecraft:element_45
states version  
oldnameminecraft:element_46val   
newnameminecraft:element_46
states version  
oldnameminecraft:element_47val   
newnameminecraft:element_47
states version  
oldnameminecraft:element_48val   
newnameminecraft:element_48
states version  
oldnameminecraft:element_49val   
newnameminecraft:element_49
states version  
oldnameminecraft:element_5val   
newnameminecraft:element_5
states version  
oldnameminecraft:element_50val   
newnameminecraft:element_50
states version  
oldnameminecraft:element_51val   
newnameminecraft:element_51
states version  
oldnameminecraft:element_52val   
newnameminecraft:element_52
states version  
oldnameminecraft:element_53val   
newnameminecraft:element_53
states version  
oldnameminecraft:element_54val   
newnameminecraft:element_54
states version  
oldnameminecraft:element_55val   
newnameminecraft:element_55
states version  
oldnameminecraft:element_56val   
newnameminecraft:element_56
states version  
oldnameminecraft:element_57val   
newnameminecraft:element_57
states version  
oldnameminecraft:element_58val   
newnameminecraft:element_58
states version  
oldnameminecraft:element_59val   
newnameminecraft:element_59
states version  
oldnameminecraft:element_6val   
newnameminecraft:element_6
states version  
oldnameminecraft:element_60val   
newnameminecraft:element_60
states version  
oldnameminecraft:element_61val   
newnameminecraft:element_61
states version  
oldnameminecraft:element_62val   
newnameminecraft:element_62
states version  
oldnameminecraft:element_63val   
newnameminecraft:element_63
states version  
oldnameminecraft:element_64val   
newnameminecraft:element_64
states version  
oldnameminecraft:element_65val   
newnameminecraft:element_65
states version  
oldnameminecraft:element_66val   
newnameminecraft:element_66
states version  
oldnameminecraft:element_67val   
newnameminecraft:element_67
states version  
oldnameminecraft:element_68val   
newnameminecraft:element_68
states version  
oldnameminecraft:element_69val   
newnameminecraft:element_69
states version  
oldnameminecraft:element_7val   
newnameminecraft:element_7
states version  
oldnameminecraft:element_70val   
newnameminecraft:element_70
states version  
oldnameminecraft:element_71val   
newnameminecraft:element_71
states version  
oldnameminecraft:element_72val   
newnameminecraft:element_72
states version  
oldnameminecraft:element_73val   
newnameminecraft:element_73
states version  
oldnameminecraft:element_74val   
newnameminecraft:element_74
states version  
oldnameminecraft:element_75val   
newnameminecraft:element_75
states version  
oldnameminecraft:element_76val   
newnameminecraft:element_76
states version  
oldnameminecraft:element_77val   
newnameminecraft:element_77
states version  
oldnameminecraft:element_78val   
newnameminecraft:element_78
states version  
oldnameminecraft:element_79val   
newnameminecraft:element_79
states version  
oldnameminecraft:element_8val   
newnameminecraft:element_8
states version  
oldnameminecraft:element_80val   
newnameminecraft:element_80
states version  
oldnameminecraft:element_81val   
newnameminecraft:element_81
states version  
oldnameminecraft:element_82val   
newnameminecraft:element_82
states version  
oldnameminecraft:element_83val   
newnameminecraft:element_83
states version  
oldnameminecraft:element_84val   
newnameminecraft:element_84
states version  
oldnameminecraft:element_85val   
newnameminecraft:element_85
states version  
oldnameminecraft:element_86val   
newnameminecraft:element_86
states version  
oldnameminecraft:element_87val   
newnameminecraft:element_87
states version  
oldnameminecraft:element_88val   
newnameminecraft:element_88
states version  
oldnameminecraft:element_89val   
newnameminecraft:element_89
states version  
oldnameminecraft:element_9val   
newnameminecraft:element_9
states version  
oldnameminecraft:element_90val   
newnameminecraft:element_90
states version  
oldnameminecraft:element_91val   
newnameminecraft:element_91
states version  
oldnameminecraft:element_92val   
newnameminecraft:element_92
states version  
oldnameminecraft:element_93val   
newnameminecraft:element_93
states version  
oldnameminecraft:element_94val   
newnameminecraft:element_94
states version  
oldnameminecraft:element_95val   
newnameminecraft:element_95
states version  
oldnameminecraft:element_96val   
newnameminecraft:element_96
states version  
oldnameminecraft:element_97val   
newnameminecraft:element_97
states version  
oldnameminecraft:element_98val   
newnameminecraft:element_98
states version  
oldnameminecraft:element_99val   
newnameminecraft:element_99
states version  
oldnameminecraft:emerald_blockval   
newnameminecraft:emerald_block
states version  
oldnameminecraft:emerald_oreval   
newnameminecraft:emerald_ore
states version  
oldnameminecraft:enchanting_tableval   
newnameminecraft:enchanting_table
states version  
oldnameminecraft:end_brick_stairsval   
newnameminecraft:end_brick_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:end_brick_stairsval  
newnameminecraft:end_brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:end_brick_stairsval  
newnameminecraft:end_brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:end_brick_stairsval  
newnameminecraft:end_brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:end_brick_stairsval  
newnameminecraft:end_brick_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:end_brick_stairsval  
newnameminecraft:end_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:end_brick_stairsval  
newnameminecraft:end_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:end_brick_stairsval  
newnameminecraft:end_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:end_bricksval   
newnameminecraft:end_bricks
states version  
oldnameminecraft:end_gatewayval   
newnameminecraft:end_gateway
states version  
oldnameminecraft:end_portalval   
newnameminecraft:end_portal
states version  
oldnameminecraft:end_portal_frameval   
newnameminecraft:end_portal_frame
states	direction end_portal_eye_bit  version  
oldnameminecraft:end_portal_frameval  
newnameminecraft:end_portal_frame
states	directionend_portal_eye_bit  version  
oldnameminecraft:end_portal_frameval  
newnameminecraft:end_portal_frame
states	directionend_portal_eye_bit  version  
oldnameminecraft:end_portal_frameval  
newnameminecraft:end_portal_frame
states	directionend_portal_eye_bit  version  
oldnameminecraft:end_portal_frameval  
newnameminecraft:end_portal_frame
states	direction end_portal_eye_bit version  
oldnameminecraft:end_portal_frameval  
newnameminecraft:end_portal_frame
states	directionend_portal_eye_bit version  
oldnameminecraft:end_portal_frameval  
newnameminecraft:end_portal_frame
states	directionend_portal_eye_bit version  
oldnameminecraft:end_portal_frameval  
newnameminecraft:end_portal_frame
states	directionend_portal_eye_bit version  
oldnameminecraft:end_rodval   
newnameminecraft:end_rod
statesfacing_direction  version  
oldnameminecraft:end_rodval  
newnameminecraft:end_rod
statesfacing_direction version  
oldnameminecraft:end_rodval  
newnameminecraft:end_rod
statesfacing_direction version  
oldnameminecraft:end_rodval  
newnameminecraft:end_rod
statesfacing_direction version  
oldnameminecraft:end_rodval  
newnameminecraft:end_rod
statesfacing_direction version  
oldnameminecraft:end_rodval  
newnameminecraft:end_rod
statesfacing_direction
 version  
oldnameminecraft:end_rodval  
newnameminecraft:light_block
statesblock_light_level version  
oldnameminecraft:end_rodval  
newnameminecraft:light_block
statesblock_light_level version  
oldnameminecraft:end_stoneval   
newnameminecraft:end_stone
states version  
oldnameminecraft:ender_chestval   
newnameminecraft:ender_chest
statesfacing_direction  version  
oldnameminecraft:ender_chestval  
newnameminecraft:ender_chest
statesfacing_direction version  
oldnameminecraft:ender_chestval  
newnameminecraft:ender_chest
statesfacing_direction version  
oldnameminecraft:ender_chestval  
newnameminecraft:ender_chest
statesfacing_direction version  
oldnameminecraft:ender_chestval  
newnameminecraft:ender_chest
statesfacing_direction version  
oldnameminecraft:ender_chestval  
newnameminecraft:ender_chest
statesfacing_direction
 version  
oldnameminecraft:ender_chestval  
newnameminecraft:ender_chest
statesfacing_direction  version  
oldnameminecraft:ender_chestval  
newnameminecraft:ender_chest
statesfacing_direction  version  
oldnameminecraft:farmlandval   
newnameminecraft:farmland
statesmoisturized_amount  version  
oldnameminecraft:farmlandval  
newnameminecraft:farmland
statesmoisturized_amount version  
oldnameminecraft:farmlandval  
newnameminecraft:farmland
statesmoisturized_amount version  
oldnameminecraft:farmlandval  
newnameminecraft:farmland
statesmoisturized_amount version  
oldnameminecraft:farmlandval  
newnameminecraft:farmland
statesmoisturized_amount version  
oldnameminecraft:farmlandval  
newnameminecraft:farmland
statesmoisturized_amount
 version  
oldnameminecraft:farmlandval  
newnameminecraft:farmland
statesmoisturized_amount version  
oldnameminecraft:farmlandval  
newnameminecraft:farmland
statesmoisturized_amount version  
oldnameminecraft:fenceval   
newnameminecraft:fence
states	wood_typeoak version  
oldnameminecraft:fenceval  
newnameminecraft:fence
states	wood_typespruce version  
oldnameminecraft:fenceval  
newnameminecraft:fence
states	wood_typebirch version  
oldnameminecraft:fenceval  
newnameminecraft:fence
states	wood_typejungle version  
oldnameminecraft:fenceval  
newnameminecraft:fence
states	wood_typeacacia version  
oldnameminecraft:fenceval  
newnameminecraft:fence
states	wood_typedark_oak version  
oldnameminecraft:fenceval  
newnameminecraft:fence
states	wood_typeoak version  
oldnameminecraft:fenceval  
newnameminecraft:fence
states	wood_typeoak version  
oldnameminecraft:fence_gateval   
newnameminecraft:fence_gate
states	direction in_wall_bit open_bit  version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	direction in_wall_bit open_bit version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	direction in_wall_bitopen_bit  version  
oldnameminecraft:fence_gateval	  
newnameminecraft:fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:fence_gateval
  
newnameminecraft:fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	direction in_wall_bitopen_bit version  
oldnameminecraft:fence_gateval
  
newnameminecraft:fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:fence_gateval  
newnameminecraft:fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:fireval   
newnameminecraft:fire
statesage  version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage
 version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval	  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval
  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval
  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fireval  
newnameminecraft:fire
statesage version  
oldnameminecraft:fletching_tableval   
newnameminecraft:fletching_table
states version  
oldnameminecraft:flower_potval   
newnameminecraft:flower_pot
states
update_bit  version  
oldnameminecraft:flower_potval  
newnameminecraft:flower_pot
states
update_bit version  
oldnameminecraft:flowing_lavaval   
newnameminecraft:flowing_lava
statesliquid_depth  version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth
 version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval	  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval
  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval
  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_lavaval  
newnameminecraft:flowing_lava
statesliquid_depth version  
oldnameminecraft:flowing_waterval   
newnameminecraft:flowing_water
statesliquid_depth  version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth
 version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval	  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval
  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval
  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:flowing_waterval  
newnameminecraft:flowing_water
statesliquid_depth version  
oldnameminecraft:frameval   
newnameminecraft:frame
statesfacing_direction
item_frame_map_bit  version  
oldnameminecraft:frameval  
newnameminecraft:frame
statesfacing_directionitem_frame_map_bit  version  
oldnameminecraft:frameval  
newnameminecraft:frame
statesfacing_directionitem_frame_map_bit  version  
oldnameminecraft:frameval  
newnameminecraft:frame
statesfacing_directionitem_frame_map_bit  version  
oldnameminecraft:frameval  
newnameminecraft:frame
statesfacing_direction
item_frame_map_bit version  
oldnameminecraft:frameval  
newnameminecraft:frame
statesfacing_directionitem_frame_map_bit version  
oldnameminecraft:frameval  
newnameminecraft:frame
statesfacing_directionitem_frame_map_bit version  
oldnameminecraft:frameval  
newnameminecraft:frame
statesfacing_directionitem_frame_map_bit version  
oldnameminecraft:frosted_iceval   
newnameminecraft:frosted_ice
statesage  version  
oldnameminecraft:frosted_iceval  
newnameminecraft:frosted_ice
statesage version  
oldnameminecraft:frosted_iceval  
newnameminecraft:frosted_ice
statesage version  
oldnameminecraft:frosted_iceval  
newnameminecraft:frosted_ice
statesage version  
oldnameminecraft:furnaceval   
newnameminecraft:furnace
statesfacing_direction  version  
oldnameminecraft:furnaceval  
newnameminecraft:furnace
statesfacing_direction version  
oldnameminecraft:furnaceval  
newnameminecraft:furnace
statesfacing_direction version  
oldnameminecraft:furnaceval  
newnameminecraft:furnace
statesfacing_direction version  
oldnameminecraft:furnaceval  
newnameminecraft:furnace
statesfacing_direction version  
oldnameminecraft:furnaceval  
newnameminecraft:furnace
statesfacing_direction
 version  
oldnameminecraft:furnaceval  
newnameminecraft:furnace
statesfacing_direction  version  
oldnameminecraft:furnaceval  
newnameminecraft:furnace
statesfacing_direction  version  
oldnameminecraft:glassval   
newnameminecraft:glass
states version  
oldnameminecraft:glass_paneval   
newnameminecraft:glass_pane
states version  
oldnameminecraft:glowingobsidianval   
newnameminecraft:glowingobsidian
states version  
oldnameminecraft:glowstoneval   
newnameminecraft:glowstone
states version  
oldnameminecraft:gold_blockval   
newnameminecraft:gold_block
states version  
oldnameminecraft:gold_oreval   
newnameminecraft:gold_ore
states version  
oldnameminecraft:golden_railval   
newnameminecraft:golden_rail
states
rail_data_bit rail_direction  version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bit rail_direction version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bit rail_direction
 version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bit rail_direction  version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bit rail_direction  version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bitrail_direction  version  
oldnameminecraft:golden_railval	  
newnameminecraft:golden_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:golden_railval
  
newnameminecraft:golden_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bitrail_direction version  
oldnameminecraft:golden_railval
  
newnameminecraft:golden_rail
states
rail_data_bitrail_direction
 version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bitrail_direction  version  
oldnameminecraft:golden_railval  
newnameminecraft:golden_rail
states
rail_data_bitrail_direction  version  
oldnameminecraft:granite_stairsval   
newnameminecraft:granite_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:granite_stairsval  
newnameminecraft:granite_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:granite_stairsval  
newnameminecraft:granite_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:granite_stairsval  
newnameminecraft:granite_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:granite_stairsval  
newnameminecraft:granite_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:granite_stairsval  
newnameminecraft:granite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:granite_stairsval  
newnameminecraft:granite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:granite_stairsval  
newnameminecraft:granite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:grassval   
newnameminecraft:grass
states version  
oldnameminecraft:grass_pathval   
newnameminecraft:grass_path
states version  
oldnameminecraft:gravelval   
newnameminecraft:gravel
states version  
oldname minecraft:gray_glazed_terracottaval   
newname minecraft:gray_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:gray_glazed_terracottaval  
newname minecraft:gray_glazed_terracotta
statesfacing_direction version  
oldname minecraft:gray_glazed_terracottaval  
newname minecraft:gray_glazed_terracotta
statesfacing_direction version  
oldname minecraft:gray_glazed_terracottaval  
newname minecraft:gray_glazed_terracotta
statesfacing_direction version  
oldname minecraft:gray_glazed_terracottaval  
newname minecraft:gray_glazed_terracotta
statesfacing_direction version  
oldname minecraft:gray_glazed_terracottaval  
newname minecraft:gray_glazed_terracotta
statesfacing_direction
 version  
oldname minecraft:gray_glazed_terracottaval  
newname minecraft:gray_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:gray_glazed_terracottaval  
newname minecraft:gray_glazed_terracotta
statesfacing_direction  version  
oldname!minecraft:green_glazed_terracottaval   
newname!minecraft:green_glazed_terracotta
statesfacing_direction  version  
oldname!minecraft:green_glazed_terracottaval  
newname!minecraft:green_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:green_glazed_terracottaval  
newname!minecraft:green_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:green_glazed_terracottaval  
newname!minecraft:green_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:green_glazed_terracottaval  
newname!minecraft:green_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:green_glazed_terracottaval  
newname!minecraft:green_glazed_terracotta
statesfacing_direction
 version  
oldname!minecraft:green_glazed_terracottaval  
newname!minecraft:green_glazed_terracotta
statesfacing_direction  version  
oldname!minecraft:green_glazed_terracottaval  
newname!minecraft:green_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:grindstoneval   
newnameminecraft:grindstone
states
attachmentstanding	direction  version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmentstanding	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmentstanding	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmentstanding	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmenthanging	direction  version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmenthanging	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmenthanging	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmenthanging	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmentside	direction  version  
oldnameminecraft:grindstoneval	  
newnameminecraft:grindstone
states
attachmentside	direction version  
oldnameminecraft:grindstoneval
  
newnameminecraft:grindstone
states
attachmentside	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmentside	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmentmultiple	direction  version  
oldnameminecraft:grindstoneval
  
newnameminecraft:grindstone
states
attachmentmultiple	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmentmultiple	direction version  
oldnameminecraft:grindstoneval  
newnameminecraft:grindstone
states
attachmentmultiple	direction version  
oldnameminecraft:hard_glassval   
newnameminecraft:hard_glass
states version  
oldnameminecraft:hard_glass_paneval   
newnameminecraft:hard_glass_pane
states version  
oldnameminecraft:hard_stained_glassval   
newnameminecraft:hard_stained_glass
statescolorwhite version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolororange version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolormagenta version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolor
light_blue version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescoloryellow version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolorlime version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolorpink version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolorgray version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolorsilver version  
oldnameminecraft:hard_stained_glassval	  
newnameminecraft:hard_stained_glass
statescolorcyan version  
oldnameminecraft:hard_stained_glassval
  
newnameminecraft:hard_stained_glass
statescolorpurple version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolorblue version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolorbrown version  
oldnameminecraft:hard_stained_glassval
  
newnameminecraft:hard_stained_glass
statescolorgreen version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolorred version  
oldnameminecraft:hard_stained_glassval  
newnameminecraft:hard_stained_glass
statescolorblack version  
oldname!minecraft:hard_stained_glass_paneval   
newname!minecraft:hard_stained_glass_pane
statescolorwhite version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolororange version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolormagenta version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolor
light_blue version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescoloryellow version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolorlime version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolorpink version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolorgray version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolorsilver version  
oldname!minecraft:hard_stained_glass_paneval	  
newname!minecraft:hard_stained_glass_pane
statescolorcyan version  
oldname!minecraft:hard_stained_glass_paneval
  
newname!minecraft:hard_stained_glass_pane
statescolorpurple version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolorblue version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolorbrown version  
oldname!minecraft:hard_stained_glass_paneval
  
newname!minecraft:hard_stained_glass_pane
statescolorgreen version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolorred version  
oldname!minecraft:hard_stained_glass_paneval  
newname!minecraft:hard_stained_glass_pane
statescolorblack version  
oldnameminecraft:hardened_clayval   
newnameminecraft:hardened_clay
states version  
oldnameminecraft:hay_blockval   
newnameminecraft:hay_block
states
deprecated pillar_axisy version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecatedpillar_axisy version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecatedpillar_axisy version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecatedpillar_axisy version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecated pillar_axisx version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecatedpillar_axisx version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecatedpillar_axisx version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecatedpillar_axisx version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecated pillar_axisz version  
oldnameminecraft:hay_blockval	  
newnameminecraft:hay_block
states
deprecatedpillar_axisz version  
oldnameminecraft:hay_blockval
  
newnameminecraft:hay_block
states
deprecatedpillar_axisz version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecatedpillar_axisz version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecated pillar_axisy version  
oldnameminecraft:hay_blockval
  
newnameminecraft:hay_block
states
deprecatedpillar_axisy version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecatedpillar_axisy version  
oldnameminecraft:hay_blockval  
newnameminecraft:hay_block
states
deprecatedpillar_axisy version  
oldname'minecraft:heavy_weighted_pressure_plateval   
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal  version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal
 version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval	  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval
  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval
  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:heavy_weighted_pressure_plateval  
newname'minecraft:heavy_weighted_pressure_plate
statesredstone_signal version  
oldnameminecraft:hopperval   
newnameminecraft:hopper
statesfacing_direction 
toggle_bit  version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction
toggle_bit  version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction
toggle_bit  version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction
toggle_bit  version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction
toggle_bit  version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction

toggle_bit  version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction 
toggle_bit  version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction 
toggle_bit  version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction 
toggle_bit version  
oldnameminecraft:hopperval	  
newnameminecraft:hopper
statesfacing_direction
toggle_bit version  
oldnameminecraft:hopperval
  
newnameminecraft:hopper
statesfacing_direction
toggle_bit version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction
toggle_bit version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction
toggle_bit version  
oldnameminecraft:hopperval
  
newnameminecraft:hopper
statesfacing_direction

toggle_bit version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction 
toggle_bit version  
oldnameminecraft:hopperval  
newnameminecraft:hopper
statesfacing_direction 
toggle_bit version  
oldname
minecraft:iceval   
newname
minecraft:ice
states version  
oldnameminecraft:info_updateval   
newnameminecraft:info_update
states version  
oldnameminecraft:info_update2val   
newnameminecraft:info_update2
states version  
oldnameminecraft:invisibleBedrockval   
newnameminecraft:invisibleBedrock
states version  
oldnameminecraft:iron_barsval   
newnameminecraft:iron_bars
states version  
oldnameminecraft:iron_blockval   
newnameminecraft:iron_block
states version  
oldnameminecraft:iron_doorval   
newnameminecraft:iron_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:iron_doorval	  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:iron_doorval
  
newnameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:iron_doorval
  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:iron_doorval  
newnameminecraft:iron_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:iron_oreval   
newnameminecraft:iron_ore
states version  
oldnameminecraft:iron_trapdoorval   
newnameminecraft:iron_trapdoor
states	direction open_bit upside_down_bit  version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	direction open_bit upside_down_bit version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	direction open_bitupside_down_bit  version  
oldnameminecraft:iron_trapdoorval	  
newnameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:iron_trapdoorval
  
newnameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	direction open_bitupside_down_bit version  
oldnameminecraft:iron_trapdoorval
  
newnameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:iron_trapdoorval  
newnameminecraft:iron_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:jigsawval   
newnameminecraft:jigsaw
statesfacing_direction  version  
oldnameminecraft:jigsawval  
newnameminecraft:jigsaw
statesfacing_direction version  
oldnameminecraft:jigsawval  
newnameminecraft:jigsaw
statesfacing_direction version  
oldnameminecraft:jigsawval  
newnameminecraft:jigsaw
statesfacing_direction version  
oldnameminecraft:jigsawval  
newnameminecraft:jigsaw
statesfacing_direction version  
oldnameminecraft:jigsawval  
newnameminecraft:jigsaw
statesfacing_direction
 version  
oldnameminecraft:jigsawval  
newnameminecraft:jigsaw
statesfacing_direction  version  
oldnameminecraft:jigsawval  
newnameminecraft:jigsaw
statesfacing_direction  version  
oldnameminecraft:jukeboxval   
newnameminecraft:jukebox
states version  
oldnameminecraft:jungle_buttonval   
newnameminecraft:jungle_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bit facing_direction
 version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:jungle_buttonval	  
newnameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:jungle_buttonval
  
newnameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:jungle_buttonval
  
newnameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction
 version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:jungle_buttonval  
newnameminecraft:jungle_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:jungle_doorval   
newnameminecraft:jungle_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:jungle_doorval	  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:jungle_doorval
  
newnameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:jungle_doorval
  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:jungle_doorval  
newnameminecraft:jungle_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:jungle_fence_gateval   
newnameminecraft:jungle_fence_gate
states	direction in_wall_bit open_bit  version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	direction in_wall_bit open_bit version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	direction in_wall_bitopen_bit  version  
oldnameminecraft:jungle_fence_gateval	  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:jungle_fence_gateval
  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	direction in_wall_bitopen_bit version  
oldnameminecraft:jungle_fence_gateval
  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:jungle_fence_gateval  
newnameminecraft:jungle_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:jungle_pressure_plateval   
newnameminecraft:jungle_pressure_plate
statesredstone_signal  version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal
 version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval	  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval
  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval
  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_pressure_plateval  
newnameminecraft:jungle_pressure_plate
statesredstone_signal version  
oldnameminecraft:jungle_stairsval   
newnameminecraft:jungle_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:jungle_stairsval  
newnameminecraft:jungle_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:jungle_stairsval  
newnameminecraft:jungle_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:jungle_stairsval  
newnameminecraft:jungle_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:jungle_stairsval  
newnameminecraft:jungle_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:jungle_stairsval  
newnameminecraft:jungle_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:jungle_stairsval  
newnameminecraft:jungle_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:jungle_stairsval  
newnameminecraft:jungle_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:jungle_standing_signval   
newnameminecraft:jungle_standing_sign
statesground_sign_direction  version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction
 version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval	  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval
  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval
  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_standing_signval  
newnameminecraft:jungle_standing_sign
statesground_sign_direction version  
oldnameminecraft:jungle_trapdoorval   
newnameminecraft:jungle_trapdoor
states	direction open_bit upside_down_bit  version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	direction open_bit upside_down_bit version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	direction open_bitupside_down_bit  version  
oldnameminecraft:jungle_trapdoorval	  
newnameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:jungle_trapdoorval
  
newnameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	direction open_bitupside_down_bit version  
oldnameminecraft:jungle_trapdoorval
  
newnameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:jungle_trapdoorval  
newnameminecraft:jungle_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:jungle_wall_signval   
newnameminecraft:jungle_wall_sign
statesfacing_direction  version  
oldnameminecraft:jungle_wall_signval  
newnameminecraft:jungle_wall_sign
statesfacing_direction version  
oldnameminecraft:jungle_wall_signval  
newnameminecraft:jungle_wall_sign
statesfacing_direction version  
oldnameminecraft:jungle_wall_signval  
newnameminecraft:jungle_wall_sign
statesfacing_direction version  
oldnameminecraft:jungle_wall_signval  
newnameminecraft:jungle_wall_sign
statesfacing_direction version  
oldnameminecraft:jungle_wall_signval  
newnameminecraft:jungle_wall_sign
statesfacing_direction
 version  
oldnameminecraft:jungle_wall_signval  
newnameminecraft:jungle_wall_sign
statesfacing_direction  version  
oldnameminecraft:jungle_wall_signval  
newnameminecraft:jungle_wall_sign
statesfacing_direction  version  
oldnameminecraft:kelpval   
newnameminecraft:kelp
stateskelp_age  version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age
 version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval	  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval
  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval
  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:kelpval  
newnameminecraft:kelp
stateskelp_age version  
oldnameminecraft:ladderval   
newnameminecraft:ladder
statesfacing_direction  version  
oldnameminecraft:ladderval  
newnameminecraft:ladder
statesfacing_direction version  
oldnameminecraft:ladderval  
newnameminecraft:ladder
statesfacing_direction version  
oldnameminecraft:ladderval  
newnameminecraft:ladder
statesfacing_direction version  
oldnameminecraft:ladderval  
newnameminecraft:ladder
statesfacing_direction version  
oldnameminecraft:ladderval  
newnameminecraft:ladder
statesfacing_direction
 version  
oldnameminecraft:ladderval  
newnameminecraft:ladder
statesfacing_direction  version  
oldnameminecraft:ladderval  
newnameminecraft:ladder
statesfacing_direction  version  
oldnameminecraft:lanternval   
newnameminecraft:lantern
stateshanging  version  
oldnameminecraft:lanternval  
newnameminecraft:lantern
stateshanging version  
oldnameminecraft:lapis_blockval   
newnameminecraft:lapis_block
states version  
oldnameminecraft:lapis_oreval   
newnameminecraft:lapis_ore
states version  
oldnameminecraft:lavaval   
newnameminecraft:lava
statesliquid_depth  version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth
 version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval	  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval
  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval
  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lavaval  
newnameminecraft:lava
statesliquid_depth version  
oldnameminecraft:lava_cauldronval   
newnameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level  version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level
 version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidwater
fill_level version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level  version  
oldnameminecraft:lava_cauldronval	  
newnameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:lava_cauldronval
  
newnameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:lava_cauldronval
  
newnameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level
 version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:lava_cauldronval  
newnameminecraft:lava_cauldron
statescauldron_liquidlava
fill_level version  
oldnameminecraft:leavesval   
newnameminecraft:leaves
states
old_leaf_typeoakpersistent_bit 
update_bit  version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typesprucepersistent_bit 
update_bit  version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typebirchpersistent_bit 
update_bit  version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typejunglepersistent_bit 
update_bit  version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typeoakpersistent_bit 
update_bit version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typesprucepersistent_bit 
update_bit version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typebirchpersistent_bit 
update_bit version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typejunglepersistent_bit 
update_bit version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typeoakpersistent_bit
update_bit  version  
oldnameminecraft:leavesval	  
newnameminecraft:leaves
states
old_leaf_typesprucepersistent_bit
update_bit  version  
oldnameminecraft:leavesval
  
newnameminecraft:leaves
states
old_leaf_typebirchpersistent_bit
update_bit  version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typejunglepersistent_bit
update_bit  version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typeoakpersistent_bit
update_bit version  
oldnameminecraft:leavesval
  
newnameminecraft:leaves
states
old_leaf_typesprucepersistent_bit
update_bit version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typebirchpersistent_bit
update_bit version  
oldnameminecraft:leavesval  
newnameminecraft:leaves
states
old_leaf_typejunglepersistent_bit
update_bit version  
oldnameminecraft:leaves2val   
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit 
update_bit  version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typedark_oakpersistent_bit 
update_bit  version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit 
update_bit  version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit 
update_bit  version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit 
update_bit version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typedark_oakpersistent_bit 
update_bit version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit 
update_bit version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit 
update_bit version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit
update_bit  version  
oldnameminecraft:leaves2val	  
newnameminecraft:leaves2
states
new_leaf_typedark_oakpersistent_bit
update_bit  version  
oldnameminecraft:leaves2val
  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit
update_bit  version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit
update_bit  version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit
update_bit version  
oldnameminecraft:leaves2val
  
newnameminecraft:leaves2
states
new_leaf_typedark_oakpersistent_bit
update_bit version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit
update_bit version  
oldnameminecraft:leaves2val  
newnameminecraft:leaves2
states
new_leaf_typeacaciapersistent_bit
update_bit version  
oldnameminecraft:lecternval   
newnameminecraft:lectern
states	direction powered_bit  version  
oldnameminecraft:lecternval  
newnameminecraft:lectern
states	directionpowered_bit  version  
oldnameminecraft:lecternval  
newnameminecraft:lectern
states	directionpowered_bit  version  
oldnameminecraft:lecternval  
newnameminecraft:lectern
states	directionpowered_bit  version  
oldnameminecraft:lecternval  
newnameminecraft:lectern
states	direction powered_bit version  
oldnameminecraft:lecternval  
newnameminecraft:lectern
states	directionpowered_bit version  
oldnameminecraft:lecternval  
newnameminecraft:lectern
states	directionpowered_bit version  
oldnameminecraft:lecternval  
newnameminecraft:lectern
states	directionpowered_bit version  
oldnameminecraft:leverval   
newnameminecraft:lever
stateslever_directiondown_east_westopen_bit  version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directioneastopen_bit  version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directionwestopen_bit  version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directionsouthopen_bit  version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directionnorthopen_bit  version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directionup_north_southopen_bit  version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directionup_east_westopen_bit  version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directiondown_north_southopen_bit  version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directiondown_east_westopen_bit version  
oldnameminecraft:leverval	  
newnameminecraft:lever
stateslever_directioneastopen_bit version  
oldnameminecraft:leverval
  
newnameminecraft:lever
stateslever_directionwestopen_bit version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directionsouthopen_bit version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directionnorthopen_bit version  
oldnameminecraft:leverval
  
newnameminecraft:lever
stateslever_directionup_north_southopen_bit version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directionup_east_westopen_bit version  
oldnameminecraft:leverval  
newnameminecraft:lever
stateslever_directiondown_north_southopen_bit version  
oldname&minecraft:light_blue_glazed_terracottaval   
newname&minecraft:light_blue_glazed_terracotta
statesfacing_direction  version  
oldname&minecraft:light_blue_glazed_terracottaval  
newname&minecraft:light_blue_glazed_terracotta
statesfacing_direction version  
oldname&minecraft:light_blue_glazed_terracottaval  
newname&minecraft:light_blue_glazed_terracotta
statesfacing_direction version  
oldname&minecraft:light_blue_glazed_terracottaval  
newname&minecraft:light_blue_glazed_terracotta
statesfacing_direction version  
oldname&minecraft:light_blue_glazed_terracottaval  
newname&minecraft:light_blue_glazed_terracotta
statesfacing_direction version  
oldname&minecraft:light_blue_glazed_terracottaval  
newname&minecraft:light_blue_glazed_terracotta
statesfacing_direction
 version  
oldname&minecraft:light_blue_glazed_terracottaval  
newname&minecraft:light_blue_glazed_terracotta
statesfacing_direction  version  
oldname&minecraft:light_blue_glazed_terracottaval  
newname&minecraft:light_blue_glazed_terracotta
statesfacing_direction  version  
oldname'minecraft:light_weighted_pressure_plateval   
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal  version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal
 version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval	  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval
  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval
  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname'minecraft:light_weighted_pressure_plateval  
newname'minecraft:light_weighted_pressure_plate
statesredstone_signal version  
oldname minecraft:lime_glazed_terracottaval   
newname minecraft:lime_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:lime_glazed_terracottaval  
newname minecraft:lime_glazed_terracotta
statesfacing_direction version  
oldname minecraft:lime_glazed_terracottaval  
newname minecraft:lime_glazed_terracotta
statesfacing_direction version  
oldname minecraft:lime_glazed_terracottaval  
newname minecraft:lime_glazed_terracotta
statesfacing_direction version  
oldname minecraft:lime_glazed_terracottaval  
newname minecraft:lime_glazed_terracotta
statesfacing_direction version  
oldname minecraft:lime_glazed_terracottaval  
newname minecraft:lime_glazed_terracotta
statesfacing_direction
 version  
oldname minecraft:lime_glazed_terracottaval  
newname minecraft:lime_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:lime_glazed_terracottaval  
newname minecraft:lime_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:lit_blast_furnaceval   
newnameminecraft:lit_blast_furnace
statesfacing_direction  version  
oldnameminecraft:lit_blast_furnaceval  
newnameminecraft:lit_blast_furnace
statesfacing_direction version  
oldnameminecraft:lit_blast_furnaceval  
newnameminecraft:lit_blast_furnace
statesfacing_direction version  
oldnameminecraft:lit_blast_furnaceval  
newnameminecraft:lit_blast_furnace
statesfacing_direction version  
oldnameminecraft:lit_blast_furnaceval  
newnameminecraft:lit_blast_furnace
statesfacing_direction version  
oldnameminecraft:lit_blast_furnaceval  
newnameminecraft:lit_blast_furnace
statesfacing_direction
 version  
oldnameminecraft:lit_blast_furnaceval  
newnameminecraft:lit_blast_furnace
statesfacing_direction  version  
oldnameminecraft:lit_blast_furnaceval  
newnameminecraft:lit_blast_furnace
statesfacing_direction  version  
oldnameminecraft:lit_furnaceval   
newnameminecraft:lit_furnace
statesfacing_direction  version  
oldnameminecraft:lit_furnaceval  
newnameminecraft:lit_furnace
statesfacing_direction version  
oldnameminecraft:lit_furnaceval  
newnameminecraft:lit_furnace
statesfacing_direction version  
oldnameminecraft:lit_furnaceval  
newnameminecraft:lit_furnace
statesfacing_direction version  
oldnameminecraft:lit_furnaceval  
newnameminecraft:lit_furnace
statesfacing_direction version  
oldnameminecraft:lit_furnaceval  
newnameminecraft:lit_furnace
statesfacing_direction
 version  
oldnameminecraft:lit_furnaceval  
newnameminecraft:lit_furnace
statesfacing_direction  version  
oldnameminecraft:lit_furnaceval  
newnameminecraft:lit_furnace
statesfacing_direction  version  
oldnameminecraft:lit_pumpkinval   
newnameminecraft:lit_pumpkin
states	direction  version  
oldnameminecraft:lit_pumpkinval  
newnameminecraft:lit_pumpkin
states	direction version  
oldnameminecraft:lit_pumpkinval  
newnameminecraft:lit_pumpkin
states	direction version  
oldnameminecraft:lit_pumpkinval  
newnameminecraft:lit_pumpkin
states	direction version  
oldnameminecraft:lit_redstone_lampval   
newnameminecraft:lit_redstone_lamp
states version  
oldnameminecraft:lit_redstone_oreval   
newnameminecraft:lit_redstone_ore
states version  
oldnameminecraft:lit_smokerval   
newnameminecraft:lit_smoker
statesfacing_direction  version  
oldnameminecraft:lit_smokerval  
newnameminecraft:lit_smoker
statesfacing_direction version  
oldnameminecraft:lit_smokerval  
newnameminecraft:lit_smoker
statesfacing_direction version  
oldnameminecraft:lit_smokerval  
newnameminecraft:lit_smoker
statesfacing_direction version  
oldnameminecraft:lit_smokerval  
newnameminecraft:lit_smoker
statesfacing_direction version  
oldnameminecraft:lit_smokerval  
newnameminecraft:lit_smoker
statesfacing_direction
 version  
oldnameminecraft:lit_smokerval  
newnameminecraft:lit_smoker
statesfacing_direction  version  
oldnameminecraft:lit_smokerval  
newnameminecraft:lit_smoker
statesfacing_direction  version  
oldname
minecraft:logval   
newname
minecraft:log
statesold_log_typeoakpillar_axisy version  
oldname
minecraft:logval  
newname
minecraft:log
statesold_log_typesprucepillar_axisy version  
oldname
minecraft:logval  
newname
minecraft:log
statesold_log_typebirchpillar_axisy version  
oldname
minecraft:logval  
newname
minecraft:log
statesold_log_typejunglepillar_axisy version  
oldname
minecraft:logval  
newname
minecraft:log
statesold_log_typeoakpillar_axisx version  
oldname
minecraft:logval  
newname
minecraft:log
statesold_log_typesprucepillar_axisx version  
oldname
minecraft:logval  
newname
minecraft:log
statesold_log_typebirchpillar_axisx version  
oldname
minecraft:logval  
newname
minecraft:log
statesold_log_typejunglepillar_axisx version  
oldname
minecraft:logval  
newname
minecraft:log
statesold_log_typeoakpillar_axisz version  
oldname
minecraft:logval	  
newname
minecraft:log
statesold_log_typesprucepillar_axisz version  
oldname
minecraft:logval
  
newname
minecraft:log
statesold_log_typebirchpillar_axisz version  
oldname
minecraft:logval  
newname
minecraft:log
statesold_log_typejunglepillar_axisz version  
oldname
minecraft:logval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typeoak version  
oldname
minecraft:logval
  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typespruce version  
oldname
minecraft:logval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typebirch version  
oldname
minecraft:logval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typejungle version  
oldnameminecraft:log2val   
newnameminecraft:log2
statesnew_log_typeacaciapillar_axisy version  
oldnameminecraft:log2val  
newnameminecraft:log2
statesnew_log_typedark_oakpillar_axisy version  
oldnameminecraft:log2val  
newnameminecraft:log2
statesnew_log_typeacaciapillar_axisy version  
oldnameminecraft:log2val  
newnameminecraft:log2
statesnew_log_typeacaciapillar_axisy version  
oldnameminecraft:log2val  
newnameminecraft:log2
statesnew_log_typeacaciapillar_axisx version  
oldnameminecraft:log2val  
newnameminecraft:log2
statesnew_log_typedark_oakpillar_axisx version  
oldnameminecraft:log2val  
newnameminecraft:log2
statesnew_log_typeacaciapillar_axisx version  
oldnameminecraft:log2val  
newnameminecraft:log2
statesnew_log_typeacaciapillar_axisx version  
oldnameminecraft:log2val  
newnameminecraft:log2
statesnew_log_typeacaciapillar_axisz version  
oldnameminecraft:log2val	  
newnameminecraft:log2
statesnew_log_typedark_oakpillar_axisz version  
oldnameminecraft:log2val
  
newnameminecraft:log2
statesnew_log_typeacaciapillar_axisz version  
oldnameminecraft:log2val  
newnameminecraft:log2
statesnew_log_typeacaciapillar_axisz version  
oldnameminecraft:log2val  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typeacacia version  
oldnameminecraft:log2val
  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typedark_oak version  
oldnameminecraft:log2val  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typeacacia version  
oldnameminecraft:log2val  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typeacacia version  
oldnameminecraft:loomval   
newnameminecraft:loom
states	direction  version  
oldnameminecraft:loomval  
newnameminecraft:loom
states	direction version  
oldnameminecraft:loomval  
newnameminecraft:loom
states	direction version  
oldnameminecraft:loomval  
newnameminecraft:loom
states	direction version  
oldname#minecraft:magenta_glazed_terracottaval   
newname#minecraft:magenta_glazed_terracotta
statesfacing_direction  version  
oldname#minecraft:magenta_glazed_terracottaval  
newname#minecraft:magenta_glazed_terracotta
statesfacing_direction version  
oldname#minecraft:magenta_glazed_terracottaval  
newname#minecraft:magenta_glazed_terracotta
statesfacing_direction version  
oldname#minecraft:magenta_glazed_terracottaval  
newname#minecraft:magenta_glazed_terracotta
statesfacing_direction version  
oldname#minecraft:magenta_glazed_terracottaval  
newname#minecraft:magenta_glazed_terracotta
statesfacing_direction version  
oldname#minecraft:magenta_glazed_terracottaval  
newname#minecraft:magenta_glazed_terracotta
statesfacing_direction
 version  
oldname#minecraft:magenta_glazed_terracottaval  
newname#minecraft:magenta_glazed_terracotta
statesfacing_direction  version  
oldname#minecraft:magenta_glazed_terracottaval  
newname#minecraft:magenta_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:magmaval   
newnameminecraft:magma
states version  
oldnameminecraft:melon_blockval   
newnameminecraft:melon_block
states version  
oldnameminecraft:melon_stemval   
newnameminecraft:melon_stem
statesgrowth  version  
oldnameminecraft:melon_stemval  
newnameminecraft:melon_stem
statesgrowth version  
oldnameminecraft:melon_stemval  
newnameminecraft:melon_stem
statesgrowth version  
oldnameminecraft:melon_stemval  
newnameminecraft:melon_stem
statesgrowth version  
oldnameminecraft:melon_stemval  
newnameminecraft:melon_stem
statesgrowth version  
oldnameminecraft:melon_stemval  
newnameminecraft:melon_stem
statesgrowth
 version  
oldnameminecraft:melon_stemval  
newnameminecraft:melon_stem
statesgrowth version  
oldnameminecraft:melon_stemval  
newnameminecraft:melon_stem
statesgrowth version  
oldnameminecraft:mob_spawnerval   
newnameminecraft:mob_spawner
states version  
oldnameminecraft:monster_eggval   
newnameminecraft:monster_egg
statesmonster_egg_stone_typestone version  
oldnameminecraft:monster_eggval  
newnameminecraft:monster_egg
statesmonster_egg_stone_typecobblestone version  
oldnameminecraft:monster_eggval  
newnameminecraft:monster_egg
statesmonster_egg_stone_typestone_brick version  
oldnameminecraft:monster_eggval  
newnameminecraft:monster_egg
statesmonster_egg_stone_typemossy_stone_brick version  
oldnameminecraft:monster_eggval  
newnameminecraft:monster_egg
statesmonster_egg_stone_typecracked_stone_brick version  
oldnameminecraft:monster_eggval  
newnameminecraft:monster_egg
statesmonster_egg_stone_typechiseled_stone_brick version  
oldnameminecraft:monster_eggval  
newnameminecraft:monster_egg
statesmonster_egg_stone_typestone version  
oldnameminecraft:monster_eggval  
newnameminecraft:monster_egg
statesmonster_egg_stone_typestone version  
oldnameminecraft:mossy_cobblestoneval   
newnameminecraft:mossy_cobblestone
states version  
oldname"minecraft:mossy_cobblestone_stairsval   
newname"minecraft:mossy_cobblestone_stairs
statesupside_down_bit weirdo_direction  version  
oldname"minecraft:mossy_cobblestone_stairsval  
newname"minecraft:mossy_cobblestone_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:mossy_cobblestone_stairsval  
newname"minecraft:mossy_cobblestone_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:mossy_cobblestone_stairsval  
newname"minecraft:mossy_cobblestone_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:mossy_cobblestone_stairsval  
newname"minecraft:mossy_cobblestone_stairs
statesupside_down_bitweirdo_direction  version  
oldname"minecraft:mossy_cobblestone_stairsval  
newname"minecraft:mossy_cobblestone_stairs
statesupside_down_bitweirdo_direction version  
oldname"minecraft:mossy_cobblestone_stairsval  
newname"minecraft:mossy_cobblestone_stairs
statesupside_down_bitweirdo_direction version  
oldname"minecraft:mossy_cobblestone_stairsval  
newname"minecraft:mossy_cobblestone_stairs
statesupside_down_bitweirdo_direction version  
oldname"minecraft:mossy_stone_brick_stairsval   
newname"minecraft:mossy_stone_brick_stairs
statesupside_down_bit weirdo_direction  version  
oldname"minecraft:mossy_stone_brick_stairsval  
newname"minecraft:mossy_stone_brick_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:mossy_stone_brick_stairsval  
newname"minecraft:mossy_stone_brick_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:mossy_stone_brick_stairsval  
newname"minecraft:mossy_stone_brick_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:mossy_stone_brick_stairsval  
newname"minecraft:mossy_stone_brick_stairs
statesupside_down_bitweirdo_direction  version  
oldname"minecraft:mossy_stone_brick_stairsval  
newname"minecraft:mossy_stone_brick_stairs
statesupside_down_bitweirdo_direction version  
oldname"minecraft:mossy_stone_brick_stairsval  
newname"minecraft:mossy_stone_brick_stairs
statesupside_down_bitweirdo_direction version  
oldname"minecraft:mossy_stone_brick_stairsval  
newname"minecraft:mossy_stone_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:movingBlockval   
newnameminecraft:movingBlock
states version  
oldnameminecraft:myceliumval   
newnameminecraft:mycelium
states version  
oldnameminecraft:nether_brickval   
newnameminecraft:nether_brick
states version  
oldnameminecraft:nether_brick_fenceval   
newnameminecraft:nether_brick_fence
states version  
oldnameminecraft:nether_brick_stairsval   
newnameminecraft:nether_brick_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:nether_brick_stairsval  
newnameminecraft:nether_brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:nether_brick_stairsval  
newnameminecraft:nether_brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:nether_brick_stairsval  
newnameminecraft:nether_brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:nether_brick_stairsval  
newnameminecraft:nether_brick_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:nether_brick_stairsval  
newnameminecraft:nether_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:nether_brick_stairsval  
newnameminecraft:nether_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:nether_brick_stairsval  
newnameminecraft:nether_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:nether_wartval   
newnameminecraft:nether_wart
statesage  version  
oldnameminecraft:nether_wartval  
newnameminecraft:nether_wart
statesage version  
oldnameminecraft:nether_wartval  
newnameminecraft:nether_wart
statesage version  
oldnameminecraft:nether_wartval  
newnameminecraft:nether_wart
statesage version  
oldnameminecraft:nether_wart_blockval   
newnameminecraft:nether_wart_block
states version  
oldnameminecraft:netherrackval   
newnameminecraft:netherrack
states version  
oldnameminecraft:netherreactorval   
newnameminecraft:netherreactor
states version  
oldnameminecraft:normal_stone_stairsval   
newnameminecraft:normal_stone_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:normal_stone_stairsval  
newnameminecraft:normal_stone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:normal_stone_stairsval  
newnameminecraft:normal_stone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:normal_stone_stairsval  
newnameminecraft:normal_stone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:normal_stone_stairsval  
newnameminecraft:normal_stone_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:normal_stone_stairsval  
newnameminecraft:normal_stone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:normal_stone_stairsval  
newnameminecraft:normal_stone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:normal_stone_stairsval  
newnameminecraft:normal_stone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:noteblockval   
newnameminecraft:noteblock
states version  
oldnameminecraft:oak_stairsval   
newnameminecraft:oak_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:oak_stairsval  
newnameminecraft:oak_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:oak_stairsval  
newnameminecraft:oak_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:oak_stairsval  
newnameminecraft:oak_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:oak_stairsval  
newnameminecraft:oak_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:oak_stairsval  
newnameminecraft:oak_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:oak_stairsval  
newnameminecraft:oak_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:oak_stairsval  
newnameminecraft:oak_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:observerval   
newnameminecraft:observer
statesfacing_direction powered_bit  version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_directionpowered_bit  version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_directionpowered_bit  version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_directionpowered_bit  version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_directionpowered_bit  version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_direction
powered_bit  version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_direction powered_bit  version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_direction powered_bit  version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_direction powered_bit version  
oldnameminecraft:observerval	  
newnameminecraft:observer
statesfacing_directionpowered_bit version  
oldnameminecraft:observerval
  
newnameminecraft:observer
statesfacing_directionpowered_bit version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_directionpowered_bit version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_directionpowered_bit version  
oldnameminecraft:observerval
  
newnameminecraft:observer
statesfacing_direction
powered_bit version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_direction powered_bit version  
oldnameminecraft:observerval  
newnameminecraft:observer
statesfacing_direction powered_bit version  
oldnameminecraft:obsidianval   
newnameminecraft:obsidian
states version  
oldname"minecraft:orange_glazed_terracottaval   
newname"minecraft:orange_glazed_terracotta
statesfacing_direction  version  
oldname"minecraft:orange_glazed_terracottaval  
newname"minecraft:orange_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:orange_glazed_terracottaval  
newname"minecraft:orange_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:orange_glazed_terracottaval  
newname"minecraft:orange_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:orange_glazed_terracottaval  
newname"minecraft:orange_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:orange_glazed_terracottaval  
newname"minecraft:orange_glazed_terracotta
statesfacing_direction
 version  
oldname"minecraft:orange_glazed_terracottaval  
newname"minecraft:orange_glazed_terracotta
statesfacing_direction  version  
oldname"minecraft:orange_glazed_terracottaval  
newname"minecraft:orange_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:packed_iceval   
newnameminecraft:packed_ice
states version  
oldname minecraft:pink_glazed_terracottaval   
newname minecraft:pink_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:pink_glazed_terracottaval  
newname minecraft:pink_glazed_terracotta
statesfacing_direction version  
oldname minecraft:pink_glazed_terracottaval  
newname minecraft:pink_glazed_terracotta
statesfacing_direction version  
oldname minecraft:pink_glazed_terracottaval  
newname minecraft:pink_glazed_terracotta
statesfacing_direction version  
oldname minecraft:pink_glazed_terracottaval  
newname minecraft:pink_glazed_terracotta
statesfacing_direction version  
oldname minecraft:pink_glazed_terracottaval  
newname minecraft:pink_glazed_terracotta
statesfacing_direction
 version  
oldname minecraft:pink_glazed_terracottaval  
newname minecraft:pink_glazed_terracotta
statesfacing_direction  version  
oldname minecraft:pink_glazed_terracottaval  
newname minecraft:pink_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:pistonval   
newnameminecraft:piston
statesfacing_direction  version  
oldnameminecraft:pistonval  
newnameminecraft:piston
statesfacing_direction version  
oldnameminecraft:pistonval  
newnameminecraft:piston
statesfacing_direction version  
oldnameminecraft:pistonval  
newnameminecraft:piston
statesfacing_direction version  
oldnameminecraft:pistonval  
newnameminecraft:piston
statesfacing_direction version  
oldnameminecraft:pistonval  
newnameminecraft:piston
statesfacing_direction
 version  
oldnameminecraft:pistonval  
newnameminecraft:piston
statesfacing_direction  version  
oldnameminecraft:pistonval  
newnameminecraft:piston
statesfacing_direction  version  
oldnameminecraft:pistonArmCollisionval   
newnameminecraft:pistonArmCollision
statesfacing_direction  version  
oldnameminecraft:pistonArmCollisionval  
newnameminecraft:pistonArmCollision
statesfacing_direction version  
oldnameminecraft:pistonArmCollisionval  
newnameminecraft:pistonArmCollision
statesfacing_direction version  
oldnameminecraft:pistonArmCollisionval  
newnameminecraft:pistonArmCollision
statesfacing_direction version  
oldnameminecraft:pistonArmCollisionval  
newnameminecraft:pistonArmCollision
statesfacing_direction version  
oldnameminecraft:pistonArmCollisionval  
newnameminecraft:pistonArmCollision
statesfacing_direction
 version  
oldnameminecraft:pistonArmCollisionval  
newnameminecraft:pistonArmCollision
statesfacing_direction  version  
oldnameminecraft:pistonArmCollisionval  
newnameminecraft:pistonArmCollision
statesfacing_direction  version  
oldnameminecraft:planksval   
newnameminecraft:planks
states	wood_typeoak version  
oldnameminecraft:planksval  
newnameminecraft:planks
states	wood_typespruce version  
oldnameminecraft:planksval  
newnameminecraft:planks
states	wood_typebirch version  
oldnameminecraft:planksval  
newnameminecraft:planks
states	wood_typejungle version  
oldnameminecraft:planksval  
newnameminecraft:planks
states	wood_typeacacia version  
oldnameminecraft:planksval  
newnameminecraft:planks
states	wood_typedark_oak version  
oldnameminecraft:planksval  
newnameminecraft:planks
states	wood_typeoak version  
oldnameminecraft:planksval  
newnameminecraft:planks
states	wood_typeoak version  
oldnameminecraft:podzolval   
newnameminecraft:podzol
states version  
oldname"minecraft:polished_andesite_stairsval   
newname"minecraft:polished_andesite_stairs
statesupside_down_bit weirdo_direction  version  
oldname"minecraft:polished_andesite_stairsval  
newname"minecraft:polished_andesite_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:polished_andesite_stairsval  
newname"minecraft:polished_andesite_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:polished_andesite_stairsval  
newname"minecraft:polished_andesite_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:polished_andesite_stairsval  
newname"minecraft:polished_andesite_stairs
statesupside_down_bitweirdo_direction  version  
oldname"minecraft:polished_andesite_stairsval  
newname"minecraft:polished_andesite_stairs
statesupside_down_bitweirdo_direction version  
oldname"minecraft:polished_andesite_stairsval  
newname"minecraft:polished_andesite_stairs
statesupside_down_bitweirdo_direction version  
oldname"minecraft:polished_andesite_stairsval  
newname"minecraft:polished_andesite_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:polished_diorite_stairsval   
newname!minecraft:polished_diorite_stairs
statesupside_down_bit weirdo_direction  version  
oldname!minecraft:polished_diorite_stairsval  
newname!minecraft:polished_diorite_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:polished_diorite_stairsval  
newname!minecraft:polished_diorite_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:polished_diorite_stairsval  
newname!minecraft:polished_diorite_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:polished_diorite_stairsval  
newname!minecraft:polished_diorite_stairs
statesupside_down_bitweirdo_direction  version  
oldname!minecraft:polished_diorite_stairsval  
newname!minecraft:polished_diorite_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:polished_diorite_stairsval  
newname!minecraft:polished_diorite_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:polished_diorite_stairsval  
newname!minecraft:polished_diorite_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:polished_granite_stairsval   
newname!minecraft:polished_granite_stairs
statesupside_down_bit weirdo_direction  version  
oldname!minecraft:polished_granite_stairsval  
newname!minecraft:polished_granite_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:polished_granite_stairsval  
newname!minecraft:polished_granite_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:polished_granite_stairsval  
newname!minecraft:polished_granite_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:polished_granite_stairsval  
newname!minecraft:polished_granite_stairs
statesupside_down_bitweirdo_direction  version  
oldname!minecraft:polished_granite_stairsval  
newname!minecraft:polished_granite_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:polished_granite_stairsval  
newname!minecraft:polished_granite_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:polished_granite_stairsval  
newname!minecraft:polished_granite_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:portalval   
newnameminecraft:portal
statesportal_axisunknown version  
oldnameminecraft:portalval  
newnameminecraft:portal
statesportal_axisx version  
oldnameminecraft:portalval  
newnameminecraft:portal
statesportal_axisz version  
oldnameminecraft:portalval  
newnameminecraft:portal
statesportal_axisunknown version  
oldnameminecraft:potatoesval   
newnameminecraft:potatoes
statesgrowth  version  
oldnameminecraft:potatoesval  
newnameminecraft:potatoes
statesgrowth version  
oldnameminecraft:potatoesval  
newnameminecraft:potatoes
statesgrowth version  
oldnameminecraft:potatoesval  
newnameminecraft:potatoes
statesgrowth version  
oldnameminecraft:potatoesval  
newnameminecraft:potatoes
statesgrowth version  
oldnameminecraft:potatoesval  
newnameminecraft:potatoes
statesgrowth
 version  
oldnameminecraft:potatoesval  
newnameminecraft:potatoes
statesgrowth version  
oldnameminecraft:potatoesval  
newnameminecraft:potatoes
statesgrowth version  
oldnameminecraft:powered_comparatorval   
newnameminecraft:powered_comparator
states	direction output_lit_bit output_subtract_bit  version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit  version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit  version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit  version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	direction output_lit_bit output_subtract_bit version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	directionoutput_lit_bit output_subtract_bit version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	direction output_lit_bitoutput_subtract_bit  version  
oldnameminecraft:powered_comparatorval	  
newnameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version  
oldnameminecraft:powered_comparatorval
  
newnameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	direction output_lit_bitoutput_subtract_bit version  
oldnameminecraft:powered_comparatorval
  
newnameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version  
oldnameminecraft:powered_comparatorval  
newnameminecraft:powered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version  
oldnameminecraft:powered_repeaterval   
newnameminecraft:powered_repeater
states	direction repeater_delay  version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	directionrepeater_delay  version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	directionrepeater_delay  version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	directionrepeater_delay  version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	direction repeater_delay version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	directionrepeater_delay version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	directionrepeater_delay version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	directionrepeater_delay version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	direction repeater_delay version  
oldnameminecraft:powered_repeaterval	  
newnameminecraft:powered_repeater
states	directionrepeater_delay version  
oldnameminecraft:powered_repeaterval
  
newnameminecraft:powered_repeater
states	directionrepeater_delay version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	directionrepeater_delay version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	direction repeater_delay version  
oldnameminecraft:powered_repeaterval
  
newnameminecraft:powered_repeater
states	directionrepeater_delay version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	directionrepeater_delay version  
oldnameminecraft:powered_repeaterval  
newnameminecraft:powered_repeater
states	directionrepeater_delay version  
oldnameminecraft:prismarineval   
newnameminecraft:prismarine
statesprismarine_block_typedefault version  
oldnameminecraft:prismarineval  
newnameminecraft:prismarine
statesprismarine_block_typedark version  
oldnameminecraft:prismarineval  
newnameminecraft:prismarine
statesprismarine_block_typebricks version  
oldnameminecraft:prismarineval  
newnameminecraft:prismarine
statesprismarine_block_typedefault version  
oldname"minecraft:prismarine_bricks_stairsval   
newname"minecraft:prismarine_bricks_stairs
statesupside_down_bit weirdo_direction  version  
oldname"minecraft:prismarine_bricks_stairsval  
newname"minecraft:prismarine_bricks_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:prismarine_bricks_stairsval  
newname"minecraft:prismarine_bricks_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:prismarine_bricks_stairsval  
newname"minecraft:prismarine_bricks_stairs
statesupside_down_bit weirdo_direction version  
oldname"minecraft:prismarine_bricks_stairsval  
newname"minecraft:prismarine_bricks_stairs
statesupside_down_bitweirdo_direction  version  
oldname"minecraft:prismarine_bricks_stairsval  
newname"minecraft:prismarine_bricks_stairs
statesupside_down_bitweirdo_direction version  
oldname"minecraft:prismarine_bricks_stairsval  
newname"minecraft:prismarine_bricks_stairs
statesupside_down_bitweirdo_direction version  
oldname"minecraft:prismarine_bricks_stairsval  
newname"minecraft:prismarine_bricks_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:prismarine_stairsval   
newnameminecraft:prismarine_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:prismarine_stairsval  
newnameminecraft:prismarine_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:prismarine_stairsval  
newnameminecraft:prismarine_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:prismarine_stairsval  
newnameminecraft:prismarine_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:prismarine_stairsval  
newnameminecraft:prismarine_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:prismarine_stairsval  
newnameminecraft:prismarine_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:prismarine_stairsval  
newnameminecraft:prismarine_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:prismarine_stairsval  
newnameminecraft:prismarine_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:pumpkinval   
newnameminecraft:pumpkin
states	direction  version  
oldnameminecraft:pumpkinval  
newnameminecraft:pumpkin
states	direction version  
oldnameminecraft:pumpkinval  
newnameminecraft:pumpkin
states	direction version  
oldnameminecraft:pumpkinval  
newnameminecraft:pumpkin
states	direction version  
oldnameminecraft:pumpkin_stemval   
newnameminecraft:pumpkin_stem
statesgrowth  version  
oldnameminecraft:pumpkin_stemval  
newnameminecraft:pumpkin_stem
statesgrowth version  
oldnameminecraft:pumpkin_stemval  
newnameminecraft:pumpkin_stem
statesgrowth version  
oldnameminecraft:pumpkin_stemval  
newnameminecraft:pumpkin_stem
statesgrowth version  
oldnameminecraft:pumpkin_stemval  
newnameminecraft:pumpkin_stem
statesgrowth version  
oldnameminecraft:pumpkin_stemval  
newnameminecraft:pumpkin_stem
statesgrowth
 version  
oldnameminecraft:pumpkin_stemval  
newnameminecraft:pumpkin_stem
statesgrowth version  
oldnameminecraft:pumpkin_stemval  
newnameminecraft:pumpkin_stem
statesgrowth version  
oldname"minecraft:purple_glazed_terracottaval   
newname"minecraft:purple_glazed_terracotta
statesfacing_direction  version  
oldname"minecraft:purple_glazed_terracottaval  
newname"minecraft:purple_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:purple_glazed_terracottaval  
newname"minecraft:purple_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:purple_glazed_terracottaval  
newname"minecraft:purple_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:purple_glazed_terracottaval  
newname"minecraft:purple_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:purple_glazed_terracottaval  
newname"minecraft:purple_glazed_terracotta
statesfacing_direction
 version  
oldname"minecraft:purple_glazed_terracottaval  
newname"minecraft:purple_glazed_terracotta
statesfacing_direction  version  
oldname"minecraft:purple_glazed_terracottaval  
newname"minecraft:purple_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:purpur_blockval   
newnameminecraft:purpur_block
stateschisel_typedefaultpillar_axisy version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typechiseledpillar_axisy version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typelinespillar_axisy version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typesmoothpillar_axisy version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typedefaultpillar_axisx version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typechiseledpillar_axisx version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typelinespillar_axisx version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typesmoothpillar_axisx version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typedefaultpillar_axisz version  
oldnameminecraft:purpur_blockval	  
newnameminecraft:purpur_block
stateschisel_typechiseledpillar_axisz version  
oldnameminecraft:purpur_blockval
  
newnameminecraft:purpur_block
stateschisel_typelinespillar_axisz version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typesmoothpillar_axisz version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typedefaultpillar_axisy version  
oldnameminecraft:purpur_blockval
  
newnameminecraft:purpur_block
stateschisel_typechiseledpillar_axisy version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typelinespillar_axisy version  
oldnameminecraft:purpur_blockval  
newnameminecraft:purpur_block
stateschisel_typesmoothpillar_axisy version  
oldnameminecraft:purpur_stairsval   
newnameminecraft:purpur_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:purpur_stairsval  
newnameminecraft:purpur_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:purpur_stairsval  
newnameminecraft:purpur_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:purpur_stairsval  
newnameminecraft:purpur_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:purpur_stairsval  
newnameminecraft:purpur_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:purpur_stairsval  
newnameminecraft:purpur_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:purpur_stairsval  
newnameminecraft:purpur_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:purpur_stairsval  
newnameminecraft:purpur_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:quartz_blockval   
newnameminecraft:quartz_block
stateschisel_typedefaultpillar_axisy version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typechiseledpillar_axisy version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typelinespillar_axisy version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typesmoothpillar_axisy version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typedefaultpillar_axisx version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typechiseledpillar_axisx version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typelinespillar_axisx version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typesmoothpillar_axisx version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typedefaultpillar_axisz version  
oldnameminecraft:quartz_blockval	  
newnameminecraft:quartz_block
stateschisel_typechiseledpillar_axisz version  
oldnameminecraft:quartz_blockval
  
newnameminecraft:quartz_block
stateschisel_typelinespillar_axisz version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typesmoothpillar_axisz version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typedefaultpillar_axisy version  
oldnameminecraft:quartz_blockval
  
newnameminecraft:quartz_block
stateschisel_typechiseledpillar_axisy version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typelinespillar_axisy version  
oldnameminecraft:quartz_blockval  
newnameminecraft:quartz_block
stateschisel_typesmoothpillar_axisy version  
oldnameminecraft:quartz_oreval   
newnameminecraft:quartz_ore
states version  
oldnameminecraft:quartz_stairsval   
newnameminecraft:quartz_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:quartz_stairsval  
newnameminecraft:quartz_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:quartz_stairsval  
newnameminecraft:quartz_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:quartz_stairsval  
newnameminecraft:quartz_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:quartz_stairsval  
newnameminecraft:quartz_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:quartz_stairsval  
newnameminecraft:quartz_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:quartz_stairsval  
newnameminecraft:quartz_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:quartz_stairsval  
newnameminecraft:quartz_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:railval   
newnameminecraft:rail
statesrail_direction  version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction
 version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction version  
oldnameminecraft:railval	  
newnameminecraft:rail
statesrail_direction version  
oldnameminecraft:railval
  
newnameminecraft:rail
statesrail_direction  version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction  version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction  version  
oldnameminecraft:railval
  
newnameminecraft:rail
statesrail_direction  version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction  version  
oldnameminecraft:railval  
newnameminecraft:rail
statesrail_direction  version  
oldnameminecraft:red_flowerval   
newnameminecraft:red_flower
statesflower_typepoppy version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_typeorchid version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_typeallium version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_type	houstonia version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_type	tulip_red version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_typetulip_orange version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_typetulip_white version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_type
tulip_pink version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_typeoxeye version  
oldnameminecraft:red_flowerval	  
newnameminecraft:red_flower
statesflower_type
cornflower version  
oldnameminecraft:red_flowerval
  
newnameminecraft:red_flower
statesflower_typelily_of_the_valley version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_typepoppy version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_typepoppy version  
oldnameminecraft:red_flowerval
  
newnameminecraft:red_flower
statesflower_typepoppy version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_typepoppy version  
oldnameminecraft:red_flowerval  
newnameminecraft:red_flower
statesflower_typepoppy version  
oldnameminecraft:red_glazed_terracottaval   
newnameminecraft:red_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:red_glazed_terracottaval  
newnameminecraft:red_glazed_terracotta
statesfacing_direction version  
oldnameminecraft:red_glazed_terracottaval  
newnameminecraft:red_glazed_terracotta
statesfacing_direction version  
oldnameminecraft:red_glazed_terracottaval  
newnameminecraft:red_glazed_terracotta
statesfacing_direction version  
oldnameminecraft:red_glazed_terracottaval  
newnameminecraft:red_glazed_terracotta
statesfacing_direction version  
oldnameminecraft:red_glazed_terracottaval  
newnameminecraft:red_glazed_terracotta
statesfacing_direction
 version  
oldnameminecraft:red_glazed_terracottaval  
newnameminecraft:red_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:red_glazed_terracottaval  
newnameminecraft:red_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:red_mushroomval   
newnameminecraft:red_mushroom
states version  
oldnameminecraft:red_mushroom_blockval   
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits  version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits
 version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval	  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval
  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval
  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_mushroom_blockval  
newnameminecraft:red_mushroom_block
stateshuge_mushroom_bits version  
oldnameminecraft:red_nether_brickval   
newnameminecraft:red_nether_brick
states version  
oldname!minecraft:red_nether_brick_stairsval   
newname!minecraft:red_nether_brick_stairs
statesupside_down_bit weirdo_direction  version  
oldname!minecraft:red_nether_brick_stairsval  
newname!minecraft:red_nether_brick_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:red_nether_brick_stairsval  
newname!minecraft:red_nether_brick_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:red_nether_brick_stairsval  
newname!minecraft:red_nether_brick_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:red_nether_brick_stairsval  
newname!minecraft:red_nether_brick_stairs
statesupside_down_bitweirdo_direction  version  
oldname!minecraft:red_nether_brick_stairsval  
newname!minecraft:red_nether_brick_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:red_nether_brick_stairsval  
newname!minecraft:red_nether_brick_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:red_nether_brick_stairsval  
newname!minecraft:red_nether_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:red_sandstoneval   
newnameminecraft:red_sandstone
statessand_stone_typedefault version  
oldnameminecraft:red_sandstoneval  
newnameminecraft:red_sandstone
statessand_stone_typeheiroglyphs version  
oldnameminecraft:red_sandstoneval  
newnameminecraft:red_sandstone
statessand_stone_typecut version  
oldnameminecraft:red_sandstoneval  
newnameminecraft:red_sandstone
statessand_stone_typesmooth version  
oldnameminecraft:red_sandstone_stairsval   
newnameminecraft:red_sandstone_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:red_sandstone_stairsval  
newnameminecraft:red_sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:red_sandstone_stairsval  
newnameminecraft:red_sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:red_sandstone_stairsval  
newnameminecraft:red_sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:red_sandstone_stairsval  
newnameminecraft:red_sandstone_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:red_sandstone_stairsval  
newnameminecraft:red_sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:red_sandstone_stairsval  
newnameminecraft:red_sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:red_sandstone_stairsval  
newnameminecraft:red_sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:redstone_blockval   
newnameminecraft:redstone_block
states version  
oldnameminecraft:redstone_lampval   
newnameminecraft:redstone_lamp
states version  
oldnameminecraft:redstone_oreval   
newnameminecraft:redstone_ore
states version  
oldnameminecraft:redstone_torchval   
newnameminecraft:redstone_torch
statestorch_facing_directionunknown version  
oldnameminecraft:redstone_torchval  
newnameminecraft:redstone_torch
statestorch_facing_directionwest version  
oldnameminecraft:redstone_torchval  
newnameminecraft:redstone_torch
statestorch_facing_directioneast version  
oldnameminecraft:redstone_torchval  
newnameminecraft:redstone_torch
statestorch_facing_directionnorth version  
oldnameminecraft:redstone_torchval  
newnameminecraft:redstone_torch
statestorch_facing_directionsouth version  
oldnameminecraft:redstone_torchval  
newnameminecraft:redstone_torch
statestorch_facing_directiontop version  
oldnameminecraft:redstone_torchval  
newnameminecraft:redstone_torch
statestorch_facing_directionunknown version  
oldnameminecraft:redstone_torchval  
newnameminecraft:redstone_torch
statestorch_facing_directionunknown version  
oldnameminecraft:redstone_wireval   
newnameminecraft:redstone_wire
statesredstone_signal  version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal
 version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval	  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval
  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval
  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:redstone_wireval  
newnameminecraft:redstone_wire
statesredstone_signal version  
oldnameminecraft:reedsval   
newnameminecraft:reeds
statesage  version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage
 version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval	  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval
  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval
  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldnameminecraft:reedsval  
newnameminecraft:reeds
statesage version  
oldname!minecraft:repeating_command_blockval   
newname!minecraft:repeating_command_block
statesconditional_bit facing_direction  version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bit facing_direction version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bit facing_direction version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bit facing_direction version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bit facing_direction version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bit facing_direction
 version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bit facing_direction  version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bit facing_direction  version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bitfacing_direction  version  
oldname!minecraft:repeating_command_blockval	  
newname!minecraft:repeating_command_block
statesconditional_bitfacing_direction version  
oldname!minecraft:repeating_command_blockval
  
newname!minecraft:repeating_command_block
statesconditional_bitfacing_direction version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bitfacing_direction version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bitfacing_direction version  
oldname!minecraft:repeating_command_blockval
  
newname!minecraft:repeating_command_block
statesconditional_bitfacing_direction
 version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bitfacing_direction  version  
oldname!minecraft:repeating_command_blockval  
newname!minecraft:repeating_command_block
statesconditional_bitfacing_direction  version  
oldnameminecraft:reserved6val   
newnameminecraft:reserved6
states version  
oldnameminecraft:sandval   
newnameminecraft:sand
states	sand_typenormal version  
oldnameminecraft:sandval  
newnameminecraft:sand
states	sand_typered version  
oldnameminecraft:sandstoneval   
newnameminecraft:sandstone
statessand_stone_typedefault version  
oldnameminecraft:sandstoneval  
newnameminecraft:sandstone
statessand_stone_typeheiroglyphs version  
oldnameminecraft:sandstoneval  
newnameminecraft:sandstone
statessand_stone_typecut version  
oldnameminecraft:sandstoneval  
newnameminecraft:sandstone
statessand_stone_typesmooth version  
oldnameminecraft:sandstone_stairsval   
newnameminecraft:sandstone_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:sandstone_stairsval  
newnameminecraft:sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:sandstone_stairsval  
newnameminecraft:sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:sandstone_stairsval  
newnameminecraft:sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:sandstone_stairsval  
newnameminecraft:sandstone_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:sandstone_stairsval  
newnameminecraft:sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:sandstone_stairsval  
newnameminecraft:sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:sandstone_stairsval  
newnameminecraft:sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:saplingval   
newnameminecraft:sapling
statesage_bit sapling_typeoak version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bit sapling_typespruce version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bit sapling_typebirch version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bit sapling_typejungle version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bit sapling_typeacacia version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bit sapling_typedark_oak version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bit sapling_typeoak version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bit sapling_typeoak version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bitsapling_typeoak version  
oldnameminecraft:saplingval	  
newnameminecraft:sapling
statesage_bitsapling_typespruce version  
oldnameminecraft:saplingval
  
newnameminecraft:sapling
statesage_bitsapling_typebirch version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bitsapling_typejungle version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bitsapling_typeacacia version  
oldnameminecraft:saplingval
  
newnameminecraft:sapling
statesage_bitsapling_typedark_oak version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bitsapling_typeoak version  
oldnameminecraft:saplingval  
newnameminecraft:sapling
statesage_bitsapling_typeoak version  
oldnameminecraft:scaffoldingval   
newnameminecraft:scaffolding
states	stability stability_check  version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check  version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check  version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check  version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check  version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stability
stability_check  version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check  version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check  version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stability stability_check version  
oldnameminecraft:scaffoldingval	  
newnameminecraft:scaffolding
states	stabilitystability_check version  
oldnameminecraft:scaffoldingval
  
newnameminecraft:scaffolding
states	stabilitystability_check version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check version  
oldnameminecraft:scaffoldingval
  
newnameminecraft:scaffolding
states	stability
stability_check version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check version  
oldnameminecraft:scaffoldingval  
newnameminecraft:scaffolding
states	stabilitystability_check version  
oldnameminecraft:seaLanternval   
newnameminecraft:seaLantern
states version  
oldnameminecraft:sea_pickleval   
newnameminecraft:sea_pickle
states
cluster_count dead_bit  version  
oldnameminecraft:sea_pickleval  
newnameminecraft:sea_pickle
states
cluster_countdead_bit  version  
oldnameminecraft:sea_pickleval  
newnameminecraft:sea_pickle
states
cluster_countdead_bit  version  
oldnameminecraft:sea_pickleval  
newnameminecraft:sea_pickle
states
cluster_countdead_bit  version  
oldnameminecraft:sea_pickleval  
newnameminecraft:sea_pickle
states
cluster_count dead_bit version  
oldnameminecraft:sea_pickleval  
newnameminecraft:sea_pickle
states
cluster_countdead_bit version  
oldnameminecraft:sea_pickleval  
newnameminecraft:sea_pickle
states
cluster_countdead_bit version  
oldnameminecraft:sea_pickleval  
newnameminecraft:sea_pickle
states
cluster_countdead_bit version  
oldnameminecraft:seagrassval   
newnameminecraft:seagrass
statessea_grass_typedefault version  
oldnameminecraft:seagrassval  
newnameminecraft:seagrass
statessea_grass_type
double_top version  
oldnameminecraft:seagrassval  
newnameminecraft:seagrass
statessea_grass_type
double_bot version  
oldnameminecraft:seagrassval  
newnameminecraft:seagrass
statessea_grass_typedefault version  
oldnameminecraft:shulker_boxval   
newnameminecraft:shulker_box
statescolorwhite version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolororange version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolormagenta version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolor
light_blue version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescoloryellow version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolorlime version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolorpink version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolorgray version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolorsilver version  
oldnameminecraft:shulker_boxval	  
newnameminecraft:shulker_box
statescolorcyan version  
oldnameminecraft:shulker_boxval
  
newnameminecraft:shulker_box
statescolorpurple version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolorblue version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolorbrown version  
oldnameminecraft:shulker_boxval
  
newnameminecraft:shulker_box
statescolorgreen version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolorred version  
oldnameminecraft:shulker_boxval  
newnameminecraft:shulker_box
statescolorblack version  
oldname"minecraft:silver_glazed_terracottaval   
newname"minecraft:silver_glazed_terracotta
statesfacing_direction  version  
oldname"minecraft:silver_glazed_terracottaval  
newname"minecraft:silver_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:silver_glazed_terracottaval  
newname"minecraft:silver_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:silver_glazed_terracottaval  
newname"minecraft:silver_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:silver_glazed_terracottaval  
newname"minecraft:silver_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:silver_glazed_terracottaval  
newname"minecraft:silver_glazed_terracotta
statesfacing_direction
 version  
oldname"minecraft:silver_glazed_terracottaval  
newname"minecraft:silver_glazed_terracotta
statesfacing_direction  version  
oldname"minecraft:silver_glazed_terracottaval  
newname"minecraft:silver_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:skullval   
newnameminecraft:skull
statesfacing_direction no_drop_bit  version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_directionno_drop_bit  version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_directionno_drop_bit  version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_directionno_drop_bit  version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_directionno_drop_bit  version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_direction
no_drop_bit  version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_direction no_drop_bit  version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_direction no_drop_bit  version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_direction no_drop_bit version  
oldnameminecraft:skullval	  
newnameminecraft:skull
statesfacing_directionno_drop_bit version  
oldnameminecraft:skullval
  
newnameminecraft:skull
statesfacing_directionno_drop_bit version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_directionno_drop_bit version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_directionno_drop_bit version  
oldnameminecraft:skullval
  
newnameminecraft:skull
statesfacing_direction
no_drop_bit version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_direction no_drop_bit version  
oldnameminecraft:skullval  
newnameminecraft:skull
statesfacing_direction no_drop_bit version  
oldnameminecraft:slimeval   
newnameminecraft:slime
states version  
oldnameminecraft:smithing_tableval   
newnameminecraft:smithing_table
states version  
oldnameminecraft:smokerval   
newnameminecraft:smoker
statesfacing_direction  version  
oldnameminecraft:smokerval  
newnameminecraft:smoker
statesfacing_direction version  
oldnameminecraft:smokerval  
newnameminecraft:smoker
statesfacing_direction version  
oldnameminecraft:smokerval  
newnameminecraft:smoker
statesfacing_direction version  
oldnameminecraft:smokerval  
newnameminecraft:smoker
statesfacing_direction version  
oldnameminecraft:smokerval  
newnameminecraft:smoker
statesfacing_direction
 version  
oldnameminecraft:smokerval  
newnameminecraft:smoker
statesfacing_direction  version  
oldnameminecraft:smokerval  
newnameminecraft:smoker
statesfacing_direction  version  
oldnameminecraft:smooth_quartz_stairsval   
newnameminecraft:smooth_quartz_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:smooth_quartz_stairsval  
newnameminecraft:smooth_quartz_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:smooth_quartz_stairsval  
newnameminecraft:smooth_quartz_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:smooth_quartz_stairsval  
newnameminecraft:smooth_quartz_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:smooth_quartz_stairsval  
newnameminecraft:smooth_quartz_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:smooth_quartz_stairsval  
newnameminecraft:smooth_quartz_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:smooth_quartz_stairsval  
newnameminecraft:smooth_quartz_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:smooth_quartz_stairsval  
newnameminecraft:smooth_quartz_stairs
statesupside_down_bitweirdo_direction version  
oldname%minecraft:smooth_red_sandstone_stairsval   
newname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bit weirdo_direction  version  
oldname%minecraft:smooth_red_sandstone_stairsval  
newname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldname%minecraft:smooth_red_sandstone_stairsval  
newname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldname%minecraft:smooth_red_sandstone_stairsval  
newname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldname%minecraft:smooth_red_sandstone_stairsval  
newname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bitweirdo_direction  version  
oldname%minecraft:smooth_red_sandstone_stairsval  
newname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldname%minecraft:smooth_red_sandstone_stairsval  
newname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldname%minecraft:smooth_red_sandstone_stairsval  
newname%minecraft:smooth_red_sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:smooth_sandstone_stairsval   
newname!minecraft:smooth_sandstone_stairs
statesupside_down_bit weirdo_direction  version  
oldname!minecraft:smooth_sandstone_stairsval  
newname!minecraft:smooth_sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:smooth_sandstone_stairsval  
newname!minecraft:smooth_sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:smooth_sandstone_stairsval  
newname!minecraft:smooth_sandstone_stairs
statesupside_down_bit weirdo_direction version  
oldname!minecraft:smooth_sandstone_stairsval  
newname!minecraft:smooth_sandstone_stairs
statesupside_down_bitweirdo_direction  version  
oldname!minecraft:smooth_sandstone_stairsval  
newname!minecraft:smooth_sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:smooth_sandstone_stairsval  
newname!minecraft:smooth_sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldname!minecraft:smooth_sandstone_stairsval  
newname!minecraft:smooth_sandstone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:smooth_stoneval   
newnameminecraft:smooth_stone
states version  
oldnameminecraft:snowval   
newnameminecraft:snow
states version  
oldnameminecraft:snow_layerval   
newnameminecraft:snow_layer
statescovered_bit height  version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bit height version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bit height version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bit height version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bit height version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bit height
 version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bit height version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bit height version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bitheight  version  
oldnameminecraft:snow_layerval	  
newnameminecraft:snow_layer
statescovered_bitheight version  
oldnameminecraft:snow_layerval
  
newnameminecraft:snow_layer
statescovered_bitheight version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bitheight version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bitheight version  
oldnameminecraft:snow_layerval
  
newnameminecraft:snow_layer
statescovered_bitheight
 version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bitheight version  
oldnameminecraft:snow_layerval  
newnameminecraft:snow_layer
statescovered_bitheight version  
oldnameminecraft:soul_sandval   
newnameminecraft:soul_sand
states version  
oldnameminecraft:spongeval   
newnameminecraft:sponge
statessponge_typedry version  
oldnameminecraft:spongeval  
newnameminecraft:sponge
statessponge_typewet version  
oldnameminecraft:spruce_buttonval   
newnameminecraft:spruce_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bit facing_direction
 version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:spruce_buttonval	  
newnameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:spruce_buttonval
  
newnameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:spruce_buttonval
  
newnameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction
 version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:spruce_buttonval  
newnameminecraft:spruce_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:spruce_doorval   
newnameminecraft:spruce_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:spruce_doorval	  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:spruce_doorval
  
newnameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:spruce_doorval
  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:spruce_doorval  
newnameminecraft:spruce_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:spruce_fence_gateval   
newnameminecraft:spruce_fence_gate
states	direction in_wall_bit open_bit  version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit  version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	direction in_wall_bit open_bit version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bit open_bit version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	direction in_wall_bitopen_bit  version  
oldnameminecraft:spruce_fence_gateval	  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:spruce_fence_gateval
  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit  version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	direction in_wall_bitopen_bit version  
oldnameminecraft:spruce_fence_gateval
  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:spruce_fence_gateval  
newnameminecraft:spruce_fence_gate
states	directionin_wall_bitopen_bit version  
oldnameminecraft:spruce_pressure_plateval   
newnameminecraft:spruce_pressure_plate
statesredstone_signal  version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal
 version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval	  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval
  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval
  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_pressure_plateval  
newnameminecraft:spruce_pressure_plate
statesredstone_signal version  
oldnameminecraft:spruce_stairsval   
newnameminecraft:spruce_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:spruce_stairsval  
newnameminecraft:spruce_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:spruce_stairsval  
newnameminecraft:spruce_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:spruce_stairsval  
newnameminecraft:spruce_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:spruce_stairsval  
newnameminecraft:spruce_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:spruce_stairsval  
newnameminecraft:spruce_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:spruce_stairsval  
newnameminecraft:spruce_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:spruce_stairsval  
newnameminecraft:spruce_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:spruce_standing_signval   
newnameminecraft:spruce_standing_sign
statesground_sign_direction  version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction
 version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval	  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval
  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval
  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_standing_signval  
newnameminecraft:spruce_standing_sign
statesground_sign_direction version  
oldnameminecraft:spruce_trapdoorval   
newnameminecraft:spruce_trapdoor
states	direction open_bit upside_down_bit  version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	direction open_bit upside_down_bit version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	direction open_bitupside_down_bit  version  
oldnameminecraft:spruce_trapdoorval	  
newnameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:spruce_trapdoorval
  
newnameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	direction open_bitupside_down_bit version  
oldnameminecraft:spruce_trapdoorval
  
newnameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:spruce_trapdoorval  
newnameminecraft:spruce_trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:spruce_wall_signval   
newnameminecraft:spruce_wall_sign
statesfacing_direction  version  
oldnameminecraft:spruce_wall_signval  
newnameminecraft:spruce_wall_sign
statesfacing_direction version  
oldnameminecraft:spruce_wall_signval  
newnameminecraft:spruce_wall_sign
statesfacing_direction version  
oldnameminecraft:spruce_wall_signval  
newnameminecraft:spruce_wall_sign
statesfacing_direction version  
oldnameminecraft:spruce_wall_signval  
newnameminecraft:spruce_wall_sign
statesfacing_direction version  
oldnameminecraft:spruce_wall_signval  
newnameminecraft:spruce_wall_sign
statesfacing_direction
 version  
oldnameminecraft:spruce_wall_signval  
newnameminecraft:spruce_wall_sign
statesfacing_direction  version  
oldnameminecraft:spruce_wall_signval  
newnameminecraft:spruce_wall_sign
statesfacing_direction  version  
oldnameminecraft:stained_glassval   
newnameminecraft:stained_glass
statescolorwhite version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolororange version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolormagenta version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolor
light_blue version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescoloryellow version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolorlime version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolorpink version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolorgray version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolorsilver version  
oldnameminecraft:stained_glassval	  
newnameminecraft:stained_glass
statescolorcyan version  
oldnameminecraft:stained_glassval
  
newnameminecraft:stained_glass
statescolorpurple version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolorblue version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolorbrown version  
oldnameminecraft:stained_glassval
  
newnameminecraft:stained_glass
statescolorgreen version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolorred version  
oldnameminecraft:stained_glassval  
newnameminecraft:stained_glass
statescolorblack version  
oldnameminecraft:stained_glass_paneval   
newnameminecraft:stained_glass_pane
statescolorwhite version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolororange version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolormagenta version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolor
light_blue version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescoloryellow version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolorlime version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolorpink version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolorgray version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolorsilver version  
oldnameminecraft:stained_glass_paneval	  
newnameminecraft:stained_glass_pane
statescolorcyan version  
oldnameminecraft:stained_glass_paneval
  
newnameminecraft:stained_glass_pane
statescolorpurple version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolorblue version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolorbrown version  
oldnameminecraft:stained_glass_paneval
  
newnameminecraft:stained_glass_pane
statescolorgreen version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolorred version  
oldnameminecraft:stained_glass_paneval  
newnameminecraft:stained_glass_pane
statescolorblack version  
oldnameminecraft:stained_hardened_clayval   
newnameminecraft:stained_hardened_clay
statescolorwhite version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolororange version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolormagenta version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolor
light_blue version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescoloryellow version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolorlime version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolorpink version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolorgray version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolorsilver version  
oldnameminecraft:stained_hardened_clayval	  
newnameminecraft:stained_hardened_clay
statescolorcyan version  
oldnameminecraft:stained_hardened_clayval
  
newnameminecraft:stained_hardened_clay
statescolorpurple version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolorblue version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolorbrown version  
oldnameminecraft:stained_hardened_clayval
  
newnameminecraft:stained_hardened_clay
statescolorgreen version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolorred version  
oldnameminecraft:stained_hardened_clayval  
newnameminecraft:stained_hardened_clay
statescolorblack version  
oldnameminecraft:standing_bannerval   
newnameminecraft:standing_banner
statesground_sign_direction  version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction
 version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval	  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval
  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval
  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_bannerval  
newnameminecraft:standing_banner
statesground_sign_direction version  
oldnameminecraft:standing_signval   
newnameminecraft:standing_sign
statesground_sign_direction  version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction
 version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval	  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval
  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval
  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:standing_signval  
newnameminecraft:standing_sign
statesground_sign_direction version  
oldnameminecraft:sticky_pistonval   
newnameminecraft:sticky_piston
statesfacing_direction  version  
oldnameminecraft:sticky_pistonval  
newnameminecraft:sticky_piston
statesfacing_direction version  
oldnameminecraft:sticky_pistonval  
newnameminecraft:sticky_piston
statesfacing_direction version  
oldnameminecraft:sticky_pistonval  
newnameminecraft:sticky_piston
statesfacing_direction version  
oldnameminecraft:sticky_pistonval  
newnameminecraft:sticky_piston
statesfacing_direction version  
oldnameminecraft:sticky_pistonval  
newnameminecraft:sticky_piston
statesfacing_direction
 version  
oldnameminecraft:sticky_pistonval  
newnameminecraft:sticky_piston
statesfacing_direction  version  
oldnameminecraft:sticky_pistonval  
newnameminecraft:sticky_piston
statesfacing_direction  version  
oldnameminecraft:stoneval   
newnameminecraft:stone
states
stone_typestone version  
oldnameminecraft:stoneval  
newnameminecraft:stone
states
stone_typegranite version  
oldnameminecraft:stoneval  
newnameminecraft:stone
states
stone_typegranite_smooth version  
oldnameminecraft:stoneval  
newnameminecraft:stone
states
stone_typediorite version  
oldnameminecraft:stoneval  
newnameminecraft:stone
states
stone_typediorite_smooth version  
oldnameminecraft:stoneval  
newnameminecraft:stone
states
stone_typeandesite version  
oldnameminecraft:stoneval  
newnameminecraft:stone
states
stone_typeandesite_smooth version  
oldnameminecraft:stoneval  
newnameminecraft:stone
states
stone_typestone version  
oldnameminecraft:stone_brick_stairsval   
newnameminecraft:stone_brick_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:stone_brick_stairsval  
newnameminecraft:stone_brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:stone_brick_stairsval  
newnameminecraft:stone_brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:stone_brick_stairsval  
newnameminecraft:stone_brick_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:stone_brick_stairsval  
newnameminecraft:stone_brick_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:stone_brick_stairsval  
newnameminecraft:stone_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:stone_brick_stairsval  
newnameminecraft:stone_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:stone_brick_stairsval  
newnameminecraft:stone_brick_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:stone_buttonval   
newnameminecraft:stone_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bit facing_direction
 version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:stone_buttonval	  
newnameminecraft:stone_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:stone_buttonval
  
newnameminecraft:stone_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:stone_buttonval
  
newnameminecraft:stone_button
statesbutton_pressed_bitfacing_direction
 version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:stone_buttonval  
newnameminecraft:stone_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:stone_pressure_plateval   
newnameminecraft:stone_pressure_plate
statesredstone_signal  version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal
 version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval	  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval
  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval
  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_pressure_plateval  
newnameminecraft:stone_pressure_plate
statesredstone_signal version  
oldnameminecraft:stone_slabval   
newnameminecraft:stone_slab
statesstone_slab_typesmooth_stonetop_slot_bit  version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_type	sandstonetop_slot_bit  version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typewoodtop_slot_bit  version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typecobblestonetop_slot_bit  version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typebricktop_slot_bit  version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typestone_bricktop_slot_bit  version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typequartztop_slot_bit  version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typenether_bricktop_slot_bit  version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typesmooth_stonetop_slot_bit version  
oldnameminecraft:stone_slabval	  
newnameminecraft:stone_slab
statesstone_slab_type	sandstonetop_slot_bit version  
oldnameminecraft:stone_slabval
  
newnameminecraft:stone_slab
statesstone_slab_typewoodtop_slot_bit version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typecobblestonetop_slot_bit version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typebricktop_slot_bit version  
oldnameminecraft:stone_slabval
  
newnameminecraft:stone_slab
statesstone_slab_typestone_bricktop_slot_bit version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typequartztop_slot_bit version  
oldnameminecraft:stone_slabval  
newnameminecraft:stone_slab
statesstone_slab_typenether_bricktop_slot_bit version  
oldnameminecraft:stone_slab2val   
newnameminecraft:stone_slab2
statesstone_slab_type_2
red_sandstonetop_slot_bit  version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2purpurtop_slot_bit  version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2prismarine_roughtop_slot_bit  version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2prismarine_darktop_slot_bit  version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2prismarine_bricktop_slot_bit  version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2mossy_cobblestonetop_slot_bit  version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2smooth_sandstonetop_slot_bit  version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2red_nether_bricktop_slot_bit  version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2
red_sandstonetop_slot_bit version  
oldnameminecraft:stone_slab2val	  
newnameminecraft:stone_slab2
statesstone_slab_type_2purpurtop_slot_bit version  
oldnameminecraft:stone_slab2val
  
newnameminecraft:stone_slab2
statesstone_slab_type_2prismarine_roughtop_slot_bit version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2prismarine_darktop_slot_bit version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2prismarine_bricktop_slot_bit version  
oldnameminecraft:stone_slab2val
  
newnameminecraft:stone_slab2
statesstone_slab_type_2mossy_cobblestonetop_slot_bit version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2smooth_sandstonetop_slot_bit version  
oldnameminecraft:stone_slab2val  
newnameminecraft:stone_slab2
statesstone_slab_type_2red_nether_bricktop_slot_bit version  
oldnameminecraft:stone_slab3val   
newnameminecraft:stone_slab3
statesstone_slab_type_3end_stone_bricktop_slot_bit  version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3smooth_red_sandstonetop_slot_bit  version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3polished_andesitetop_slot_bit  version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3andesitetop_slot_bit  version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3dioritetop_slot_bit  version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3polished_dioritetop_slot_bit  version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3granitetop_slot_bit  version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3polished_granitetop_slot_bit  version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3end_stone_bricktop_slot_bit version  
oldnameminecraft:stone_slab3val	  
newnameminecraft:stone_slab3
statesstone_slab_type_3smooth_red_sandstonetop_slot_bit version  
oldnameminecraft:stone_slab3val
  
newnameminecraft:stone_slab3
statesstone_slab_type_3polished_andesitetop_slot_bit version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3andesitetop_slot_bit version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3dioritetop_slot_bit version  
oldnameminecraft:stone_slab3val
  
newnameminecraft:stone_slab3
statesstone_slab_type_3polished_dioritetop_slot_bit version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3granitetop_slot_bit version  
oldnameminecraft:stone_slab3val  
newnameminecraft:stone_slab3
statesstone_slab_type_3polished_granitetop_slot_bit version  
oldnameminecraft:stone_slab4val   
newnameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4
smooth_quartztop_slot_bit  version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4stonetop_slot_bit  version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4
cut_sandstonetop_slot_bit  version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4cut_red_sandstonetop_slot_bit  version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit  version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version  
oldnameminecraft:stone_slab4val	  
newnameminecraft:stone_slab4
statesstone_slab_type_4
smooth_quartztop_slot_bit version  
oldnameminecraft:stone_slab4val
  
newnameminecraft:stone_slab4
statesstone_slab_type_4stonetop_slot_bit version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4
cut_sandstonetop_slot_bit version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4cut_red_sandstonetop_slot_bit version  
oldnameminecraft:stone_slab4val
  
newnameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version  
oldnameminecraft:stone_slab4val  
newnameminecraft:stone_slab4
statesstone_slab_type_4mossy_stone_bricktop_slot_bit version  
oldnameminecraft:stone_stairsval   
newnameminecraft:stone_stairs
statesupside_down_bit weirdo_direction  version  
oldnameminecraft:stone_stairsval  
newnameminecraft:stone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:stone_stairsval  
newnameminecraft:stone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:stone_stairsval  
newnameminecraft:stone_stairs
statesupside_down_bit weirdo_direction version  
oldnameminecraft:stone_stairsval  
newnameminecraft:stone_stairs
statesupside_down_bitweirdo_direction  version  
oldnameminecraft:stone_stairsval  
newnameminecraft:stone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:stone_stairsval  
newnameminecraft:stone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:stone_stairsval  
newnameminecraft:stone_stairs
statesupside_down_bitweirdo_direction version  
oldnameminecraft:stonebrickval   
newnameminecraft:stonebrick
statesstone_brick_typedefault version  
oldnameminecraft:stonebrickval  
newnameminecraft:stonebrick
statesstone_brick_typemossy version  
oldnameminecraft:stonebrickval  
newnameminecraft:stonebrick
statesstone_brick_typecracked version  
oldnameminecraft:stonebrickval  
newnameminecraft:stonebrick
statesstone_brick_typechiseled version  
oldnameminecraft:stonebrickval  
newnameminecraft:stonebrick
statesstone_brick_typesmooth version  
oldnameminecraft:stonebrickval  
newnameminecraft:stonebrick
statesstone_brick_typedefault version  
oldnameminecraft:stonebrickval  
newnameminecraft:stonebrick
statesstone_brick_typedefault version  
oldnameminecraft:stonebrickval  
newnameminecraft:stonebrick
statesstone_brick_typedefault version  
oldnameminecraft:stonecutterval   
newnameminecraft:stonecutter
states version  
oldnameminecraft:stonecutter_blockval   
newnameminecraft:stonecutter_block
statesfacing_direction  version  
oldnameminecraft:stonecutter_blockval  
newnameminecraft:stonecutter_block
statesfacing_direction version  
oldnameminecraft:stonecutter_blockval  
newnameminecraft:stonecutter_block
statesfacing_direction version  
oldnameminecraft:stonecutter_blockval  
newnameminecraft:stonecutter_block
statesfacing_direction version  
oldnameminecraft:stonecutter_blockval  
newnameminecraft:stonecutter_block
statesfacing_direction version  
oldnameminecraft:stonecutter_blockval  
newnameminecraft:stonecutter_block
statesfacing_direction
 version  
oldnameminecraft:stonecutter_blockval  
newnameminecraft:stonecutter_block
statesfacing_direction  version  
oldnameminecraft:stonecutter_blockval  
newnameminecraft:stonecutter_block
statesfacing_direction  version  
oldnameminecraft:stripped_acacia_logval   
newnameminecraft:stripped_acacia_log
statespillar_axisy version  
oldnameminecraft:stripped_acacia_logval  
newnameminecraft:stripped_acacia_log
statespillar_axisx version  
oldnameminecraft:stripped_acacia_logval  
newnameminecraft:stripped_acacia_log
statespillar_axisz version  
oldnameminecraft:stripped_acacia_logval  
newnameminecraft:stripped_acacia_log
statespillar_axisy version  
oldnameminecraft:stripped_birch_logval   
newnameminecraft:stripped_birch_log
statespillar_axisy version  
oldnameminecraft:stripped_birch_logval  
newnameminecraft:stripped_birch_log
statespillar_axisx version  
oldnameminecraft:stripped_birch_logval  
newnameminecraft:stripped_birch_log
statespillar_axisz version  
oldnameminecraft:stripped_birch_logval  
newnameminecraft:stripped_birch_log
statespillar_axisy version  
oldnameminecraft:stripped_dark_oak_logval   
newnameminecraft:stripped_dark_oak_log
statespillar_axisy version  
oldnameminecraft:stripped_dark_oak_logval  
newnameminecraft:stripped_dark_oak_log
statespillar_axisx version  
oldnameminecraft:stripped_dark_oak_logval  
newnameminecraft:stripped_dark_oak_log
statespillar_axisz version  
oldnameminecraft:stripped_dark_oak_logval  
newnameminecraft:stripped_dark_oak_log
statespillar_axisy version  
oldnameminecraft:stripped_jungle_logval   
newnameminecraft:stripped_jungle_log
statespillar_axisy version  
oldnameminecraft:stripped_jungle_logval  
newnameminecraft:stripped_jungle_log
statespillar_axisx version  
oldnameminecraft:stripped_jungle_logval  
newnameminecraft:stripped_jungle_log
statespillar_axisz version  
oldnameminecraft:stripped_jungle_logval  
newnameminecraft:stripped_jungle_log
statespillar_axisy version  
oldnameminecraft:stripped_oak_logval   
newnameminecraft:stripped_oak_log
statespillar_axisy version  
oldnameminecraft:stripped_oak_logval  
newnameminecraft:stripped_oak_log
statespillar_axisx version  
oldnameminecraft:stripped_oak_logval  
newnameminecraft:stripped_oak_log
statespillar_axisz version  
oldnameminecraft:stripped_oak_logval  
newnameminecraft:stripped_oak_log
statespillar_axisy version  
oldnameminecraft:stripped_spruce_logval   
newnameminecraft:stripped_spruce_log
statespillar_axisy version  
oldnameminecraft:stripped_spruce_logval  
newnameminecraft:stripped_spruce_log
statespillar_axisx version  
oldnameminecraft:stripped_spruce_logval  
newnameminecraft:stripped_spruce_log
statespillar_axisz version  
oldnameminecraft:stripped_spruce_logval  
newnameminecraft:stripped_spruce_log
statespillar_axisy version  
oldnameminecraft:structure_blockval   
newnameminecraft:structure_block
statesstructure_block_typedata version  
oldnameminecraft:structure_blockval  
newnameminecraft:structure_block
statesstructure_block_typesave version  
oldnameminecraft:structure_blockval  
newnameminecraft:structure_block
statesstructure_block_typeload version  
oldnameminecraft:structure_blockval  
newnameminecraft:structure_block
statesstructure_block_typecorner version  
oldnameminecraft:structure_blockval  
newnameminecraft:structure_block
statesstructure_block_typeinvalid version  
oldnameminecraft:structure_blockval  
newnameminecraft:structure_block
statesstructure_block_typeexport version  
oldnameminecraft:structure_blockval  
newnameminecraft:structure_block
statesstructure_block_typedata version  
oldnameminecraft:structure_blockval  
newnameminecraft:structure_block
statesstructure_block_typedata version  
oldnameminecraft:sweet_berry_bushval   
newnameminecraft:sweet_berry_bush
statesgrowth  version  
oldnameminecraft:sweet_berry_bushval  
newnameminecraft:sweet_berry_bush
statesgrowth version  
oldnameminecraft:sweet_berry_bushval  
newnameminecraft:sweet_berry_bush
statesgrowth version  
oldnameminecraft:sweet_berry_bushval  
newnameminecraft:sweet_berry_bush
statesgrowth version  
oldnameminecraft:sweet_berry_bushval  
newnameminecraft:sweet_berry_bush
statesgrowth version  
oldnameminecraft:sweet_berry_bushval  
newnameminecraft:sweet_berry_bush
statesgrowth
 version  
oldnameminecraft:sweet_berry_bushval  
newnameminecraft:sweet_berry_bush
statesgrowth version  
oldnameminecraft:sweet_berry_bushval  
newnameminecraft:sweet_berry_bush
statesgrowth version  
oldnameminecraft:tallgrassval   
newnameminecraft:tallgrass
statestall_grass_typedefault version  
oldnameminecraft:tallgrassval  
newnameminecraft:tallgrass
statestall_grass_typetall version  
oldnameminecraft:tallgrassval  
newnameminecraft:tallgrass
statestall_grass_typefern version  
oldnameminecraft:tallgrassval  
newnameminecraft:tallgrass
statestall_grass_typesnow version  
oldname
minecraft:tntval   
newname
minecraft:tnt
statesallow_underwater_bit explode_bit  version  
oldname
minecraft:tntval  
newname
minecraft:tnt
statesallow_underwater_bit explode_bit version  
oldname
minecraft:tntval  
newname
minecraft:tnt
statesallow_underwater_bitexplode_bit  version  
oldname
minecraft:tntval  
newname
minecraft:tnt
statesallow_underwater_bitexplode_bit version  
oldnameminecraft:torchval   
newnameminecraft:torch
statestorch_facing_directionunknown version  
oldnameminecraft:torchval  
newnameminecraft:torch
statestorch_facing_directionwest version  
oldnameminecraft:torchval  
newnameminecraft:torch
statestorch_facing_directioneast version  
oldnameminecraft:torchval  
newnameminecraft:torch
statestorch_facing_directionnorth version  
oldnameminecraft:torchval  
newnameminecraft:torch
statestorch_facing_directionsouth version  
oldnameminecraft:torchval  
newnameminecraft:torch
statestorch_facing_directiontop version  
oldnameminecraft:torchval  
newnameminecraft:torch
statestorch_facing_directionunknown version  
oldnameminecraft:torchval  
newnameminecraft:torch
statestorch_facing_directionunknown version  
oldnameminecraft:trapdoorval   
newnameminecraft:trapdoor
states	direction open_bit upside_down_bit  version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	directionopen_bit upside_down_bit  version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	direction open_bit upside_down_bit version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	directionopen_bit upside_down_bit version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	direction open_bitupside_down_bit  version  
oldnameminecraft:trapdoorval	  
newnameminecraft:trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:trapdoorval
  
newnameminecraft:trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	directionopen_bitupside_down_bit  version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	direction open_bitupside_down_bit version  
oldnameminecraft:trapdoorval
  
newnameminecraft:trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:trapdoorval  
newnameminecraft:trapdoor
states	directionopen_bitupside_down_bit version  
oldnameminecraft:trapped_chestval   
newnameminecraft:trapped_chest
statesfacing_direction  version  
oldnameminecraft:trapped_chestval  
newnameminecraft:trapped_chest
statesfacing_direction version  
oldnameminecraft:trapped_chestval  
newnameminecraft:trapped_chest
statesfacing_direction version  
oldnameminecraft:trapped_chestval  
newnameminecraft:trapped_chest
statesfacing_direction version  
oldnameminecraft:trapped_chestval  
newnameminecraft:trapped_chest
statesfacing_direction version  
oldnameminecraft:trapped_chestval  
newnameminecraft:trapped_chest
statesfacing_direction
 version  
oldnameminecraft:trapped_chestval  
newnameminecraft:trapped_chest
statesfacing_direction  version  
oldnameminecraft:trapped_chestval  
newnameminecraft:trapped_chest
statesfacing_direction  version  
oldnameminecraft:tripWireval   
newnameminecraft:tripWire
statesattached_bit disarmed_bit powered_bit 
suspended_bit  version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bit disarmed_bit powered_bit
suspended_bit  version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bit disarmed_bit powered_bit 
suspended_bit version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bit disarmed_bit powered_bit
suspended_bit version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bitdisarmed_bit powered_bit 
suspended_bit  version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bitdisarmed_bit powered_bit
suspended_bit  version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bitdisarmed_bit powered_bit 
suspended_bit version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bitdisarmed_bit powered_bit
suspended_bit version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bit disarmed_bitpowered_bit 
suspended_bit  version  
oldnameminecraft:tripWireval	  
newnameminecraft:tripWire
statesattached_bit disarmed_bitpowered_bit
suspended_bit  version  
oldnameminecraft:tripWireval
  
newnameminecraft:tripWire
statesattached_bit disarmed_bitpowered_bit 
suspended_bit version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bit disarmed_bitpowered_bit
suspended_bit version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bitdisarmed_bitpowered_bit 
suspended_bit  version  
oldnameminecraft:tripWireval
  
newnameminecraft:tripWire
statesattached_bitdisarmed_bitpowered_bit
suspended_bit  version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bitdisarmed_bitpowered_bit 
suspended_bit version  
oldnameminecraft:tripWireval  
newnameminecraft:tripWire
statesattached_bitdisarmed_bitpowered_bit
suspended_bit version  
oldnameminecraft:tripwire_hookval   
newnameminecraft:tripwire_hook
statesattached_bit 	direction powered_bit  version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit  version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit  version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit  version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit	direction powered_bit  version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit  version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit  version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit  version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit 	direction powered_bit version  
oldnameminecraft:tripwire_hookval	  
newnameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit version  
oldnameminecraft:tripwire_hookval
  
newnameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit 	directionpowered_bit version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit	direction powered_bit version  
oldnameminecraft:tripwire_hookval
  
newnameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit version  
oldnameminecraft:tripwire_hookval  
newnameminecraft:tripwire_hook
statesattached_bit	directionpowered_bit version  
oldnameminecraft:turtle_eggval   
newnameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_countone_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_counttwo_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_count	three_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_countfour_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_statecrackedturtle_egg_countone_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_statecrackedturtle_egg_counttwo_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_statecrackedturtle_egg_count	three_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_statecrackedturtle_egg_countfour_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_statemax_crackedturtle_egg_countone_egg version  
oldnameminecraft:turtle_eggval	  
newnameminecraft:turtle_egg
states
cracked_statemax_crackedturtle_egg_counttwo_egg version  
oldnameminecraft:turtle_eggval
  
newnameminecraft:turtle_egg
states
cracked_statemax_crackedturtle_egg_count	three_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_statemax_crackedturtle_egg_countfour_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_countone_egg version  
oldnameminecraft:turtle_eggval
  
newnameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_counttwo_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_count	three_egg version  
oldnameminecraft:turtle_eggval  
newnameminecraft:turtle_egg
states
cracked_state	no_cracksturtle_egg_countfour_egg version  
oldnameminecraft:underwater_torchval   
newnameminecraft:underwater_torch
statestorch_facing_directionunknown version  
oldnameminecraft:underwater_torchval  
newnameminecraft:underwater_torch
statestorch_facing_directionwest version  
oldnameminecraft:underwater_torchval  
newnameminecraft:underwater_torch
statestorch_facing_directioneast version  
oldnameminecraft:underwater_torchval  
newnameminecraft:underwater_torch
statestorch_facing_directionnorth version  
oldnameminecraft:underwater_torchval  
newnameminecraft:underwater_torch
statestorch_facing_directionsouth version  
oldnameminecraft:underwater_torchval  
newnameminecraft:underwater_torch
statestorch_facing_directiontop version  
oldnameminecraft:underwater_torchval  
newnameminecraft:underwater_torch
statestorch_facing_directionunknown version  
oldnameminecraft:underwater_torchval  
newnameminecraft:underwater_torch
statestorch_facing_directionunknown version  
oldnameminecraft:undyed_shulker_boxval   
newnameminecraft:undyed_shulker_box
states version  
oldnameminecraft:unlit_redstone_torchval   
newnameminecraft:unlit_redstone_torch
statestorch_facing_directionunknown version  
oldnameminecraft:unlit_redstone_torchval  
newnameminecraft:unlit_redstone_torch
statestorch_facing_directionwest version  
oldnameminecraft:unlit_redstone_torchval  
newnameminecraft:unlit_redstone_torch
statestorch_facing_directioneast version  
oldnameminecraft:unlit_redstone_torchval  
newnameminecraft:unlit_redstone_torch
statestorch_facing_directionnorth version  
oldnameminecraft:unlit_redstone_torchval  
newnameminecraft:unlit_redstone_torch
statestorch_facing_directionsouth version  
oldnameminecraft:unlit_redstone_torchval  
newnameminecraft:unlit_redstone_torch
statestorch_facing_directiontop version  
oldnameminecraft:unlit_redstone_torchval  
newnameminecraft:unlit_redstone_torch
statestorch_facing_directionunknown version  
oldnameminecraft:unlit_redstone_torchval  
newnameminecraft:unlit_redstone_torch
statestorch_facing_directionunknown version  
oldnameminecraft:unpowered_comparatorval   
newnameminecraft:unpowered_comparator
states	direction output_lit_bit output_subtract_bit  version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit  version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit  version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit  version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	direction output_lit_bit output_subtract_bit version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bit output_subtract_bit version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	direction output_lit_bitoutput_subtract_bit  version  
oldnameminecraft:unpowered_comparatorval	  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version  
oldnameminecraft:unpowered_comparatorval
  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit  version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	direction output_lit_bitoutput_subtract_bit version  
oldnameminecraft:unpowered_comparatorval
  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version  
oldnameminecraft:unpowered_comparatorval  
newnameminecraft:unpowered_comparator
states	directionoutput_lit_bitoutput_subtract_bit version  
oldnameminecraft:unpowered_repeaterval   
newnameminecraft:unpowered_repeater
states	direction repeater_delay  version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay  version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay  version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay  version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	direction repeater_delay version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	direction repeater_delay version  
oldnameminecraft:unpowered_repeaterval	  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay version  
oldnameminecraft:unpowered_repeaterval
  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	direction repeater_delay version  
oldnameminecraft:unpowered_repeaterval
  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay version  
oldnameminecraft:unpowered_repeaterval  
newnameminecraft:unpowered_repeater
states	directionrepeater_delay version  
oldnameminecraft:vineval   
newnameminecraft:vine
statesvine_direction_bits  version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits
 version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval	  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval
  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval
  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:vineval  
newnameminecraft:vine
statesvine_direction_bits version  
oldnameminecraft:wall_bannerval   
newnameminecraft:wall_banner
statesfacing_direction  version  
oldnameminecraft:wall_bannerval  
newnameminecraft:wall_banner
statesfacing_direction version  
oldnameminecraft:wall_bannerval  
newnameminecraft:wall_banner
statesfacing_direction version  
oldnameminecraft:wall_bannerval  
newnameminecraft:wall_banner
statesfacing_direction version  
oldnameminecraft:wall_bannerval  
newnameminecraft:wall_banner
statesfacing_direction version  
oldnameminecraft:wall_bannerval  
newnameminecraft:wall_banner
statesfacing_direction
 version  
oldnameminecraft:wall_bannerval  
newnameminecraft:wall_banner
statesfacing_direction  version  
oldnameminecraft:wall_bannerval  
newnameminecraft:wall_banner
statesfacing_direction  version  
oldnameminecraft:wall_signval   
newnameminecraft:wall_sign
statesfacing_direction  version  
oldnameminecraft:wall_signval  
newnameminecraft:wall_sign
statesfacing_direction version  
oldnameminecraft:wall_signval  
newnameminecraft:wall_sign
statesfacing_direction version  
oldnameminecraft:wall_signval  
newnameminecraft:wall_sign
statesfacing_direction version  
oldnameminecraft:wall_signval  
newnameminecraft:wall_sign
statesfacing_direction version  
oldnameminecraft:wall_signval  
newnameminecraft:wall_sign
statesfacing_direction
 version  
oldnameminecraft:wall_signval  
newnameminecraft:wall_sign
statesfacing_direction  version  
oldnameminecraft:wall_signval  
newnameminecraft:wall_sign
statesfacing_direction  version  
oldnameminecraft:waterval   
newnameminecraft:water
statesliquid_depth  version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth
 version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval	  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval
  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval
  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterval  
newnameminecraft:water
statesliquid_depth version  
oldnameminecraft:waterlilyval   
newnameminecraft:waterlily
states version  
oldname
minecraft:webval   
newname
minecraft:web
states version  
oldnameminecraft:wheatval   
newnameminecraft:wheat
statesgrowth  version  
oldnameminecraft:wheatval  
newnameminecraft:wheat
statesgrowth version  
oldnameminecraft:wheatval  
newnameminecraft:wheat
statesgrowth version  
oldnameminecraft:wheatval  
newnameminecraft:wheat
statesgrowth version  
oldnameminecraft:wheatval  
newnameminecraft:wheat
statesgrowth version  
oldnameminecraft:wheatval  
newnameminecraft:wheat
statesgrowth
 version  
oldnameminecraft:wheatval  
newnameminecraft:wheat
statesgrowth version  
oldnameminecraft:wheatval  
newnameminecraft:wheat
statesgrowth version  
oldname!minecraft:white_glazed_terracottaval   
newname!minecraft:white_glazed_terracotta
statesfacing_direction  version  
oldname!minecraft:white_glazed_terracottaval  
newname!minecraft:white_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:white_glazed_terracottaval  
newname!minecraft:white_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:white_glazed_terracottaval  
newname!minecraft:white_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:white_glazed_terracottaval  
newname!minecraft:white_glazed_terracotta
statesfacing_direction version  
oldname!minecraft:white_glazed_terracottaval  
newname!minecraft:white_glazed_terracotta
statesfacing_direction
 version  
oldname!minecraft:white_glazed_terracottaval  
newname!minecraft:white_glazed_terracotta
statesfacing_direction  version  
oldname!minecraft:white_glazed_terracottaval  
newname!minecraft:white_glazed_terracotta
statesfacing_direction  version  
oldnameminecraft:woodval   
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typeoak version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typespruce version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typebirch version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typejungle version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typeacacia version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typedark_oak version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typeoak version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit 	wood_typeoak version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit	wood_typeoak version  
oldnameminecraft:woodval	  
newnameminecraft:wood
statespillar_axisystripped_bit	wood_typespruce version  
oldnameminecraft:woodval
  
newnameminecraft:wood
statespillar_axisystripped_bit	wood_typebirch version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit	wood_typejungle version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit	wood_typeacacia version  
oldnameminecraft:woodval
  
newnameminecraft:wood
statespillar_axisystripped_bit	wood_typedark_oak version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit	wood_typeoak version  
oldnameminecraft:woodval  
newnameminecraft:wood
statespillar_axisystripped_bit	wood_typeoak version  
oldnameminecraft:wooden_buttonval   
newnameminecraft:wooden_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bit facing_direction version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bit facing_direction
 version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bit facing_direction  version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:wooden_buttonval	  
newnameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:wooden_buttonval
  
newnameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction version  
oldnameminecraft:wooden_buttonval
  
newnameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction
 version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:wooden_buttonval  
newnameminecraft:wooden_button
statesbutton_pressed_bitfacing_direction  version  
oldnameminecraft:wooden_doorval   
newnameminecraft:wooden_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:wooden_doorval	  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:wooden_doorval
  
newnameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:wooden_doorval
  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	direction door_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	direction door_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit  version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	direction door_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bit open_bit upper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bit upper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	direction door_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bit open_bitupper_block_bit version  
oldnameminecraft:wooden_doorval  
newnameminecraft:wooden_door
states	directiondoor_hinge_bitopen_bitupper_block_bit version  
oldnameminecraft:wooden_pressure_plateval   
newnameminecraft:wooden_pressure_plate
statesredstone_signal  version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal
 version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval	  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval
  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval
  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_pressure_plateval  
newnameminecraft:wooden_pressure_plate
statesredstone_signal version  
oldnameminecraft:wooden_slabval   
newnameminecraft:wooden_slab
statestop_slot_bit 	wood_typeoak version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit 	wood_typespruce version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit 	wood_typebirch version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit 	wood_typejungle version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit 	wood_typeacacia version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit 	wood_typedark_oak version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit 	wood_typeoak version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit 	wood_typeoak version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit	wood_typeoak version  
oldnameminecraft:wooden_slabval	  
newnameminecraft:wooden_slab
statestop_slot_bit	wood_typespruce version  
oldnameminecraft:wooden_slabval
  
newnameminecraft:wooden_slab
statestop_slot_bit	wood_typebirch version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit	wood_typejungle version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit	wood_typeacacia version  
oldnameminecraft:wooden_slabval
  
newnameminecraft:wooden_slab
statestop_slot_bit	wood_typedark_oak version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit	wood_typeoak version  
oldnameminecraft:wooden_slabval  
newnameminecraft:wooden_slab
statestop_slot_bit	wood_typeoak version  
oldnameminecraft:woolval   
newnameminecraft:wool
statescolorwhite version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolororange version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolormagenta version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolor
light_blue version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescoloryellow version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolorlime version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolorpink version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolorgray version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolorsilver version  
oldnameminecraft:woolval	  
newnameminecraft:wool
statescolorcyan version  
oldnameminecraft:woolval
  
newnameminecraft:wool
statescolorpurple version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolorblue version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolorbrown version  
oldnameminecraft:woolval
  
newnameminecraft:wool
statescolorgreen version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolorred version  
oldnameminecraft:woolval  
newnameminecraft:wool
statescolorblack version  
oldnameminecraft:yellow_flowerval   
newnameminecraft:yellow_flower
states version  
oldname"minecraft:yellow_glazed_terracottaval   
newname"minecraft:yellow_glazed_terracotta
statesfacing_direction  version  
oldname"minecraft:yellow_glazed_terracottaval  
newname"minecraft:yellow_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:yellow_glazed_terracottaval  
newname"minecraft:yellow_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:yellow_glazed_terracottaval  
newname"minecraft:yellow_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:yellow_glazed_terracottaval  
newname"minecraft:yellow_glazed_terracotta
statesfacing_direction version  
oldname"minecraft:yellow_glazed_terracottaval  
newname"minecraft:yellow_glazed_terracotta
statesfacing_direction
 version  
oldname"minecraft:yellow_glazed_terracottaval  
newname"minecraft:yellow_glazed_terracotta
statesfacing_direction  version  
oldname"minecraft:yellow_glazed_terracottaval  
newname"minecraft:yellow_glazed_terracotta
statesfacing_direction  version  {"minecraft:honeycomb_block":-221,"minecraft:honey_block":-220,"minecraft:beehive":-219,"minecraft:bee_nest":-218,"minecraft:stickypistonarmcollision":-217,"minecraft:wither_rose":-216,"minecraft:light_block":-215,"minecraft:lit_blast_furnace":-214,"minecraft:composter":-213,"minecraft:wood":-212,"minecraft:jigsaw":-211,"minecraft:lava_cauldron":-210,"minecraft:item.campfire":-209,"minecraft:lantern":-208,"minecraft:sweet_berry_bush":-207,"minecraft:bell":-206,"minecraft:loom":-204,"minecraft:barrel":-203,"minecraft:smithing_table":-202,"minecraft:fletching_table":-201,"minecraft:cartography_table":-200,"minecraft:lit_smoker":-199,"minecraft:smoker":-198,"minecraft:stonecutter_block":-197,"minecraft:blast_furnace":-196,"minecraft:grindstone":-195,"minecraft:lectern":-194,"minecraft:darkoak_wall_sign":-193,"minecraft:darkoak_standing_sign":-192,"minecraft:acacia_wall_sign":-191,"minecraft:acacia_standing_sign":-190,"minecraft:jungle_wall_sign":-189,"minecraft:jungle_standing_sign":-188,"minecraft:birch_wall_sign":-187,"minecraft:birch_standing_sign":-186,"minecraft:smooth_quartz_stairs":-185,"minecraft:red_nether_brick_stairs":-184,"minecraft:smooth_stone":-183,"minecraft:spruce_wall_sign":-182,"minecraft:spruce_standing_sign":-181,"minecraft:normal_stone_stairs":-180,"minecraft:mossy_cobblestone_stairs":-179,"minecraft:end_brick_stairs":-178,"minecraft:smooth_sandstone_stairs":-177,"minecraft:smooth_red_sandstone_stairs":-176,"minecraft:mossy_stone_brick_stairs":-175,"minecraft:polished_andesite_stairs":-174,"minecraft:polished_diorite_stairs":-173,"minecraft:polished_granite_stairs":-172,"minecraft:andesite_stairs":-171,"minecraft:diorite_stairs":-170,"minecraft:granite_stairs":-169,"minecraft:real_double_stone_slab4":-168,"minecraft:real_double_stone_slab3":-167,"minecraft:double_stone_slab4":-166,"minecraft:scaffolding":-165,"minecraft:bamboo_sapling":-164,"minecraft:bamboo":-163,"minecraft:double_stone_slab3":-162,"minecraft:barrier":-161,"minecraft:bubble_column":-160,"minecraft:turtle_egg":-159,"minecraft:air":-158,"minecraft:conduit":-157,"minecraft:sea_pickle":-156,"minecraft:carved_pumpkin":-155,"minecraft:spruce_pressure_plate":-154,"minecraft:jungle_pressure_plate":-153,"minecraft:dark_oak_pressure_plate":-152,"minecraft:birch_pressure_plate":-151,"minecraft:acacia_pressure_plate":-150,"minecraft:spruce_trapdoor":-149,"minecraft:jungle_trapdoor":-148,"minecraft:dark_oak_trapdoor":-147,"minecraft:birch_trapdoor":-146,"minecraft:acacia_trapdoor":-145,"minecraft:spruce_button":-144,"minecraft:jungle_button":-143,"minecraft:dark_oak_button":-142,"minecraft:birch_button":-141,"minecraft:acacia_button":-140,"minecraft:dried_kelp_block":-139,"minecraft:item.kelp":-138,"minecraft:coral_fan_hang3":-137,"minecraft:coral_fan_hang2":-136,"minecraft:coral_fan_hang":-135,"minecraft:coral_fan_dead":-134,"minecraft:coral_fan":-133,"minecraft:coral_block":-132,"minecraft:coral":-131,"minecraft:seagrass":-130,"minecraft:element_118":-129,"minecraft:element_117":-128,"minecraft:element_116":-127,"minecraft:element_115":-126,"minecraft:element_114":-125,"minecraft:element_113":-124,"minecraft:element_112":-123,"minecraft:element_111":-122,"minecraft:element_110":-121,"minecraft:element_109":-120,"minecraft:element_108":-119,"minecraft:element_107":-118,"minecraft:element_106":-117,"minecraft:element_105":-116,"minecraft:element_104":-115,"minecraft:element_103":-114,"minecraft:element_102":-113,"minecraft:element_101":-112,"minecraft:element_100":-111,"minecraft:element_99":-110,"minecraft:element_98":-109,"minecraft:element_97":-108,"minecraft:element_96":-107,"minecraft:element_95":-106,"minecraft:element_94":-105,"minecraft:element_93":-104,"minecraft:element_92":-103,"minecraft:element_91":-102,"minecraft:element_90":-101,"minecraft:element_89":-100,"minecraft:element_88":-99,"minecraft:element_87":-98,"minecraft:element_86":-97,"minecraft:element_85":-96,"minecraft:element_84":-95,"minecraft:element_83":-94,"minecraft:element_82":-93,"minecraft:element_81":-92,"minecraft:element_80":-91,"minecraft:element_79":-90,"minecraft:element_78":-89,"minecraft:element_77":-88,"minecraft:element_76":-87,"minecraft:element_75":-86,"minecraft:element_74":-85,"minecraft:element_73":-84,"minecraft:element_72":-83,"minecraft:element_71":-82,"minecraft:element_70":-81,"minecraft:element_69":-80,"minecraft:element_68":-79,"minecraft:element_67":-78,"minecraft:element_66":-77,"minecraft:element_65":-76,"minecraft:element_64":-75,"minecraft:element_63":-74,"minecraft:element_62":-73,"minecraft:element_61":-72,"minecraft:element_60":-71,"minecraft:element_59":-70,"minecraft:element_58":-69,"minecraft:element_57":-68,"minecraft:element_56":-67,"minecraft:element_55":-66,"minecraft:element_54":-65,"minecraft:element_53":-64,"minecraft:element_52":-63,"minecraft:element_51":-62,"minecraft:element_50":-61,"minecraft:element_49":-60,"minecraft:element_48":-59,"minecraft:element_47":-58,"minecraft:element_46":-57,"minecraft:element_45":-56,"minecraft:element_44":-55,"minecraft:element_43":-54,"minecraft:element_42":-53,"minecraft:element_41":-52,"minecraft:element_40":-51,"minecraft:element_39":-50,"minecraft:element_38":-49,"minecraft:element_37":-48,"minecraft:element_36":-47,"minecraft:element_35":-46,"minecraft:element_34":-45,"minecraft:element_33":-44,"minecraft:element_32":-43,"minecraft:element_31":-42,"minecraft:element_30":-41,"minecraft:element_29":-40,"minecraft:element_28":-39,"minecraft:element_27":-38,"minecraft:element_26":-37,"minecraft:element_25":-36,"minecraft:element_24":-35,"minecraft:element_23":-34,"minecraft:element_22":-33,"minecraft:element_21":-32,"minecraft:element_20":-31,"minecraft:element_19":-30,"minecraft:element_18":-29,"minecraft:element_17":-28,"minecraft:element_16":-27,"minecraft:element_15":-26,"minecraft:element_14":-25,"minecraft:element_13":-24,"minecraft:element_12":-23,"minecraft:element_11":-22,"minecraft:element_10":-21,"minecraft:element_9":-20,"minecraft:element_8":-19,"minecraft:element_7":-18,"minecraft:element_6":-17,"minecraft:element_5":-16,"minecraft:element_4":-15,"minecraft:element_3":-14,"minecraft:element_2":-13,"minecraft:element_1":-12,"minecraft:blue_ice":-11,"minecraft:stripped_oak_log":-10,"minecraft:stripped_dark_oak_log":-9,"minecraft:stripped_acacia_log":-8,"minecraft:stripped_jungle_log":-7,"minecraft:stripped_birch_log":-6,"minecraft:stripped_spruce_log":-5,"minecraft:prismarine_bricks_stairs":-4,"minecraft:dark_prismarine_stairs":-3,"minecraft:prismarine_stairs":-2,"minecraft:stone":1,"minecraft:grass":2,"minecraft:dirt":3,"minecraft:cobblestone":4,"minecraft:planks":5,"minecraft:sapling":6,"minecraft:bedrock":7,"minecraft:flowing_water":8,"minecraft:water":9,"minecraft:flowing_lava":10,"minecraft:lava":11,"minecraft:sand":12,"minecraft:gravel":13,"minecraft:gold_ore":14,"minecraft:iron_ore":15,"minecraft:coal_ore":16,"minecraft:log":17,"minecraft:leaves":18,"minecraft:sponge":19,"minecraft:glass":20,"minecraft:lapis_ore":21,"minecraft:lapis_block":22,"minecraft:dispenser":23,"minecraft:sandstone":24,"minecraft:noteblock":25,"minecraft:item.bed":26,"minecraft:golden_rail":27,"minecraft:detector_rail":28,"minecraft:sticky_piston":29,"minecraft:web":30,"minecraft:tallgrass":31,"minecraft:deadbush":32,"minecraft:piston":33,"minecraft:pistonarmcollision":34,"minecraft:wool":35,"minecraft:element_0":36,"minecraft:yellow_flower":37,"minecraft:red_flower":38,"minecraft:brown_mushroom":39,"minecraft:red_mushroom":40,"minecraft:gold_block":41,"minecraft:iron_block":42,"minecraft:real_double_stone_slab":43,"minecraft:double_stone_slab":44,"minecraft:brick_block":45,"minecraft:tnt":46,"minecraft:bookshelf":47,"minecraft:mossy_cobblestone":48,"minecraft:obsidian":49,"minecraft:torch":50,"minecraft:fire":51,"minecraft:mob_spawner":52,"minecraft:oak_stairs":53,"minecraft:chest":54,"minecraft:redstone_wire":55,"minecraft:diamond_ore":56,"minecraft:diamond_block":57,"minecraft:crafting_table":58,"minecraft:item.wheat":59,"minecraft:farmland":60,"minecraft:furnace":61,"minecraft:lit_furnace":62,"minecraft:standing_sign":63,"minecraft:item.wooden_door":64,"minecraft:ladder":65,"minecraft:rail":66,"minecraft:stone_stairs":67,"minecraft:wall_sign":68,"minecraft:lever":69,"minecraft:stone_pressure_plate":70,"minecraft:item.iron_door":71,"minecraft:wooden_pressure_plate":72,"minecraft:redstone_ore":73,"minecraft:lit_redstone_ore":74,"minecraft:unlit_redstone_torch":75,"minecraft:redstone_torch":76,"minecraft:stone_button":77,"minecraft:snow_layer":78,"minecraft:ice":79,"minecraft:snow":80,"minecraft:cactus":81,"minecraft:clay":82,"minecraft:item.reeds":83,"minecraft:jukebox":84,"minecraft:fence":85,"minecraft:pumpkin":86,"minecraft:netherrack":87,"minecraft:soul_sand":88,"minecraft:glowstone":89,"minecraft:portal":90,"minecraft:lit_pumpkin":91,"minecraft:item.cake":92,"minecraft:unpowered_repeater":93,"minecraft:powered_repeater":94,"minecraft:invisiblebedrock":95,"minecraft:trapdoor":96,"minecraft:monster_egg":97,"minecraft:stonebrick":98,"minecraft:brown_mushroom_block":99,"minecraft:red_mushroom_block":100,"minecraft:iron_bars":101,"minecraft:glass_pane":102,"minecraft:melon_block":103,"minecraft:pumpkin_stem":104,"minecraft:melon_stem":105,"minecraft:vine":106,"minecraft:fence_gate":107,"minecraft:brick_stairs":108,"minecraft:stone_brick_stairs":109,"minecraft:mycelium":110,"minecraft:waterlily":111,"minecraft:nether_brick":112,"minecraft:nether_brick_fence":113,"minecraft:nether_brick_stairs":114,"minecraft:item.nether_wart":115,"minecraft:enchanting_table":116,"minecraft:brewingstandblock":117,"minecraft:item.cauldron":118,"minecraft:end_portal":119,"minecraft:end_portal_frame":120,"minecraft:end_stone":121,"minecraft:dragon_egg":122,"minecraft:redstone_lamp":123,"minecraft:lit_redstone_lamp":124,"minecraft:dropper":125,"minecraft:activator_rail":126,"minecraft:cocoa":127,"minecraft:sandstone_stairs":128,"minecraft:emerald_ore":129,"minecraft:ender_chest":130,"minecraft:tripwire_hook":131,"minecraft:tripwire":132,"minecraft:emerald_block":133,"minecraft:spruce_stairs":134,"minecraft:birch_stairs":135,"minecraft:jungle_stairs":136,"minecraft:command_block":137,"minecraft:beacon":138,"minecraft:cobblestone_wall":139,"minecraft:item.flower_pot":140,"minecraft:carrots":141,"minecraft:potatoes":142,"minecraft:wooden_button":143,"minecraft:item.skull":144,"minecraft:anvil":145,"minecraft:trapped_chest":146,"minecraft:light_weighted_pressure_plate":147,"minecraft:heavy_weighted_pressure_plate":148,"minecraft:unpowered_comparator":149,"minecraft:powered_comparator":150,"minecraft:daylight_detector":151,"minecraft:redstone_block":152,"minecraft:quartz_ore":153,"minecraft:item.hopper":154,"minecraft:quartz_block":155,"minecraft:quartz_stairs":156,"minecraft:double_wooden_slab":157,"minecraft:wooden_slab":158,"minecraft:stained_hardened_clay":159,"minecraft:stained_glass_pane":160,"minecraft:leaves2":161,"minecraft:log2":162,"minecraft:acacia_stairs":163,"minecraft:dark_oak_stairs":164,"minecraft:slime":165,"minecraft:glow_stick":166,"minecraft:iron_trapdoor":167,"minecraft:prismarine":168,"minecraft:sealantern":169,"minecraft:hay_block":170,"minecraft:carpet":171,"minecraft:hardened_clay":172,"minecraft:coal_block":173,"minecraft:packed_ice":174,"minecraft:double_plant":175,"minecraft:standing_banner":176,"minecraft:wall_banner":177,"minecraft:daylight_detector_inverted":178,"minecraft:red_sandstone":179,"minecraft:red_sandstone_stairs":180,"minecraft:real_double_stone_slab2":181,"minecraft:double_stone_slab2":182,"minecraft:spruce_fence_gate":183,"minecraft:birch_fence_gate":184,"minecraft:jungle_fence_gate":185,"minecraft:dark_oak_fence_gate":186,"minecraft:acacia_fence_gate":187,"minecraft:repeating_command_block":188,"minecraft:chain_command_block":189,"minecraft:hard_glass_pane":190,"minecraft:hard_stained_glass_pane":191,"minecraft:chemical_heat":192,"minecraft:item.spruce_door":193,"minecraft:item.birch_door":194,"minecraft:item.jungle_door":195,"minecraft:item.acacia_door":196,"minecraft:item.dark_oak_door":197,"minecraft:grass_path":198,"minecraft:item.frame":199,"minecraft:chorus_flower":200,"minecraft:purpur_block":201,"minecraft:colored_torch_rg":202,"minecraft:purpur_stairs":203,"minecraft:colored_torch_bp":204,"minecraft:undyed_shulker_box":205,"minecraft:end_bricks":206,"minecraft:frosted_ice":207,"minecraft:end_rod":208,"minecraft:end_gateway":209,"minecraft:magma":213,"minecraft:nether_wart_block":214,"minecraft:red_nether_brick":215,"minecraft:bone_block":216,"minecraft:structure_void":217,"minecraft:shulker_box":218,"minecraft:purple_glazed_terracotta":219,"minecraft:white_glazed_terracotta":220,"minecraft:orange_glazed_terracotta":221,"minecraft:magenta_glazed_terracotta":222,"minecraft:light_blue_glazed_terracotta":223,"minecraft:yellow_glazed_terracotta":224,"minecraft:lime_glazed_terracotta":225,"minecraft:pink_glazed_terracotta":226,"minecraft:gray_glazed_terracotta":227,"minecraft:silver_glazed_terracotta":228,"minecraft:cyan_glazed_terracotta":229,"minecraft:blue_glazed_terracotta":231,"minecraft:brown_glazed_terracotta":232,"minecraft:green_glazed_terracotta":233,"minecraft:red_glazed_terracotta":234,"minecraft:black_glazed_terracotta":235,"minecraft:concrete":236,"minecraft:concrete_powder":237,"minecraft:chemistry_table":238,"minecraft:underwater_torch":239,"minecraft:chorus_plant":240,"minecraft:stained_glass":241,"minecraft:item.camera":242,"minecraft:podzol":243,"minecraft:item.beetroot":244,"minecraft:stonecutter":245,"minecraft:glowingobsidian":246,"minecraft:netherreactor":247,"minecraft:info_update":248,"minecraft:info_update2":249,"minecraft:movingblock":250,"minecraft:observer":251,"minecraft:structure_block":252,"minecraft:hard_glass":253,"minecraft:hard_stained_glass":254,"minecraft:reserved6":255,"minecraft:iron_shovel":256,"minecraft:iron_pickaxe":257,"minecraft:iron_axe":258,"minecraft:flint_and_steel":259,"minecraft:apple":260,"minecraft:bow":261,"minecraft:arrow":262,"minecraft:coal":263,"minecraft:diamond":264,"minecraft:iron_ingot":265,"minecraft:gold_ingot":266,"minecraft:iron_sword":267,"minecraft:wooden_sword":268,"minecraft:wooden_shovel":269,"minecraft:wooden_pickaxe":270,"minecraft:wooden_axe":271,"minecraft:stone_sword":272,"minecraft:stone_shovel":273,"minecraft:stone_pickaxe":274,"minecraft:stone_axe":275,"minecraft:diamond_sword":276,"minecraft:diamond_shovel":277,"minecraft:diamond_pickaxe":278,"minecraft:diamond_axe":279,"minecraft:stick":280,"minecraft:bowl":281,"minecraft:mushroom_stew":282,"minecraft:golden_sword":283,"minecraft:golden_shovel":284,"minecraft:golden_pickaxe":285,"minecraft:golden_axe":286,"minecraft:string":287,"minecraft:feather":288,"minecraft:gunpowder":289,"minecraft:wooden_hoe":290,"minecraft:stone_hoe":291,"minecraft:iron_hoe":292,"minecraft:diamond_hoe":293,"minecraft:golden_hoe":294,"minecraft:wheat_seeds":295,"minecraft:wheat":296,"minecraft:bread":297,"minecraft:leather_helmet":298,"minecraft:leather_chestplate":299,"minecraft:leather_leggings":300,"minecraft:leather_boots":301,"minecraft:chainmail_helmet":302,"minecraft:chainmail_chestplate":303,"minecraft:chainmail_leggings":304,"minecraft:chainmail_boots":305,"minecraft:iron_helmet":306,"minecraft:iron_chestplate":307,"minecraft:iron_leggings":308,"minecraft:iron_boots":309,"minecraft:diamond_helmet":310,"minecraft:diamond_chestplate":311,"minecraft:diamond_leggings":312,"minecraft:diamond_boots":313,"minecraft:golden_helmet":314,"minecraft:golden_chestplate":315,"minecraft:golden_leggings":316,"minecraft:golden_boots":317,"minecraft:flint":318,"minecraft:porkchop":319,"minecraft:cooked_porkchop":320,"minecraft:painting":321,"minecraft:golden_apple":322,"minecraft:sign":323,"minecraft:wooden_door":324,"minecraft:bucket":325,"minecraft:minecart":328,"minecraft:saddle":329,"minecraft:iron_door":330,"minecraft:redstone":331,"minecraft:snowball":332,"minecraft:boat":333,"minecraft:leather":334,"minecraft:kelp":335,"minecraft:brick":336,"minecraft:clay_ball":337,"minecraft:reeds":338,"minecraft:paper":339,"minecraft:book":340,"minecraft:slime_ball":341,"minecraft:chest_minecart":342,"minecraft:egg":344,"minecraft:compass":345,"minecraft:fishing_rod":346,"minecraft:clock":347,"minecraft:glowstone_dust":348,"minecraft:fish":349,"minecraft:cooked_fish":350,"minecraft:dye":351,"minecraft:bone":352,"minecraft:sugar":353,"minecraft:cake":354,"minecraft:bed":355,"minecraft:repeater":356,"minecraft:cookie":357,"minecraft:map":358,"minecraft:shears":359,"minecraft:melon":360,"minecraft:pumpkin_seeds":361,"minecraft:melon_seeds":362,"minecraft:beef":363,"minecraft:cooked_beef":364,"minecraft:chicken":365,"minecraft:cooked_chicken":366,"minecraft:rotten_flesh":367,"minecraft:ender_pearl":368,"minecraft:blaze_rod":369,"minecraft:ghast_tear":370,"minecraft:gold_nugget":371,"minecraft:nether_wart":372,"minecraft:potion":373,"minecraft:glass_bottle":374,"minecraft:spider_eye":375,"minecraft:fermented_spider_eye":376,"minecraft:blaze_powder":377,"minecraft:magma_cream":378,"minecraft:brewing_stand":379,"minecraft:cauldron":380,"minecraft:ender_eye":381,"minecraft:speckled_melon":382,"minecraft:spawn_egg":383,"minecraft:experience_bottle":384,"minecraft:fireball":385,"minecraft:writable_book":386,"minecraft:written_book":387,"minecraft:emerald":388,"minecraft:frame":389,"minecraft:flower_pot":390,"minecraft:carrot":391,"minecraft:potato":392,"minecraft:baked_potato":393,"minecraft:poisonous_potato":394,"minecraft:emptymap":395,"minecraft:golden_carrot":396,"minecraft:skull":397,"minecraft:carrotonastick":398,"minecraft:netherstar":399,"minecraft:pumpkin_pie":400,"minecraft:fireworks":401,"minecraft:fireworkscharge":402,"minecraft:enchanted_book":403,"minecraft:comparator":404,"minecraft:netherbrick":405,"minecraft:quartz":406,"minecraft:tnt_minecart":407,"minecraft:hopper_minecart":408,"minecraft:prismarine_shard":409,"minecraft:hopper":410,"minecraft:rabbit":411,"minecraft:cooked_rabbit":412,"minecraft:rabbit_stew":413,"minecraft:rabbit_foot":414,"minecraft:rabbit_hide":415,"minecraft:horsearmorleather":416,"minecraft:horsearmoriron":417,"minecraft:horsearmorgold":418,"minecraft:horsearmordiamond":419,"minecraft:lead":420,"minecraft:name_tag":421,"minecraft:prismarine_crystals":422,"minecraft:muttonraw":423,"minecraft:muttoncooked":424,"minecraft:armor_stand":425,"minecraft:end_crystal":426,"minecraft:spruce_door":427,"minecraft:birch_door":428,"minecraft:jungle_door":429,"minecraft:acacia_door":430,"minecraft:dark_oak_door":431,"minecraft:chorus_fruit":432,"minecraft:chorus_fruit_popped":433,"minecraft:banner_pattern":434,"minecraft:dragon_breath":437,"minecraft:splash_potion":438,"minecraft:lingering_potion":441,"minecraft:sparkler":442,"minecraft:command_block_minecart":443,"minecraft:elytra":444,"minecraft:shulker_shell":445,"minecraft:banner":446,"minecraft:medicine":447,"minecraft:balloon":448,"minecraft:rapid_fertilizer":449,"minecraft:totem":450,"minecraft:bleach":451,"minecraft:iron_nugget":452,"minecraft:ice_bomb":453,"minecraft:trident":455,"minecraft:beetroot":457,"minecraft:beetroot_seeds":458,"minecraft:beetroot_soup":459,"minecraft:salmon":460,"minecraft:clownfish":461,"minecraft:pufferfish":462,"minecraft:cooked_salmon":463,"minecraft:dried_kelp":464,"minecraft:nautilus_shell":465,"minecraft:appleenchanted":466,"minecraft:heart_of_the_sea":467,"minecraft:turtle_shell_piece":468,"minecraft:turtle_helmet":469,"minecraft:phantom_membrane":470,"minecraft:crossbow":471,"minecraft:spruce_sign":472,"minecraft:birch_sign":473,"minecraft:jungle_sign":474,"minecraft:acacia_sign":475,"minecraft:darkoak_sign":476,"minecraft:sweet_berries":477,"minecraft:camera":498,"minecraft:compound":499,"minecraft:record_13":500,"minecraft:record_cat":501,"minecraft:record_blocks":502,"minecraft:record_chirp":503,"minecraft:record_far":504,"minecraft:record_mall":505,"minecraft:record_mellohi":506,"minecraft:record_stal":507,"minecraft:record_strad":508,"minecraft:record_ward":509,"minecraft:record_11":510,"minecraft:record_wait":511,"minecraft:shield":513,"minecraft:campfire":720,"minecraft:suspicious_stew":734,"minecraft:honeycomb":736,"minecraft:honey_bottle":737}
 	idlist
bid experimental hasspawnegg idminecraft:snow_golemrid*
summonable bid experimental hasspawneggid
minecraft:cowrid
summonable bid experimental hasspawneggidminecraft:wandering_traderrid
summonable bid experimental hasspawneggid
minecraft:foxrid
summonable bid experimental hasspawneggid
minecraft:beerid
summonable bid experimental hasspawnegg idminecraft:tripod_camerarid|
summonable  bid experimental hasspawnegg idminecraft:balloonrid
summonable  bid experimental hasspawnegg idminecraft:ice_bombrid
summonable  bid experimental hasspawnegg idminecraft:agentridp
summonable  bid experimental hasspawneggidminecraft:pillagerrid
summonable bid experimental hasspawneggid
minecraft:vexrid
summonable bid experimental hasspawneggidminecraft:evocation_illagerrid
summonable bid experimental hasspawnegg idminecraft:evocation_fangrid
summonable bid experimental hasspawnegg idminecraft:fireworks_rocketrid
summonable bid experimental hasspawnegg idminecraft:lingering_potionrid
summonable  bid experimental hasspawnegg idminecraft:area_effect_cloudrid
summonable  bid experimental hasspawnegg idminecraft:llama_spitrid
summonable  bid experimental hasspawnegg idminecraft:small_fireballrid
summonable  bid experimental hasspawnegg idminecraft:lightning_boltrid
summonable bid
minecraft:experimental hasspawnegg id
minecraft:npcrid
summonable  bid experimental hasspawnegg idminecraft:boatrid
summonable bid
minecraft:experimental hasspawnegg idminecraft:playerrid
summonable  bid experimental hasspawnegg id minecraft:wither_skull_dangerousrid
summonable  bid experimental hasspawnegg idminecraft:wither_skullrid
summonable  bid experimental hasspawnegg idminecraft:leash_knotrid
summonable bid experimental hasspawnegg idminecraft:ender_pearlrid
summonable  bid experimental hasspawnegg idminecraft:splash_potionrid
summonable bid experimental hasspawnegg idminecraft:fireballrid
summonable  bid experimental hasspawneggidminecraft:zombie_pigmanridH
summonable bid experimental hasspawneggidminecraft:villager_v2rid
summonable  bid experimental hasspawneggidminecraft:creeperridB
summonable bid experimental hasspawneggid
minecraft:codrid
summonable bid experimental hasspawneggidminecraft:zombierid@
summonable bid experimental hasspawneggidminecraft:tropicalfishrid
summonable bid experimental hasspawneggidminecraft:zombie_horserid6
summonable bid experimental hasspawneggidminecraft:skeleton_horserid4
summonable bid experimental hasspawneggidminecraft:mulerid2
summonable bid experimental hasspawneggidminecraft:donkeyrid0
summonable bid experimental hasspawneggidminecraft:dolphinrid>
summonable bid experimental hasspawneggidminecraft:drownedrid
summonable bid experimental hasspawneggidminecraft:spiderridF
summonable bid experimental hasspawneggidminecraft:salmonrid
summonable bid experimental hasspawneggidminecraft:parrotrid<
summonable bid experimental hasspawneggidminecraft:skeletonridD
summonable bid experimental hasspawneggidminecraft:pandarid
summonable bid experimental hasspawneggidminecraft:pufferfishrid
summonable bid experimental hasspawneggidminecraft:llamarid:
summonable bid experimental hasspawneggidminecraft:slimeridJ
summonable bid experimental hasspawneggidminecraft:zombie_villager_v2rid
summonable  bid experimental hasspawneggidminecraft:turtlerid
summonable bid experimental hasspawneggidminecraft:silverfishridN
summonable bid experimental hasspawnegg idminecraft:villagerrid
summonable bid experimental hasspawneggidminecraft:wolfrid
summonable bid experimental hasspawneggidminecraft:sheeprid
summonable bid experimental hasspawneggid
minecraft:pigrid
summonable bid experimental hasspawneggidminecraft:endermanridL
summonable bid experimental hasspawneggid
minecraft:catrid
summonable bid experimental hasspawneggidminecraft:chickenrid
summonable bid experimental hasspawneggidminecraft:mooshroomrid 
summonable bid experimental hasspawneggidminecraft:squidrid"
summonable bid experimental hasspawnegg idminecraft:hopper_minecartrid
summonable bid experimental hasspawneggidminecraft:rabbitrid$
summonable bid experimental hasspawnegg idminecraft:tnt_minecartrid
summonable bid experimental hasspawneggid
minecraft:batrid&
summonable bid experimental hasspawnegg idminecraft:chest_minecartrid
summonable bid experimental hasspawnegg idminecraft:iron_golemrid(
summonable bid experimental hasspawneggidminecraft:ocelotrid,
summonable bid experimental hasspawneggidminecraft:horserid.
summonable bid experimental hasspawneggidminecraft:polar_bearrid8
summonable bid experimental hasspawneggidminecraft:cave_spiderridP
summonable bid experimental hasspawneggidminecraft:ghastridR
summonable bid experimental hasspawnegg idminecraft:elder_guardian_ghostrid
summonable bid experimental hasspawneggidminecraft:magma_cuberidT
summonable bid experimental hasspawneggidminecraft:blazeridV
summonable bid experimental hasspawnegg idminecraft:zombie_villagerridX
summonable bid experimental hasspawneggidminecraft:witchridZ
summonable bid experimental hasspawneggidminecraft:strayrid\
summonable bid experimental hasspawneggidminecraft:huskrid^
summonable bid experimental hasspawneggidminecraft:wither_skeletonrid`
summonable bid experimental hasspawneggidminecraft:guardianridb
summonable bid experimental hasspawneggidminecraft:elder_guardianridd
summonable bid experimental hasspawneggidminecraft:vindicatorridr
summonable bid experimental hasspawneggidminecraft:phantomridt
summonable bid experimental hasspawneggidminecraft:ravagerridv
summonable bid experimental hasspawnegg idminecraft:witherridh
summonable bid experimental hasspawnegg idminecraft:ender_dragonridj
summonable bid experimental hasspawneggidminecraft:shulkerridl
summonable bid experimental hasspawneggidminecraft:endermiteridn
summonable bid experimental hasspawnegg idminecraft:minecartrid
summonable bid experimental hasspawnegg id minecraft:command_block_minecartrid
summonable bid experimental hasspawnegg idminecraft:armor_standridz
summonable bid experimental hasspawnegg idminecraft:itemrid
summonable  bid experimental hasspawnegg id
minecraft:tntrid
summonable bid experimental hasspawnegg idminecraft:falling_blockrid
summonable  bid experimental hasspawnegg idminecraft:xp_bottlerid
summonable bid experimental hasspawnegg idminecraft:xp_orbrid
summonable bid experimental hasspawnegg idminecraft:eye_of_ender_signalrid
summonable  bid experimental hasspawnegg idminecraft:ender_crystalrid
summonable bid experimental hasspawnegg idminecraft:shulker_bulletrid
summonable  bid experimental hasspawnegg idminecraft:fishing_hookrid
summonable  bid experimental hasspawnegg idminecraft:dragon_fireballrid
summonable  bid experimental hasspawnegg idminecraft:arrowrid
summonable bid experimental hasspawnegg idminecraft:snowballrid
summonable bid experimental hasspawnegg id
minecraft:eggrid
summonable bid experimental hasspawnegg idminecraft:paintingrid
summonable  bid experimental hasspawnegg idminecraft:thrown_tridentrid
summonable   
 

bamboo_jungledownfallfff?
minecraft:climatedownfallfff?temperature33s? 
 minecraft:world_generation_rules	extended_edge_transformation
	condition{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"jungle"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"ocean"},{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"forest"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"cold"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"hills"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mega"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"birch"}]}]}
min_passing_neighbors	transforms_into
biomejungle_edgeweight  	hills_transformation
biomebamboo_jungle_hillsweight  	tags
animalbamboojunglemonster	overworldtemperature33s? 
bamboo_jungle_hillsdownfallfff?
minecraft:climatedownfallfff?temperature33s? 
 minecraft:world_generation_rules	extended_edge_transformation
	condition{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"jungle"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"ocean"},{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"forest"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"cold"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"hills"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mega"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"birch"}]}]}
min_passing_neighbors	transforms_into
biomejungle_edgeweight   	tagsanimalbamboohillsjunglemonster	overworldtemperature33s? 
beachdownfall>
minecraft:climatedownfall>temperatureL? 	tagsbeachmonster	overworldwarmtemperatureL? 
birch_forestdownfall?
minecraft:climatedownfall?temperature? 
 minecraft:world_generation_rules	generate_for_climates
temperature weight 	hills_transformation
biomebirch_forest_hillsweight 	mutate_transformation
biomebirch_forest_mutatedweight  	tags
animalbirchforestmonster	overworldtemperature? 
birch_forest_hillsdownfall?
minecraft:climatedownfall?temperature? 
 minecraft:world_generation_rules	mutate_transformation
biomebirch_forest_hills_mutatedweight  	tagsanimalbirchforesthillsmonster	overworldtemperature? 
birch_forest_hills_mutateddownfallL?
minecraft:climatedownfallL?temperature333? 	tagsanimalbirchforesthillsmonstermutatedoverworld_generationtemperature333? 
birch_forest_mutateddownfallL?
minecraft:climatedownfallL?temperature333? 	tagsanimalbirchforestmonstermutatedoverworld_generationtemperature333? 

cold_beachdownfall>
minecraft:climatedownfall>temperatureL= 
 minecraft:world_generation_rules	shore_transformation
biome
cold_beachweight  	tagsbeachcoldmonster	overworldtemperatureL= 

cold_oceandownfall   ?
minecraft:climatedownfall   ?temperature   ? 
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	river_transformation
biome
cold_oceanweight 	shore_transformation
biome
cold_oceanweight  	tagscoldmonsterocean	overworldtemperature   ? 

cold_taigadownfall>
minecraft:climatedownfall>temperature    
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	hills_transformation
biomecold_taiga_hillsweight 	mutate_transformation
biomecold_taiga_mutatedweight 	shore_transformation
biome
cold_beachweight  	tagsanimalcoldforestmonster	overworldtaigatemperature    
cold_taiga_hillsdownfall>
minecraft:climatedownfall>temperature    
 minecraft:world_generation_rules	shore_transformation
biome
cold_beachweight  	tagsanimalcoldforesthillsmonster	overworldtaigatemperature    
cold_taiga_mutateddownfall>
minecraft:climatedownfall>temperature    	tagsanimalcoldforestmonstermutatedoverworld_generationtaigatemperature    
deep_cold_oceandownfall   ?
minecraft:climatedownfall   ?temperature   ? 
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	river_transformation
biomedeep_cold_oceanweight 	shore_transformation
biomedeep_cold_oceanweight  	tags
colddeepmonsterocean	overworldtemperature   ? 
deep_frozen_oceandownfall   ?
minecraft:climatedownfall   ?temperature     
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	river_transformation
biomedeep_frozen_oceanweight 	shore_transformation
biomedeep_frozen_oceanweight  	tags
deepfrozenmonsterocean	overworldtemperature     
deep_lukewarm_oceandownfall   ?
minecraft:climatedownfall   ?temperature   ? 
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	river_transformation
biomedeep_lukewarm_oceanweight 	shore_transformation
biomedeep_lukewarm_oceanweight  	tags
deeplukewarmmonsterocean	overworldtemperature   ? 

deep_oceandownfall   ?
minecraft:climatedownfall   ?temperature   ? 
 minecraft:world_generation_rules	generate_for_climates
temperature weight 	hills_transformation
biomeplainsweight biomeforestweight 	river_transformation
biome
deep_oceanweight 	shore_transformation
biome
deep_oceanweight  	tagsdeepmonsterocean	overworldtemperature   ? 
deep_warm_oceandownfall   ?
minecraft:climatedownfall   ?temperature   ? 
 minecraft:world_generation_rules	river_transformation
biomedeep_warm_oceanweight 	shore_transformation
biomedeep_warm_oceanweight  	tags
deepmonsterocean	overworldwarmtemperature   ? 
desertdownfall    
minecraft:climatedownfall    temperature   @ 
'minecraft:legacy_world_generation_rules	$legacy_pre_hills_edge_transformation
	condition{"all_of":[{"operator":0,"subject":0,"test":"has_biome_tag","value":"ice_plains"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mutated"}]}
min_passing_neighbors	transforms_into
biomeextreme_hills_plus_treesweight   
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	hills_transformation
biomedesert_hillsweight 	mutate_transformation
biomedesert_mutatedweight 	pre_hills_edge_transformation
	condition{"all_of":[{"operator":0,"subject":0,"test":"has_biome_tag","value":"ice_plains"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mutated"}]}
min_passing_neighbors	transforms_into
biomeextreme_hills_plus_treesweight   	tagsdesertmonster	overworldtemperature   @ 
desert_hillsdownfall    
minecraft:climatedownfall    temperature   @ 	tagsdeserthillsmonster	overworldtemperature   @ 
desert_mutateddownfall    
minecraft:climatedownfall    temperature   @ 	tagsdesertmonstermutatedoverworld_generationtemperature   @ 

extreme_hillsdownfall>
minecraft:climatedownfall>temperatureL> 
'minecraft:legacy_world_generation_rules	$legacy_pre_hills_edge_transformation
	condition{"all_of":[{"any_of":[{"operator":3,"subject":0,"test":"is_temperature_value","value":0.2000000029802322},{"operator":4,"subject":0,"test":"is_temperature_value","value":1.0}]}]}
min_passing_neighbors	transforms_into
biomeextreme_hills_edgeweight   
 minecraft:world_generation_rules	generate_for_climates
temperature weight temperatureweight 	hills_transformation
biomeextreme_hills_plus_treesweight 	mutate_transformation
biomeextreme_hills_mutatedweight 	pre_hills_edge_transformation
	condition{"all_of":[{"any_of":[{"operator":3,"subject":0,"test":"is_temperature_value","value":0.2000000029802322},{"operator":4,"subject":0,"test":"is_temperature_value","value":1.0}]}]}
min_passing_neighbors	transforms_into
biomeextreme_hills_edgeweight  	shore_transformation
biomestone_beachweight  	tagsanimal
extreme_hillsmonster	overworldtemperatureL> 
extreme_hills_edgedownfall>
minecraft:climatedownfall>temperatureL> 
 minecraft:world_generation_rules	shore_transformation
biomestone_beachweight  	tagsanimaledge
extreme_hillsmonstermountain	overworldtemperatureL> 
extreme_hills_mutateddownfall>
minecraft:climatedownfall>temperatureL> 	tags
animal
extreme_hillsmonstermutated	overworldtemperatureL> 
extreme_hills_plus_treesdownfall>
minecraft:climatedownfall>temperatureL> 
 minecraft:world_generation_rules	mutate_transformation
biome extreme_hills_plus_trees_mutatedweight 	shore_transformation
biomestone_beachweight  	tagsanimal
extreme_hillsforestmonstermountain	overworldtemperatureL> 
 extreme_hills_plus_trees_mutateddownfall>
minecraft:climatedownfall>temperatureL> 	tagsanimal
extreme_hillsforestmonstermutated	overworldtemperatureL> 

flower_forestdownfallL?
minecraft:climatedownfallL?temperature333? 	tags
flower_forestmonstermutated	overworldtemperature333? 
forestdownfallL?
minecraft:climatedownfallL?temperature333? 
 minecraft:world_generation_rules	generate_for_climates
temperature weight temperatureweight 	hills_transformation
biomeforest_hillsweight 	mutate_transformation
biome
flower_forestweight  	tagsanimalforestmonster	overworldtemperature333? 
forest_hillsdownfallL?
minecraft:climatedownfallL?temperature333? 	tags
animalforest_generationhillsmonster	overworldtemperature333? 
frozen_oceandownfall   ?
minecraft:climatedownfall   ?temperature     
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	river_transformation
biomefrozen_oceanweight 	shore_transformation
biomefrozen_oceanweight  	tagsfrozenmonsterocean	overworldtemperature     
frozen_riverdownfall   ?
minecraft:climatedownfall   ?temperature     
 minecraft:world_generation_rules	shore_transformation
biome
cold_beachweight  	tagsfrozen	overworldrivertemperature     
helldownfall    
minecraft:climatedownfall    temperature   @ 	tagsnethertemperature   @ 

ice_mountainsdownfall   ?
minecraft:climatedownfall   ?temperature     
 minecraft:world_generation_rules	shore_transformation
biome
cold_beachweight  	tagsfrozenicemountain	overworldtemperature     

ice_plainsdownfall   ?
minecraft:climatedownfall   ?temperature     
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	hills_transformation
biome
ice_mountainsweight 	mutate_transformation
biomeice_plains_spikesweight 	river_transformation
biomefrozen_riverweight 	shore_transformation
biome
cold_beachweight  	tagsfrozenice
ice_plains	overworldtemperature     
ice_plains_spikesdownfall  ?
minecraft:climatedownfall  ?temperature     
 minecraft:world_generation_rules	shore_transformation
biome
cold_beachweight  	tags
frozen
ice_plainsmonstermutated	overworldtemperature     
jungledownfallfff?
minecraft:climatedownfallfff?temperature33s? 
 minecraft:world_generation_rules	extended_edge_transformation
	condition{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"jungle"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"ocean"},{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"forest"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"cold"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"hills"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mega"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"birch"}]}]}
min_passing_neighbors	transforms_into
biomejungle_edgeweight  	generate_for_climates
temperature weight 	hills_transformation
biomejungle_hillsweight 	mutate_transformation
biomejungle_mutatedweight  	tags
animaljunglemonster	overworldraretemperature33s? 
jungle_edgedownfallL?
minecraft:climatedownfallL?temperature33s? 
 minecraft:world_generation_rules	extended_edge_transformation
	condition{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"jungle"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"ocean"},{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"forest"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"cold"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"hills"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mega"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"birch"}]}]}
min_passing_neighbors	transforms_into
biomejungle_edgeweight  	mutate_transformation
biomejungle_edge_mutatedweight  	tags
animaledgejunglemonster	overworldtemperature33s? 
jungle_edge_mutateddownfallL?
minecraft:climatedownfallL?temperature33s? 
 minecraft:world_generation_rules	extended_edge_transformation
	condition{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"jungle"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"ocean"},{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"forest"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"cold"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"hills"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mega"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"birch"}]}]}
min_passing_neighbors	transforms_into
biomejungle_edgeweight   	tagsanimaledgejunglemonstermutatedoverworld_generationtemperature33s? 
jungle_hillsdownfallfff?
minecraft:climatedownfallfff?temperature33s? 
 minecraft:world_generation_rules	extended_edge_transformation
	condition{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"jungle"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"ocean"},{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"forest"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"cold"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"hills"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mega"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"birch"}]}]}
min_passing_neighbors	transforms_into
biomejungle_edgeweight   	tags
animalhillsjunglemonster	overworldtemperature33s? 
jungle_mutateddownfallfff?
minecraft:climatedownfallfff?temperature33s? 
 minecraft:world_generation_rules	extended_edge_transformation
	condition{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"jungle"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"ocean"},{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"forest"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"cold"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"hills"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mega"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"birch"}]}]}
min_passing_neighbors	transforms_into
biomejungle_edgeweight   	tags
animaljunglemonstermutatedoverworld_generationtemperature33s? 
legacy_frozen_oceandownfall   ?
minecraft:climatedownfall   ?temperature     
 minecraft:world_generation_rules	river_transformation
biomelegacy_frozen_oceanweight 	shore_transformation
biomelegacy_frozen_oceanweight  	tagsfrozenocean	overworldtemperature     
lukewarm_oceandownfall   ?
minecraft:climatedownfall   ?temperature   ? 
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	river_transformation
biomelukewarm_oceanweight 	shore_transformation
biomelukewarm_oceanweight  	tagslukewarmmonsterocean	overworldtemperature   ? 

mega_taigadownfallL?
minecraft:climatedownfallL?temperature> 
'minecraft:legacy_world_generation_rules	$legacy_pre_hills_edge_transformation
	conditionO{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"taiga"}]}
min_passing_neighbors	transforms_into
biometaigaweight   
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	hills_transformation
biomemega_taiga_hillsweight 	mutate_transformation
biomeredwood_taiga_mutatedweight 	pre_hills_edge_transformation
	conditionO{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"taiga"}]}
min_passing_neighbors	transforms_into
biometaigaweight   	tagsanimalforestmegamonster	overworldraretaigatemperature> 
mega_taiga_hillsdownfallL?
minecraft:climatedownfallL?temperature> 
 minecraft:world_generation_rules	mutate_transformation
biomeredwood_taiga_hills_mutatedweight  	tagsanimalforesthillsmegamonster	overworldtaigatemperature> 
mesadownfall    
minecraft:climatedownfall    temperature   @ 
 minecraft:world_generation_rules	extended_edge_transformation
	condition{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"mesa"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"ocean"}]}
min_passing_neighbors	transforms_into
biomedesertweight  	mutate_transformation
biome
mesa_bryceweight 	shore_transformation
biomemesaweight  	tagsmesamonster	overworldtemperature   @ 

mesa_brycedownfall    
minecraft:climatedownfall    temperature   @ 	tags
animalmesamonstermutated	overworldtemperature   @ 
mesa_plateaudownfall    
minecraft:climatedownfall    temperature   @ 
'minecraft:legacy_world_generation_rules	$legacy_pre_hills_edge_transformation
	condition{"all_of":[{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"plateau"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mesa"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"}]}]}
min_passing_neighbors	transforms_into
biomemesaweight   
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	hills_transformation
biomemesaweight 	mutate_transformation
biomemesa_plateau_mutatedweight 	pre_hills_edge_transformation
	condition{"all_of":[{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"plateau"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mesa"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"}]}]}
min_passing_neighbors	transforms_into
biomemesaweight   	tags
mesamonster	overworldplateauraretemperature   @ 
mesa_plateau_mutateddownfall    
minecraft:climatedownfall    temperature   @ 	tagsmesamonstermutated	overworldplateaustonetemperature   @ 
mesa_plateau_stonedownfall    
minecraft:climatedownfall    temperature   @ 
'minecraft:legacy_world_generation_rules	$legacy_pre_hills_edge_transformation
	condition{"all_of":[{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"plateau"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mesa"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"}]}]}
min_passing_neighbors	transforms_into
biomemesaweight   
 minecraft:world_generation_rules	extended_edge_transformation
	condition{"all_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"mesa"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"ocean"}]}
min_passing_neighbors	transforms_into
biomedesertweight  	generate_for_climates
temperatureweight 	hills_transformation
biomemesaweight 	mutate_transformation
biomemesa_plateau_stone_mutatedweight 	pre_hills_edge_transformation
	condition{"all_of":[{"any_of":[{"operator":1,"subject":0,"test":"has_biome_tag","value":"plateau"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mesa"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"mutated"}]}]}
min_passing_neighbors	transforms_into
biomemesaweight  	shore_transformation
biomemesa_plateau_stoneweight  	tagsmesamonster	overworldplateaurarestonetemperature   @ 
mesa_plateau_stone_mutateddownfall    
minecraft:climatedownfall    temperature   @ 	tags
mesamonstermutated	overworldplateautemperature   @ 
mushroom_islanddownfall  ?
minecraft:climatedownfall  ?temperaturefff? 
 minecraft:world_generation_rules	river_transformation
biomemushroom_island_shoreweight 	shore_transformation
biomemushroom_island_shoreweight  	tagsmooshroom_island	overworldtemperaturefff? 
mushroom_island_shoredownfall  ?
minecraft:climatedownfall  ?temperaturefff? 
 minecraft:world_generation_rules	river_transformation
biomemushroom_island_shoreweight  	tagsmooshroom_island	overworldshoretemperaturefff? 
oceandownfall   ?
minecraft:climatedownfall   ?temperature   ? 
 minecraft:world_generation_rules	generate_for_climates
temperature weight 	hills_transformation
biome
deep_oceanweight 	river_transformation
biomeoceanweight 	shore_transformation
biomeoceanweight  	tagsmonsterocean	overworldtemperature   ? 
plainsdownfall>
minecraft:climatedownfall>temperatureL? 
 minecraft:world_generation_rules	generate_for_climates
temperature weight temperatureweight temperatureweight 	hills_transformation
biomeforest_hillsweight biomeforestweight 	mutate_transformation
biomesunflower_plainsweight  	tagsanimalmonster	overworldplainstemperatureL? 
redwood_taiga_hills_mutateddownfallL?
minecraft:climatedownfallL?temperature> 	tagsanimalforesthillsmegamonstermutatedoverworld_generationtaigatemperature> 
redwood_taiga_mutateddownfallL?
minecraft:climatedownfallL?temperature  > 	tagsanimalforestmegamonstermutated	overworldtaigatemperature  > 
riverdownfall   ?
minecraft:climatedownfall   ?temperature   ? 
 minecraft:world_generation_rules	shore_transformation
biomeriverweight  	tags	overworldrivertemperature   ? 

roofed_forestdownfallL?
minecraft:climatedownfallL?temperature333? 
 minecraft:world_generation_rules	generate_for_climates
temperature weight 	hills_transformation
biomeplainsweight 	mutate_transformation
biomeroofed_forest_mutatedweight  	tagsanimalforestmonsterno_legacy_worldgen	overworldroofedtemperature333? 
roofed_forest_mutateddownfallL?
minecraft:climatedownfallL?temperature333? 	tagsanimalforestmonstermutatedoverworld_generationroofedtemperature333? 
savannadownfall    
minecraft:climatedownfall    temperature? 
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	hills_transformation
biomesavanna_plateauweight 	mutate_transformation
biomesavanna_mutatedweight  	tagsanimalmonster	overworldsavannatemperature? 
savanna_mutateddownfall   ?
minecraft:climatedownfall   ?temperaturě? 	tags
animalmonstermutated	overworldsavannatemperaturě? 
savanna_plateaudownfall    
minecraft:climatedownfall    temperature  ? 
 minecraft:world_generation_rules	mutate_transformation
biomesavanna_plateau_mutatedweight  	tags
animalmonster	overworldplateausavannatemperature  ? 
savanna_plateau_mutateddownfall   ?
minecraft:climatedownfall   ?temperature  ? 	tagsanimalmonstermutated	overworldplateausavannatemperature  ? 
stone_beachdownfall>
minecraft:climatedownfall>temperatureL> 	tagsbeachmonster	overworldstonetemperatureL> 
sunflower_plainsdownfall>
minecraft:climatedownfall>temperatureL? 	tags
animalmonstermutated	overworldplainstemperatureL? 
	swamplanddownfall   ?
minecraft:climatedownfall   ?temperatureL? 
'minecraft:legacy_world_generation_rules	$legacy_pre_hills_edge_transformation   
 minecraft:world_generation_rules	generate_for_climates
temperature weight 	mutate_transformation
biomeswampland_mutatedweight 	pre_hills_edge_transformation
	condition{"all_of":[{"any_of":[{"all_of":[{"operator":0,"subject":0,"test":"has_biome_tag","value":"desert"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"hills"}]},{"all_of":[{"operator":0,"subject":0,"test":"has_biome_tag","value":"taiga"},{"operator":0,"subject":0,"test":"has_biome_tag","value":"cold"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"hills"}]},{"all_of":[{"operator":0,"subject":0,"test":"has_biome_tag","value":"ice_plains"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mutated"}]}]}]}
min_passing_neighbors	transforms_into
biomeplainsweight  	condition{"all_of":[{"operator":0,"subject":0,"test":"has_biome_tag","value":"jungle"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"mutated"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"edge"},{"operator":1,"subject":0,"test":"has_biome_tag","value":"hills"}]}
min_passing_neighbors	transforms_into
biomejungle_edgeweight  	shore_transformation
biome	swamplandweight  	tagsanimalmonster	overworldswamptemperatureL? 
swampland_mutateddownfall   ?
minecraft:climatedownfall   ?temperatureL? 	tags
animalmonstermutatedoverworld_generationswamptemperatureL? 
taigadownfallL?
minecraft:climatedownfallL?temperature  > 
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	hills_transformation
biometaiga_hillsweight 	mutate_transformation
biome
taiga_mutatedweight  	tags
animalforestmonster	overworldtaigatemperature  > 
taiga_hillsdownfallL?
minecraft:climatedownfallL?temperature  > 	tagsanimalforesthillsmonster	overworldtaigatemperature  > 

taiga_mutateddownfallL?
minecraft:climatedownfallL?temperature  > 	tagsanimalforestmonstermutatedoverworld_generationtaigatemperature  > 
the_enddownfall   ?
minecraft:climatedownfall   ?temperature   ? 	tagsthe_endtemperature   ? 

warm_oceandownfall   ?
minecraft:climatedownfall   ?temperature   ? 
 minecraft:world_generation_rules	generate_for_climates
temperatureweight 	river_transformation
biome
warm_oceanweight 	shore_transformation
biome
warm_oceanweight  	tagsmonsterocean	overworldwarmtemperature   ?  <?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

class CommandData{
	/** @var string */
	public $commandName;
	/** @var string */
	public $commandDescription;
	/** @var int */
	public $flags;
	/** @var int */
	public $permission;
	/** @var CommandEnum|null */
	public $aliases;
	/** @var CommandParameter[][] */
	public $overloads = [];

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

class CommandParameter{
	public const FLAG_FORCE_COLLAPSE_ENUM = 0x1;
	public const FLAG_HAS_ENUM_CONSTRAINT = 0x2;

	/** @var string */
	public $paramName;
	/** @var int */
	public $paramType;
	/** @var bool */
	public $isOptional;
	/** @var int */
	public $flags = 0; //shows enum name if 1, always zero except for in /gamerule command
	/** @var CommandEnum|null */
	public $enum;
	/** @var string|null */
	public $postfix;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

class CommandEnum{
	/** @var string */
	public $enumName;
	/** @var string[] */
	public $enumValues = [];

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

use pocketmine\utils\UUID;

class PlayerListEntry{

	/** @var UUID */
	public $uuid;
	/** @var int */
	public $entityUniqueId;
	/** @var string */
	public $username;
	/** @var SkinData */
	public $skinData;
	/** @var string */
	public $xboxUserId;
	/** @var string */
	public $platformChatId = "";
	/** @var int */
	public $buildPlatform = -1;
	/** @var bool */
	public $isTeacher = false;
	/** @var bool */
	public $isHost = false;

	public static function createRemovalEntry(UUID $uuid) : PlayerListEntry{
		$entry = new PlayerListEntry();
		$entry->uuid = $uuid;

		return $entry;
	}

	public static function createAdditionEntry(UUID $uuid, int $entityUniqueId, string $username, SkinData $skinData, string $xboxUserId = "", string $platformChatId = "", int $buildPlatform = -1, bool $isTeacher = false, bool $isHost = false) : PlayerListEntry{
		$entry = new PlayerListEntry();
		$entry->uuid = $uuid;
		$entry->entityUniqueId = $entityUniqueId;
		$entry->username = $username;
		$entry->skinData = $skinData;
		$entry->xboxUserId = $xboxUserId;
		$entry->platformChatId = $platformChatId;
		$entry->buildPlatform = $buildPlatform;
		$entry->isTeacher = $isTeacher;
		$entry->isHost = $isHost;

		return $entry;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\format\io;

use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
use pocketmine\scheduler\AsyncTask;
use pocketmine\Server;
use function assert;
use function strlen;

class ChunkRequestTask extends AsyncTask{

	/** @var int */
	protected $levelId;

	/** @var string */
	protected $chunk;
	/** @var int */
	protected $chunkX;
	/** @var int */
	protected $chunkZ;

	/** @var int */
	protected $compressionLevel;

	/** @var int */
	private $subChunkCount;

	public function __construct(Level $level, int $chunkX, int $chunkZ, Chunk $chunk){
		$this->levelId = $level->getId();
		$this->compressionLevel = $level->getServer()->networkCompressionLevel;

		$this->chunk = $chunk->networkSerialize();
		$this->chunkX = $chunkX;
		$this->chunkZ = $chunkZ;
		$this->subChunkCount = $chunk->getSubChunkSendCount();
	}

	public function onRun(){
		$pk = LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $this->subChunkCount, $this->chunk);

		$batch = new BatchPacket();
		$batch->addPacket($pk);
		$batch->setCompressionLevel($this->compressionLevel);
		$batch->encode();

		$this->setResult($batch->buffer);
	}

	public function onCompletion(Server $server){
		$level = $server->getLevel($this->levelId);
		if($level instanceof Level){
			if($this->hasResult()){
				$batch = new BatchPacket($this->getResult());
				assert(strlen($batch->buffer) > 0);
				$batch->isEncoded = true;
				$level->chunkRequestCallback($this->chunkX, $this->chunkZ, $batch);
			}else{
				$server->getLogger()->error("Chunk request for world #" . $this->levelId . ", x=" . $this->chunkX . ", z=" . $this->chunkZ . " doesn't have any result data");
			}
		}else{
			$server->getLogger()->debug("Dropped chunk task due to world not loaded");
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\lang\TextContainer;
use pocketmine\Player;

/**
 * Called when the player spawns in the world after logging in, when they first see the terrain.
 *
 * Note: A lot of data is sent to the player between login and this event. Disconnecting the player during this event
 * will cause this data to be wasted. Prefer disconnecting at login-time if possible to minimize bandwidth wastage.
 * @see PlayerLoginEvent
 */
class PlayerJoinEvent extends PlayerEvent{
	/** @var string|TextContainer */
	protected $joinMessage;

	/**
	 * PlayerJoinEvent constructor.
	 *
	 * @param TextContainer|string $joinMessage
	 */
	public function __construct(Player $player, $joinMessage){
		$this->player = $player;
		$this->joinMessage = $joinMessage;
	}

	/**
	 * @param string|TextContainer $joinMessage
	 */
	public function setJoinMessage($joinMessage) : void{
		$this->joinMessage = $joinMessage;
	}

	/**
	 * @return string|TextContainer
	 */
	public function getJoinMessage(){
		return $this->joinMessage;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\lang;

use function count;

class TranslationContainer extends TextContainer{

	/** @var string[] $params */
	protected $params = [];

	/**
	 * @param (float|int|string)[] $params
	 */
	public function __construct(string $text, array $params = []){
		parent::__construct($text);

		$this->setParameters($params);
	}

	/**
	 * @return string[]
	 */
	public function getParameters() : array{
		return $this->params;
	}

	/**
	 * @return string|null
	 */
	public function getParameter(int $i){
		return $this->params[$i] ?? null;
	}

	/**
	 * @return void
	 */
	public function setParameter(int $i, string $str){
		if($i < 0 or $i > count($this->params)){ //Intended, allow to set the last
			throw new \InvalidArgumentException("Invalid index $i, have " . count($this->params));
		}

		$this->params[$i] = $str;
	}

	/**
	 * @param (float|int|string)[] $params
	 *
	 * @return void
	 */
	public function setParameters(array $params){
		$i = 0;
		foreach($params as $str){
			$this->params[$i] = (string) $str;

			++$i;
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\lang;

class TextContainer{

	/** @var string $text */
	protected $text;

	public function __construct(string $text){
		$this->text = $text;
	}

	/**
	 * @return void
	 */
	public function setText(string $text){
		$this->text = $text;
	}

	public function getText() : string{
		return $this->text;
	}

	public function __toString() : string{
		return $this->getText();
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\event\Cancellable;
use pocketmine\level\Location;
use pocketmine\Player;

class PlayerMoveEvent extends PlayerEvent implements Cancellable{
	/** @var Location */
	private $from;
	/** @var Location */
	private $to;

	public function __construct(Player $player, Location $from, Location $to){
		$this->player = $player;
		$this->from = $from;
		$this->to = $to;
	}

	public function getFrom() : Location{
		return $this->from;
	}

	public function getTo() : Location{
		return $this->to;
	}

	public function setTo(Location $to) : void{
		$this->to = $to;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\entity\Human;
use pocketmine\event\Cancellable;
use pocketmine\event\entity\EntityEvent;

class PlayerExhaustEvent extends EntityEvent implements Cancellable{
	public const CAUSE_ATTACK = 1;
	public const CAUSE_DAMAGE = 2;
	public const CAUSE_MINING = 3;
	public const CAUSE_HEALTH_REGEN = 4;
	public const CAUSE_POTION = 5;
	public const CAUSE_WALKING = 6;
	public const CAUSE_SPRINTING = 7;
	public const CAUSE_SWIMMING = 8;
	public const CAUSE_JUMPING = 9;
	public const CAUSE_SPRINT_JUMPING = 10;
	public const CAUSE_CUSTOM = 11;

	/** @var float */
	private $amount;
	/** @var int */
	private $cause;

	/** @var Human */
	protected $player;

	public function __construct(Human $human, float $amount, int $cause){
		$this->entity = $human;
		$this->player = $human;
		$this->amount = $amount;
		$this->cause = $cause;
	}

	/**
	 * @return Human
	 */
	public function getPlayer(){
		return $this->player;
	}

	public function getAmount() : float{
		return $this->amount;
	}

	public function setAmount(float $amount) : void{
		$this->amount = $amount;
	}

	/**
	 * Returns an int cause of the exhaustion - one of the constants at the top of this class.
	 */
	public function getCause() : int{
		return $this->cause;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\event\Cancellable;
use pocketmine\Player;

/**
 * Called when a player does an animation
 */
class PlayerAnimationEvent extends PlayerEvent implements Cancellable{
	/** @var int */
	private $animationType;

	public function __construct(Player $player, int $animation){
		$this->player = $player;
		$this->animationType = $animation;
	}

	public function getAnimationType() : int{
		return $this->animationType;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\event\Cancellable;
use pocketmine\item\Item;
use pocketmine\level\Position;
use pocketmine\math\Vector3;
use pocketmine\Player;
use function assert;

/**
 * Called when a player interacts or touches a block (including air?)
 */
class PlayerInteractEvent extends PlayerEvent implements Cancellable{
	public const LEFT_CLICK_BLOCK = 0;
	public const RIGHT_CLICK_BLOCK = 1;
	public const LEFT_CLICK_AIR = 2;
	public const RIGHT_CLICK_AIR = 3;
	public const PHYSICAL = 4;

	/** @var Block */
	protected $blockTouched;

	/** @var Vector3 */
	protected $touchVector;

	/** @var int */
	protected $blockFace;

	/** @var Item */
	protected $item;

	/** @var int */
	protected $action;

	public function __construct(Player $player, Item $item, ?Block $block, ?Vector3 $touchVector, int $face, int $action = PlayerInteractEvent::RIGHT_CLICK_BLOCK){
		assert($block !== null or $touchVector !== null);
		$this->player = $player;
		$this->item = $item;
		$this->blockTouched = $block ?? BlockFactory::get(0, 0, new Position(0, 0, 0, $player->level));
		$this->touchVector = $touchVector ?? new Vector3(0, 0, 0);
		$this->blockFace = $face;
		$this->action = $action;
	}

	public function getAction() : int{
		return $this->action;
	}

	public function getItem() : Item{
		return $this->item;
	}

	public function getBlock() : Block{
		return $this->blockTouched;
	}

	public function getTouchVector() : Vector3{
		return $this->touchVector;
	}

	public function getFace() : int{
		return $this->blockFace;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\math;

use function abs;
use function ceil;
use function floor;
use function round;
use function sqrt;

class Vector2{
	/** @var float */
	public $x;
	/** @var float */
	public $y;

	public function __construct(float $x = 0, float $y = 0){
		$this->x = $x;
		$this->y = $y;
	}

	public function getX() : float{
		return $this->x;
	}

	public function getY() : float{
		return $this->y;
	}

	public function getFloorX() : int{
		return (int) floor($this->x);
	}

	public function getFloorY() : int{
		return (int) floor($this->y);
	}

	/**
	 * @param Vector2|float $x
	 * @param float         $y
	 *
	 * @return Vector2
	 */
	public function add($x, float $y = 0) : Vector2{
		if($x instanceof Vector2){
			return $this->add($x->x, $x->y);
		}else{
			return new Vector2($this->x + $x, $this->y + $y);
		}
	}

	/**
	 * @param Vector2|float $x
	 * @param float         $y
	 *
	 * @return Vector2
	 */
	public function subtract($x, float $y = 0) : Vector2{
		if($x instanceof Vector2){
			return $this->add(-$x->x, -$x->y);
		}else{
			return $this->add(-$x, -$y);
		}
	}

	public function ceil() : Vector2{
		return new Vector2((int) ceil($this->x), (int) ceil($this->y));
	}

	public function floor() : Vector2{
		return new Vector2((int) floor($this->x), (int) floor($this->y));
	}

	public function round() : Vector2{
		return new Vector2(round($this->x), round($this->y));
	}

	public function abs() : Vector2{
		return new Vector2(abs($this->x), abs($this->y));
	}

	public function multiply(float $number) : Vector2{
		return new Vector2($this->x * $number, $this->y * $number);
	}

	public function divide(float $number) : Vector2{
		return new Vector2($this->x / $number, $this->y / $number);
	}

	/**
	 * @param Vector2|float $x
	 * @param float         $y
	 *
	 * @return float
	 */
	public function distance($x, float $y = 0) : float{
		if($x instanceof Vector2){
			return sqrt($this->distanceSquared($x->x, $x->y));
		}else{
			return sqrt($this->distanceSquared($x, $y));
		}
	}

	/**
	 * @param Vector2|float $x
	 * @param float         $y
	 *
	 * @return float
	 */
	public function distanceSquared($x, float $y = 0) : float{
		if($x instanceof Vector2){
			return $this->distanceSquared($x->x, $x->y);
		}else{
			return (($this->x - $x) ** 2) + (($this->y - $y) ** 2);
		}
	}

	public function length() : float{
		return sqrt($this->lengthSquared());
	}

	public function lengthSquared() : float{
		return $this->x * $this->x + $this->y * $this->y;
	}

	public function normalize() : Vector2{
		$len = $this->lengthSquared();
		if($len > 0){
			return $this->divide(sqrt($len));
		}

		return new Vector2(0, 0);
	}

	public function dot(Vector2 $v) : float{
		return $this->x * $v->x + $this->y * $v->y;
	}

	public function __toString(){
		return "Vector2(x=" . $this->x . ",y=" . $this->y . ")";
	}

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\block;

/**
 * Types of tools that can be used to break blocks
 * Blocks may allow multiple tool types by combining these bitflags
 */
interface BlockToolType{

	public const TYPE_NONE = 0;
	public const TYPE_SWORD = 1 << 0;
	public const TYPE_SHOVEL = 1 << 1;
	public const TYPE_PICKAXE = 1 << 2;
	public const TYPE_AXE = 1 << 3;
	public const TYPE_SHEARS = 1 << 4;

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\block;

use pocketmine\block\Block;
use pocketmine\event\Cancellable;
use pocketmine\item\Item;
use pocketmine\Player;

/**
 * Called when a player destroys a block somewhere in the world.
 */
class BlockBreakEvent extends BlockEvent implements Cancellable{
	/** @var Player */
	protected $player;

	/** @var Item */
	protected $item;

	/** @var bool */
	protected $instaBreak = false;
	/** @var Item[] */
	protected $blockDrops = [];
	/** @var int */
	protected $xpDrops;

	/**
	 * @param Item[] $drops
	 */
	public function __construct(Player $player, Block $block, Item $item, bool $instaBreak = false, array $drops, int $xpDrops = 0){
		parent::__construct($block);
		$this->item = $item;
		$this->player = $player;

		$this->instaBreak = $instaBreak;
		$this->setDrops($drops);
		$this->xpDrops = $xpDrops;
	}

	/**
	 * Returns the player who is destroying the block.
	 */
	public function getPlayer() : Player{
		return $this->player;
	}

	/**
	 * Returns the item used to destroy the block.
	 */
	public function getItem() : Item{
		return $this->item;
	}

	/**
	 * Returns whether the block may be broken in less than the amount of time calculated. This is usually true for
	 * creative players.
	 */
	public function getInstaBreak() : bool{
		return $this->instaBreak;
	}

	public function setInstaBreak(bool $instaBreak) : void{
		$this->instaBreak = $instaBreak;
	}

	/**
	 * @return Item[]
	 */
	public function getDrops() : array{
		return $this->blockDrops;
	}

	/**
	 * @param Item[] $drops
	 */
	public function setDrops(array $drops) : void{
		$this->setDropsVariadic(...$drops);
	}

	/**
	 * Variadic hack for easy array member type enforcement.
	 *
	 * @param Item ...$drops
	 */
	public function setDropsVariadic(Item ...$drops) : void{
		$this->blockDrops = $drops;
	}

	/**
	 * Returns how much XP will be dropped by breaking this block.
	 */
	public function getXpDropAmount() : int{
		return $this->xpDrops;
	}

	/**
	 * Sets how much XP will be dropped by breaking this block.
	 */
	public function setXpDropAmount(int $amount) : void{
		if($amount < 0){
			throw new \InvalidArgumentException("Amount must be at least zero");
		}
		$this->xpDrops = $amount;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

/**
 * Block related events
 */
namespace pocketmine\event\block;

use pocketmine\block\Block;
use pocketmine\event\Event;

abstract class BlockEvent extends Event{
	/** @var Block */
	protected $block;

	public function __construct(Block $block){
		$this->block = $block;
	}

	public function getBlock() : Block{
		return $this->block;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\server;

use pocketmine\command\CommandSender;
use pocketmine\event\Cancellable;

/**
 * Called when the console runs a command, early in the process
 *
 * You don't want to use this except for a few cases like logging commands,
 * blocking commands on certain places, or applying modifiers.
 *
 * The message DOES NOT contain a slash at the start
 *
 * @deprecated Use CommandEvent instead.
 */
class ServerCommandEvent extends ServerEvent implements Cancellable{
	/** @var string */
	protected $command;

	/** @var CommandSender */
	protected $sender;

	public function __construct(CommandSender $sender, string $command){
		$this->sender = $sender;
		$this->command = $command;
	}

	public function getSender() : CommandSender{
		return $this->sender;
	}

	public function getCommand() : string{
		return $this->command;
	}

	public function setCommand(string $command) : void{
		$this->command = $command;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\server;

use pocketmine\command\CommandSender;
use pocketmine\event\Cancellable;

/**
 * Called when any CommandSender runs a command, early in the process
 *
 * You don't want to use this except for a few cases like logging commands,
 * blocking commands on certain places, or applying modifiers.
 *
 * The message DOES NOT contain a slash at the start
 */
class CommandEvent extends ServerEvent implements Cancellable{
	/** @var string */
	protected $command;

	/** @var CommandSender */
	protected $sender;

	public function __construct(CommandSender $sender, string $command){
		$this->sender = $sender;
		$this->command = $command;
	}

	public function getSender() : CommandSender{
		return $this->sender;
	}

	public function getCommand() : string{
		return $this->command;
	}

	public function setCommand(string $command) : void{
		$this->command = $command;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\event\Cancellable;
use pocketmine\Player;

class PlayerToggleSprintEvent extends PlayerEvent implements Cancellable{
	/** @var bool */
	protected $isSprinting;

	public function __construct(Player $player, bool $isSprinting){
		$this->player = $player;
		$this->isSprinting = $isSprinting;
	}

	public function isSprinting() : bool{
		return $this->isSprinting;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\network\mcpe\protocol\types;

use pocketmine\utils\UUID;

class CommandOriginData{
	public const ORIGIN_PLAYER = 0;
	public const ORIGIN_BLOCK = 1;
	public const ORIGIN_MINECART_BLOCK = 2;
	public const ORIGIN_DEV_CONSOLE = 3;
	public const ORIGIN_TEST = 4;
	public const ORIGIN_AUTOMATION_PLAYER = 5;
	public const ORIGIN_CLIENT_AUTOMATION = 6;
	public const ORIGIN_DEDICATED_SERVER = 7;
	public const ORIGIN_ENTITY = 8;
	public const ORIGIN_VIRTUAL = 9;
	public const ORIGIN_GAME_ARGUMENT = 10;
	public const ORIGIN_ENTITY_SERVER = 11; //???

	/** @var int */
	public $type;
	/** @var UUID */
	public $uuid;

	/** @var string */
	public $requestId;

	/** @var int */
	public $varlong1;
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\event\Cancellable;
use pocketmine\Player;

/**
 * Called when a player runs a command or chats, early in the process
 *
 * You don't want to use this except for a few cases like logging commands,
 * blocking commands on certain places, or applying modifiers.
 *
 * The message contains a slash at the start
 */
class PlayerCommandPreprocessEvent extends PlayerEvent implements Cancellable{
	/** @var string */
	protected $message;

	public function __construct(Player $player, string $message){
		$this->player = $player;
		$this->message = $message;
	}

	public function getMessage() : string{
		return $this->message;
	}

	public function setMessage(string $message) : void{
		$this->message = $message;
	}

	public function setPlayer(Player $player) : void{
		$this->player = $player;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\event\Cancellable;
use pocketmine\Player;

/**
 * Called when a player has its gamemode changed
 */
class PlayerGameModeChangeEvent extends PlayerEvent implements Cancellable{
	/** @var int */
	protected $gamemode;

	public function __construct(Player $player, int $newGamemode){
		$this->player = $player;
		$this->gamemode = $newGamemode;
	}

	public function getNewGamemode() : int{
		return $this->gamemode;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\particle;

use pocketmine\block\Block;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelEventPacket;

class DestroyBlockParticle extends Particle{

	/** @var int */
	protected $data;

	public function __construct(Vector3 $pos, Block $b){
		parent::__construct($pos->x, $pos->y, $pos->z);
		$this->data = $b->getRuntimeId();
	}

	public function encode(){
		$pk = new LevelEventPacket;
		$pk->evid = LevelEventPacket::EVENT_PARTICLE_DESTROY;
		$pk->position = $this->asVector3();
		$pk->data = $this->data;

		return $pk;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\particle;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\DataPacket;

abstract class Particle extends Vector3{

	public const TYPE_BUBBLE = 1;
	public const TYPE_BUBBLE_MANUAL = 2;
	public const TYPE_CRITICAL = 3;
	public const TYPE_BLOCK_FORCE_FIELD = 4;
	public const TYPE_SMOKE = 5;
	public const TYPE_EXPLODE = 6;
	public const TYPE_EVAPORATION = 7;
	public const TYPE_FLAME = 8;
	public const TYPE_LAVA = 9;
	public const TYPE_LARGE_SMOKE = 10;
	public const TYPE_REDSTONE = 11;
	public const TYPE_RISING_RED_DUST = 12;
	public const TYPE_ITEM_BREAK = 13;
	public const TYPE_SNOWBALL_POOF = 14;
	public const TYPE_HUGE_EXPLODE = 15;
	public const TYPE_HUGE_EXPLODE_SEED = 16;
	public const TYPE_MOB_FLAME = 17;
	public const TYPE_HEART = 18;
	public const TYPE_TERRAIN = 19;
	public const TYPE_SUSPENDED_TOWN = 20, TYPE_TOWN_AURA = 20;
	public const TYPE_PORTAL = 21;
	//22 same as 21
	public const TYPE_SPLASH = 23, TYPE_WATER_SPLASH = 23;
	public const TYPE_WATER_SPLASH_MANUAL = 24;
	public const TYPE_WATER_WAKE = 25;
	public const TYPE_DRIP_WATER = 26;
	public const TYPE_DRIP_LAVA = 27;
	public const TYPE_DRIP_HONEY = 28;
	public const TYPE_FALLING_DUST = 29, TYPE_DUST = 29;
	public const TYPE_MOB_SPELL = 30;
	public const TYPE_MOB_SPELL_AMBIENT = 31;
	public const TYPE_MOB_SPELL_INSTANTANEOUS = 32;
	public const TYPE_INK = 33;
	public const TYPE_SLIME = 34;
	public const TYPE_RAIN_SPLASH = 35;
	public const TYPE_VILLAGER_ANGRY = 36;
	public const TYPE_VILLAGER_HAPPY = 37;
	public const TYPE_ENCHANTMENT_TABLE = 38;
	public const TYPE_TRACKING_EMITTER = 39;
	public const TYPE_NOTE = 40;
	public const TYPE_WITCH_SPELL = 41;
	public const TYPE_CARROT = 42;
	public const TYPE_MOB_APPEARANCE = 43;
	public const TYPE_END_ROD = 44;
	public const TYPE_DRAGONS_BREATH = 45;
	public const TYPE_SPIT = 46;
	public const TYPE_TOTEM = 47;
	public const TYPE_FOOD = 48;
	public const TYPE_FIREWORKS_STARTER = 49;
	public const TYPE_FIREWORKS_SPARK = 50;
	public const TYPE_FIREWORKS_OVERLAY = 51;
	public const TYPE_BALLOON_GAS = 52;
	public const TYPE_COLORED_FLAME = 53;
	public const TYPE_SPARKLER = 54;
	public const TYPE_CONDUIT = 55;
	public const TYPE_BUBBLE_COLUMN_UP = 56;
	public const TYPE_BUBBLE_COLUMN_DOWN = 57;
	public const TYPE_SNEEZE = 58;
	public const TYPE_SHULKER_BULLET = 59;
	public const TYPE_BLEACH = 60;
	public const TYPE_DRAGON_DESTROY_BLOCK = 61;
	public const TYPE_MYCELIUM_DUST = 62;
	public const TYPE_FALLING_RED_DUST = 63;
	public const TYPE_CAMPFIRE_SMOKE = 64;
	public const TYPE_TALL_CAMPFIRE_SMOKE = 65;
	public const TYPE_DRAGON_BREATH_FIRE = 66;
	public const TYPE_DRAGON_BREATH_TRAIL = 67;

	/**
	 * @return DataPacket|DataPacket[]
	 */
	abstract public function encode();

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\light;

class SkyLightUpdate extends LightUpdate{

	public function getLight(int $x, int $y, int $z) : int{
		return $this->subChunkHandler->currentSubChunk->getBlockSkyLight($x & 0x0f, $y & 0x0f, $z & 0x0f);
	}

	public function setLight(int $x, int $y, int $z, int $level){
		$this->subChunkHandler->currentSubChunk->setBlockSkyLight($x & 0x0f, $y & 0x0f, $z & 0x0f, $level);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\light;

use pocketmine\block\BlockFactory;
use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\level\utils\SubChunkIteratorManager;

//TODO: make light updates asynchronous
abstract class LightUpdate{

	/** @var ChunkManager */
	protected $level;

	/** @var int[][] blockhash => [x, y, z, new light level] */
	protected $updateNodes = [];

	/** @var \SplQueue */
	protected $spreadQueue;
	/** @var bool[] */
	protected $spreadVisited = [];

	/** @var \SplQueue */
	protected $removalQueue;
	/** @var bool[] */
	protected $removalVisited = [];
	/** @var SubChunkIteratorManager */
	protected $subChunkHandler;

	public function __construct(ChunkManager $level){
		$this->level = $level;
		$this->removalQueue = new \SplQueue();
		$this->spreadQueue = new \SplQueue();

		$this->subChunkHandler = new SubChunkIteratorManager($this->level);
	}

	abstract protected function getLight(int $x, int $y, int $z) : int;

	/**
	 * @return void
	 */
	abstract protected function setLight(int $x, int $y, int $z, int $level);

	/**
	 * @return void
	 */
	public function setAndUpdateLight(int $x, int $y, int $z, int $newLevel){
		$this->updateNodes[((($x) & 0xFFFFFFF) << 36) | ((( $y) & 0xff) << 28) | (( $z) & 0xFFFFFFF)] = [$x, $y, $z, $newLevel];
	}

	private function prepareNodes() : void{
		foreach($this->updateNodes as $blockHash => [$x, $y, $z, $newLevel]){
			if($this->subChunkHandler->moveTo($x, $y, $z)){
				$oldLevel = $this->getLight($x, $y, $z);

				if($oldLevel !== $newLevel){
					$this->setLight($x, $y, $z, $newLevel);
					if($oldLevel < $newLevel){ //light increased
						$this->spreadVisited[$blockHash] = true;
						$this->spreadQueue->enqueue([$x, $y, $z]);
					}else{ //light removed
						$this->removalVisited[$blockHash] = true;
						$this->removalQueue->enqueue([$x, $y, $z, $oldLevel]);
					}
				}
			}
		}
	}

	/**
	 * @return void
	 */
	public function execute(){
		$this->prepareNodes();

		while(!$this->removalQueue->isEmpty()){
			list($x, $y, $z, $oldAdjacentLight) = $this->removalQueue->dequeue();

			$points = [
				[$x + 1, $y, $z],
				[$x - 1, $y, $z],
				[$x, $y + 1, $z],
				[$x, $y - 1, $z],
				[$x, $y, $z + 1],
				[$x, $y, $z - 1]
			];

			foreach($points as list($cx, $cy, $cz)){
				if($this->subChunkHandler->moveTo($cx, $cy, $cz)){
					$this->computeRemoveLight($cx, $cy, $cz, $oldAdjacentLight);
				}
			}
		}

		while(!$this->spreadQueue->isEmpty()){
			list($x, $y, $z) = $this->spreadQueue->dequeue();

			unset($this->spreadVisited[((($x) & 0xFFFFFFF) << 36) | ((( $y) & 0xff) << 28) | (( $z) & 0xFFFFFFF)]);

			if(!$this->subChunkHandler->moveTo($x, $y, $z)){
				continue;
			}

			$newAdjacentLight = $this->getLight($x, $y, $z);
			if($newAdjacentLight <= 0){
				continue;
			}

			$points = [
				[$x + 1, $y, $z],
				[$x - 1, $y, $z],
				[$x, $y + 1, $z],
				[$x, $y - 1, $z],
				[$x, $y, $z + 1],
				[$x, $y, $z - 1]
			];

			foreach($points as list($cx, $cy, $cz)){
				if($this->subChunkHandler->moveTo($cx, $cy, $cz)){
					$this->computeSpreadLight($cx, $cy, $cz, $newAdjacentLight);
				}
			}
		}
	}

	/**
	 * @return void
	 */
	protected function computeRemoveLight(int $x, int $y, int $z, int $oldAdjacentLevel){
		$current = $this->getLight($x, $y, $z);

		if($current !== 0 and $current < $oldAdjacentLevel){
			$this->setLight($x, $y, $z, 0);

			if(!isset($this->removalVisited[$index = ((($x) & 0xFFFFFFF) << 36) | ((( $y) & 0xff) << 28) | (( $z) & 0xFFFFFFF)])){
				$this->removalVisited[$index] = true;
				if($current > 1){
					$this->removalQueue->enqueue([$x, $y, $z, $current]);
				}
			}
		}elseif($current >= $oldAdjacentLevel){
			if(!isset($this->spreadVisited[$index = ((($x) & 0xFFFFFFF) << 36) | ((( $y) & 0xff) << 28) | (( $z) & 0xFFFFFFF)])){
				$this->spreadVisited[$index] = true;
				$this->spreadQueue->enqueue([$x, $y, $z]);
			}
		}
	}

	/**
	 * @return void
	 */
	protected function computeSpreadLight(int $x, int $y, int $z, int $newAdjacentLevel){
		$current = $this->getLight($x, $y, $z);
		$potentialLight = $newAdjacentLevel - BlockFactory::$lightFilter[$this->subChunkHandler->currentSubChunk->getBlockId($x & 0x0f, $y & 0x0f, $z & 0x0f)];

		if($current < $potentialLight){
			$this->setLight($x, $y, $z, $potentialLight);

			if(!isset($this->spreadVisited[$index = ((($x) & 0xFFFFFFF) << 36) | ((( $y) & 0xff) << 28) | (( $z) & 0xFFFFFFF)]) and $potentialLight > 1){
				$this->spreadVisited[$index] = true;
				$this->spreadQueue->enqueue([$x, $y, $z]);
			}
		}
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\utils;

use pocketmine\level\ChunkManager;
use pocketmine\level\format\Chunk;
use pocketmine\level\format\EmptySubChunk;
use pocketmine\level\format\SubChunkInterface;

class SubChunkIteratorManager{
	/** @var ChunkManager */
	public $level;

	/** @var Chunk|null */
	public $currentChunk;
	/** @var SubChunkInterface|null */
	public $currentSubChunk;

	/** @var int */
	protected $currentX;
	/** @var int */
	protected $currentY;
	/** @var int */
	protected $currentZ;
	/** @var bool */
	protected $allocateEmptySubs = true;

	public function __construct(ChunkManager $level, bool $allocateEmptySubs = true){
		$this->level = $level;
		$this->allocateEmptySubs = $allocateEmptySubs;
	}

	public function moveTo(int $x, int $y, int $z) : bool{
		if($this->currentChunk === null or $this->currentX !== ($x >> 4) or $this->currentZ !== ($z >> 4)){
			$this->currentX = $x >> 4;
			$this->currentZ = $z >> 4;
			$this->currentSubChunk = null;

			$this->currentChunk = $this->level->getChunk($this->currentX, $this->currentZ);
			if($this->currentChunk === null){
				return false;
			}
		}

		if($this->currentSubChunk === null or $this->currentY !== ($y >> 4)){
			$this->currentY = $y >> 4;

			$this->currentSubChunk = $this->currentChunk->getSubChunk($y >> 4, $this->allocateEmptySubs);
			if($this->currentSubChunk instanceof EmptySubChunk){
				return false;
			}
		}

		return true;
	}

	public function invalidate() : void{
		$this->currentChunk = null;
		$this->currentSubChunk = null;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\level\light;

class BlockLightUpdate extends LightUpdate{

	public function getLight(int $x, int $y, int $z) : int{
		return $this->subChunkHandler->currentSubChunk->getBlockLight($x & 0x0f, $y & 0x0f, $z & 0x0f);
	}

	public function setLight(int $x, int $y, int $z, int $level){
		$this->subChunkHandler->currentSubChunk->setBlockLight($x & 0x0f, $y & 0x0f, $z & 0x0f, $level);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\block;

use pocketmine\event\Cancellable;

/**
 * Called when a block tries to be updated due to a neighbor change
 */
class BlockUpdateEvent extends BlockEvent implements Cancellable{

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\Player;

/**
 * Called when a player jumps
 */
class PlayerJumpEvent extends PlayerEvent{

	/**
	 * PlayerJumpEvent constructor.
	 */
	public function __construct(Player $player){
		$this->player = $player;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\event\Cancellable;
use pocketmine\Player;

class PlayerToggleFlightEvent extends PlayerEvent implements Cancellable{
	/** @var bool */
	protected $isFlying;

	public function __construct(Player $player, bool $isFlying){
		$this->player = $player;
		$this->isFlying = $isFlying;
	}

	public function isFlying() : bool{
		return $this->isFlying;
	}
}
