<?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);

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

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either 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\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\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\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\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\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\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;

use pocketmine\level\format\Chunk;
use const INT32_MAX;
use const INT32_MIN;

class SimpleChunkManager implements ChunkManager{

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

	/** @var int */
	protected $seed;
	/** @var int */
	protected $worldHeight;

	/**
	 * SimpleChunkManager constructor.
	 */
	public function __construct(int $seed, int $worldHeight = Level::Y_MAX){
		$this->seed = $seed;
		$this->worldHeight = $worldHeight;
	}

	/**
	 * Gets the raw block id.
	 *
	 * @return int 0-255
	 */
	public function getBlockIdAt(int $x, int $y, int $z) : int{
		if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
			return $chunk->getBlockId($x & 0xf, $y, $z & 0xf);
		}
		return 0;
	}

	/**
	 * Sets the raw block id.
	 *
	 * @param int $id 0-255
	 *
	 * @return void
	 */
	public function setBlockIdAt(int $x, int $y, int $z, int $id){
		if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
			$chunk->setBlockId($x & 0xf, $y, $z & 0xf, $id);
		}
	}

	/**
	 * Gets the raw block metadata
	 *
	 * @return int 0-15
	 */
	public function getBlockDataAt(int $x, int $y, int $z) : int{
		if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
			return $chunk->getBlockData($x & 0xf, $y, $z & 0xf);
		}
		return 0;
	}

	/**
	 * Sets the raw block metadata.
	 *
	 * @param int $data 0-15
	 *
	 * @return void
	 */
	public function setBlockDataAt(int $x, int $y, int $z, int $data){
		if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
			$chunk->setBlockData($x & 0xf, $y, $z & 0xf, $data);
		}
	}

	public function getBlockLightAt(int $x, int $y, int $z) : int{
		if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
			return $chunk->getBlockLight($x & 0xf, $y, $z & 0xf);
		}

		return 0;
	}

	public function setBlockLightAt(int $x, int $y, int $z, int $level){
		if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
			$chunk->setBlockLight($x & 0xf, $y, $z & 0xf, $level);
		}
	}

	public function getBlockSkyLightAt(int $x, int $y, int $z) : int{
		if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
			return $chunk->getBlockSkyLight($x & 0xf, $y, $z & 0xf);
		}

		return 0;
	}

	public function setBlockSkyLightAt(int $x, int $y, int $z, int $level){
		if(($chunk = $this->getChunk($x >> 4, $z >> 4)) !== null){
			$chunk->setBlockSkyLight($x & 0xf, $y, $z & 0xf, $level);
		}
	}

	/**
	 * @return Chunk|null
	 */
	public function getChunk(int $chunkX, int $chunkZ){
		return $this->chunks[((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)] ?? null;
	}

	/**
	 * @return void
	 */
	public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null){
		if($chunk === null){
			unset($this->chunks[((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)]);
			return;
		}
		$this->chunks[((($chunkX) & 0xFFFFFFFF) << 32) | (( $chunkZ) & 0xFFFFFFFF)] = $chunk;
	}

	/**
	 * @return void
	 */
	public function cleanChunks(){
		$this->chunks = [];
	}

	/**
	 * Gets the level seed
	 */
	public function getSeed() : int{
		return $this->seed;
	}

	public function getWorldHeight() : int{
		return $this->worldHeight;
	}

	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
		);
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 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\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);

/**
 * 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\utils;

use function time;

/**
 * XorShift128Engine Random Number Noise, used for fast seeded values
 * Most of the code in this class was adapted from the XorShift128Engine in the php-random library.
 */
class Random{
	public const X = 123456789;
	public const Y = 362436069;
	public const Z = 521288629;
	public const W = 88675123;

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

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

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

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

	/** @var int */
	protected $seed;

	/**
	 * @param int $seed Integer to be used as seed.
	 */
	public function __construct(int $seed = -1){
		if($seed === -1){
			$seed = time();
		}

		$this->setSeed($seed);
	}

	/**
	 * @param int $seed Integer to be used as seed.
	 *
	 * @return void
	 */
	public function setSeed(int $seed){
		$this->seed = $seed;
		$this->x = self::X ^ $seed;
		$this->y = self::Y ^ ($seed << 17) | (($seed >> 15) & 0x7fffffff) & 0xffffffff;
		$this->z = self::Z ^ ($seed << 31) | (($seed >> 1) & 0x7fffffff) & 0xffffffff;
		$this->w = self::W ^ ($seed << 18) | (($seed >> 14) & 0x7fffffff) & 0xffffffff;
	}

	public function getSeed() : int{
		return $this->seed;
	}

	/**
	 * Returns an 31-bit integer (not signed)
	 */
	public function nextInt() : int{
		return $this->nextSignedInt() & 0x7fffffff;
	}

	/**
	 * Returns a 32-bit integer (signed)
	 */
	public function nextSignedInt() : int{
		$t = ($this->x ^ ($this->x << 11)) & 0xffffffff;

		$this->x = $this->y;
		$this->y = $this->z;
		$this->z = $this->w;
		$this->w = ($this->w ^ (($this->w >> 19) & 0x7fffffff)
		                     ^ ($t ^ (($t >> 8) & 0x7fffffff))) & 0xffffffff;

		return $this->w;
	}

	/**
	 * Returns a float between 0.0 and 1.0 (inclusive)
	 */
	public function nextFloat() : float{
		return $this->nextInt() / 0x7fffffff;
	}

	/**
	 * Returns a float between -1.0 and 1.0 (inclusive)
	 */
	public function nextSignedFloat() : float{
		return $this->nextSignedInt() / 0x7fffffff;
	}

	/**
	 * Returns a random boolean
	 */
	public function nextBoolean() : bool{
		return ($this->nextSignedInt() & 0x01) === 0;
	}

	/**
	 * Returns a random integer between $start and $end
	 *
	 * @param int $start default 0
	 * @param int $end default 0x7fffffff
	 */
	public function nextRange(int $start = 0, int $end = 0x7fffffff) : int{
		return $start + ($this->nextInt() % ($end + 1 - $start));
	}

	public function nextBoundedInt(int $bound) : int{
		return $this->nextInt() % $bound;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 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\noise;

use pocketmine\utils\Random;
use function sqrt;

/**
 * Generates simplex-based noise.
 *
 * This is a modified version of the freely published version in the paper by
 * Stefan Gustavson at
 * http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
 */
class Simplex extends Perlin{
	/** @var float */
	protected static $SQRT_3;
	/** @var float */
	protected static $SQRT_5;
	/** @var float */
	protected static $F2;
	/** @var float */
	protected static $G2;
	/** @var float */
	protected static $G22;
	/** @var float */
	protected static $F3;
	/** @var float */
	protected static $G3;
	/** @var float */
	protected static $F4;
	/** @var float */
	protected static $G4;
	/** @var float */
	protected static $G42;
	/** @var float */
	protected static $G43;
	/** @var float */
	protected static $G44;
	/** @var int[][] */
	protected static $grad4 = [[0, 1, 1, 1], [0, 1, 1, -1], [0, 1, -1, 1], [0, 1, -1, -1],
		[0, -1, 1, 1], [0, -1, 1, -1], [0, -1, -1, 1], [0, -1, -1, -1],
		[1, 0, 1, 1], [1, 0, 1, -1], [1, 0, -1, 1], [1, 0, -1, -1],
		[-1, 0, 1, 1], [-1, 0, 1, -1], [-1, 0, -1, 1], [-1, 0, -1, -1],
		[1, 1, 0, 1], [1, 1, 0, -1], [1, -1, 0, 1], [1, -1, 0, -1],
		[-1, 1, 0, 1], [-1, 1, 0, -1], [-1, -1, 0, 1], [-1, -1, 0, -1],
		[1, 1, 1, 0], [1, 1, -1, 0], [1, -1, 1, 0], [1, -1, -1, 0],
		[-1, 1, 1, 0], [-1, 1, -1, 0], [-1, -1, 1, 0], [-1, -1, -1, 0]];

	/** @var int[][] */
	protected static $simplex = [
		[0, 1, 2, 3], [0, 1, 3, 2], [0, 0, 0, 0], [0, 2, 3, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 2, 3, 0],
		[0, 2, 1, 3], [0, 0, 0, 0], [0, 3, 1, 2], [0, 3, 2, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 3, 2, 0],
		[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0],
		[1, 2, 0, 3], [0, 0, 0, 0], [1, 3, 0, 2], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 3, 0, 1], [2, 3, 1, 0],
		[1, 0, 2, 3], [1, 0, 3, 2], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 0, 3, 1], [0, 0, 0, 0], [2, 1, 3, 0],
		[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0],
		[2, 0, 1, 3], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [3, 0, 1, 2], [3, 0, 2, 1], [0, 0, 0, 0], [3, 1, 2, 0],
		[2, 1, 0, 3], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [3, 1, 0, 2], [0, 0, 0, 0], [3, 2, 0, 1], [3, 2, 1, 0]];

	/** @var float */
	protected $offsetW;

	/**
	 * @param int    $octaves
	 * @param float  $persistence
	 * @param float  $expansion
	 */
	public function __construct(Random $random, $octaves, $persistence, $expansion = 1){
		parent::__construct($random, $octaves, $persistence, $expansion);
		$this->offsetW = $random->nextFloat() * 256;
		self::$SQRT_3 = sqrt(3);
		self::$SQRT_5 = sqrt(5);
		self::$F2 = 0.5 * (self::$SQRT_3 - 1);
		self::$G2 = (3 - self::$SQRT_3) / 6;
		self::$G22 = self::$G2 * 2.0 - 1;
		self::$F3 = 1.0 / 3.0;
		self::$G3 = 1.0 / 6.0;
		self::$F4 = (self::$SQRT_5 - 1.0) / 4.0;
		self::$G4 = (5.0 - self::$SQRT_5) / 20.0;
		self::$G42 = self::$G4 * 2.0;
		self::$G43 = self::$G4 * 3.0;
		self::$G44 = self::$G4 * 4.0 - 1.0;
	}

	/**
	 * @param int[] $g
	 * @param float $x
	 * @param float $y
	 *
	 * @return float
	 */
	protected static function dot2D($g, $x, $y){
		return $g[0] * $x + $g[1] * $y;
	}

	/**
	 * @param int[] $g
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return float
	 */
	protected static function dot3D($g, $x, $y, $z){
		return $g[0] * $x + $g[1] * $y + $g[2] * $z;
	}

	/**
	 * @param int[] $g
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 * @param float $w
	 *
	 * @return float
	 */
	protected static function dot4D($g, $x, $y, $z, $w){
		return $g[0] * $x + $g[1] * $y + $g[2] * $z + $g[3] * $w;
	}

	public function getNoise3D($x, $y, $z){
		$x += $this->offsetX;
		$y += $this->offsetY;
		$z += $this->offsetZ;

		// Skew the input space to determine which simplex cell we're in
		$s = ($x + $y + $z) * self::$F3; // Very nice and simple skew factor for 3D
		$i = (int) ($x + $s);
		$j = (int) ($y + $s);
		$k = (int) ($z + $s);
		$t = ($i + $j + $k) * self::$G3;
		// Unskew the cell origin back to (x,y,z) space
		$x0 = $x - ($i - $t); // The x,y,z distances from the cell origin
		$y0 = $y - ($j - $t);
		$z0 = $z - ($k - $t);

		// For the 3D case, the simplex shape is a slightly irregular tetrahedron.

		// Determine which simplex we are in.
		if($x0 >= $y0){
			if($y0 >= $z0){
				$i1 = 1;
				$j1 = 0;
				$k1 = 0;
				$i2 = 1;
				$j2 = 1;
				$k2 = 0;
			} // X Y Z order
			elseif($x0 >= $z0){
				$i1 = 1;
				$j1 = 0;
				$k1 = 0;
				$i2 = 1;
				$j2 = 0;
				$k2 = 1;
			} // X Z Y order
			else{
				$i1 = 0;
				$j1 = 0;
				$k1 = 1;
				$i2 = 1;
				$j2 = 0;
				$k2 = 1;
			}
			// Z X Y order
		}else{ // x0<y0
			if($y0 < $z0){
				$i1 = 0;
				$j1 = 0;
				$k1 = 1;
				$i2 = 0;
				$j2 = 1;
				$k2 = 1;
			} // Z Y X order
			elseif($x0 < $z0){
				$i1 = 0;
				$j1 = 1;
				$k1 = 0;
				$i2 = 0;
				$j2 = 1;
				$k2 = 1;
			} // Y Z X order
			else{
				$i1 = 0;
				$j1 = 1;
				$k1 = 0;
				$i2 = 1;
				$j2 = 1;
				$k2 = 0;
			}
			// Y X Z order
		}

		// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
		// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
		// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
		// c = 1/6.
		$x1 = $x0 - $i1 + self::$G3; // Offsets for second corner in (x,y,z) coords
		$y1 = $y0 - $j1 + self::$G3;
		$z1 = $z0 - $k1 + self::$G3;
		$x2 = $x0 - $i2 + 2.0 * self::$G3; // Offsets for third corner in (x,y,z) coords
		$y2 = $y0 - $j2 + 2.0 * self::$G3;
		$z2 = $z0 - $k2 + 2.0 * self::$G3;
		$x3 = $x0 - 1.0 + 3.0 * self::$G3; // Offsets for last corner in (x,y,z) coords
		$y3 = $y0 - 1.0 + 3.0 * self::$G3;
		$z3 = $z0 - 1.0 + 3.0 * self::$G3;

		// Work out the hashed gradient indices of the four simplex corners
		$ii = $i & 255;
		$jj = $j & 255;
		$kk = $k & 255;

		$n = 0;

		// Calculate the contribution from the four corners
		$t0 = 0.6 - $x0 * $x0 - $y0 * $y0 - $z0 * $z0;
		if($t0 > 0){
			$gi0 = self::$grad3[$this->perm[$ii + $this->perm[$jj + $this->perm[$kk]]] % 12];
			$n += $t0 * $t0 * $t0 * $t0 * ($gi0[0] * $x0 + $gi0[1] * $y0 + $gi0[2] * $z0);
		}

		$t1 = 0.6 - $x1 * $x1 - $y1 * $y1 - $z1 * $z1;
		if($t1 > 0){
			$gi1 = self::$grad3[$this->perm[$ii + $i1 + $this->perm[$jj + $j1 + $this->perm[$kk + $k1]]] % 12];
			$n += $t1 * $t1 * $t1 * $t1 * ($gi1[0] * $x1 + $gi1[1] * $y1 + $gi1[2] * $z1);
		}

		$t2 = 0.6 - $x2 * $x2 - $y2 * $y2 - $z2 * $z2;
		if($t2 > 0){
			$gi2 = self::$grad3[$this->perm[$ii + $i2 + $this->perm[$jj + $j2 + $this->perm[$kk + $k2]]] % 12];
			$n += $t2 * $t2 * $t2 * $t2 * ($gi2[0] * $x2 + $gi2[1] * $y2 + $gi2[2] * $z2);
		}

		$t3 = 0.6 - $x3 * $x3 - $y3 * $y3 - $z3 * $z3;
		if($t3 > 0){
			$gi3 = self::$grad3[$this->perm[$ii + 1 + $this->perm[$jj + 1 + $this->perm[$kk + 1]]] % 12];
			$n += $t3 * $t3 * $t3 * $t3 * ($gi3[0] * $x3 + $gi3[1] * $y3 + $gi3[2] * $z3);
		}

		// Add contributions from each corner to get the noise value.
		// The result is scaled to stay just inside [-1,1]
		return 32.0 * $n;
	}

	/**
	 * @param float $x
	 * @param float $y
	 *
	 * @return float
	 */
	public function getNoise2D($x, $y){
		$x += $this->offsetX;
		$y += $this->offsetY;

		// Skew the input space to determine which simplex cell we're in
		$s = ($x + $y) * self::$F2; // Hairy factor for 2D
		$i = (int) ($x + $s);
		$j = (int) ($y + $s);
		$t = ($i + $j) * self::$G2;
		// Unskew the cell origin back to (x,y) space
		$x0 = $x - ($i - $t); // The x,y distances from the cell origin
		$y0 = $y - ($j - $t);

		// For the 2D case, the simplex shape is an equilateral triangle.

		// Determine which simplex we are in.
		if($x0 > $y0){
			$i1 = 1;
			$j1 = 0;
		} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
		else{
			$i1 = 0;
			$j1 = 1;
		}
		// upper triangle, YX order: (0,0)->(0,1)->(1,1)

		// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
		// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
		// c = (3-sqrt(3))/6

		$x1 = $x0 - $i1 + self::$G2; // Offsets for middle corner in (x,y) unskewed coords
		$y1 = $y0 - $j1 + self::$G2;
		$x2 = $x0 + self::$G22; // Offsets for last corner in (x,y) unskewed coords
		$y2 = $y0 + self::$G22;

		// Work out the hashed gradient indices of the three simplex corners
		$ii = $i & 255;
		$jj = $j & 255;

		$n = 0;

		// Calculate the contribution from the three corners
		$t0 = 0.5 - $x0 * $x0 - $y0 * $y0;
		if($t0 > 0){
			$gi0 = self::$grad3[$this->perm[$ii + $this->perm[$jj]] % 12];
			$n += $t0 * $t0 * $t0 * $t0 * ($gi0[0] * $x0 + $gi0[1] * $y0); // (x,y) of grad3 used for 2D gradient
		}

		$t1 = 0.5 - $x1 * $x1 - $y1 * $y1;
		if($t1 > 0){
			$gi1 = self::$grad3[$this->perm[$ii + $i1 + $this->perm[$jj + $j1]] % 12];
			$n += $t1 * $t1 * $t1 * $t1 * ($gi1[0] * $x1 + $gi1[1] * $y1);
		}

		$t2 = 0.5 - $x2 * $x2 - $y2 * $y2;
		if($t2 > 0){
			$gi2 = self::$grad3[$this->perm[$ii + 1 + $this->perm[$jj + 1]] % 12];
			$n += $t2 * $t2 * $t2 * $t2 * ($gi2[0] * $x2 + $gi2[1] * $y2);
		}

		// Add contributions from each corner to get the noise value.
		// The result is scaled to return values in the interval [-1,1].
		return 70.0 * $n;
	}

	/**
	 * Computes and returns the 4D simplex noise for the given coordinates in
	 * 4D space
	 *
	 * @param float $x X coordinate
	 * @param float $y Y coordinate
	 * @param float $z Z coordinate
	 * @param float $w W coordinate
	 *
	 * @return float Noise at given location, from range -1 to 1
	 */
	/*public function getNoise4D($x, $y, $z, $w){
		x += offsetX;
		y += offsetY;
		z += offsetZ;
		w += offsetW;

		n0, n1, n2, n3, n4; // Noise contributions from the five corners

		// Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
		s = (x + y + z + w) * self::$F4; // Factor for 4D skewing
		i = floor(x + s);
		j = floor(y + s);
		k = floor(z + s);
		l = floor(w + s);

		t = (i + j + k + l) * self::$G4; // Factor for 4D unskewing
		X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
		Y0 = j - t;
		Z0 = k - t;
		W0 = l - t;
		x0 = x - X0; // The x,y,z,w distances from the cell origin
		y0 = y - Y0;
		z0 = z - Z0;
		w0 = w - W0;

		// For the 4D case, the simplex is a 4D shape I won't even try to describe.
		// To find out which of the 24 possible simplices we're in, we need to
		// determine the magnitude ordering of x0, y0, z0 and w0.
		// The method below is a good way of finding the ordering of x,y,z,w and
		// then find the correct traversal order for the simplex we’re in.
		// First, six pair-wise comparisons are performed between each possible pair
		// of the four coordinates, and the results are used to add up binary bits
		// for an integer index.
		c1 = (x0 > y0) ? 32 : 0;
		c2 = (x0 > z0) ? 16 : 0;
		c3 = (y0 > z0) ? 8 : 0;
		c4 = (x0 > w0) ? 4 : 0;
		c5 = (y0 > w0) ? 2 : 0;
		c6 = (z0 > w0) ? 1 : 0;
		c = c1 + c2 + c3 + c4 + c5 + c6;
		i1, j1, k1, l1; // The integer offsets for the second simplex corner
		i2, j2, k2, l2; // The integer offsets for the third simplex corner
		i3, j3, k3, l3; // The integer offsets for the fourth simplex corner

		// simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
		// Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w
		// impossible. Only the 24 indices which have non-zero entries make any sense.
		// We use a thresholding to set the coordinates in turn from the largest magnitude.

		// The number 3 in the "simplex" array is at the position of the largest coordinate.
		i1 = simplex[c][0] >= 3 ? 1 : 0;
		j1 = simplex[c][1] >= 3 ? 1 : 0;
		k1 = simplex[c][2] >= 3 ? 1 : 0;
		l1 = simplex[c][3] >= 3 ? 1 : 0;

		// The number 2 in the "simplex" array is at the second largest coordinate.
		i2 = simplex[c][0] >= 2 ? 1 : 0;
		j2 = simplex[c][1] >= 2 ? 1 : 0;
		k2 = simplex[c][2] >= 2 ? 1 : 0;
		l2 = simplex[c][3] >= 2 ? 1 : 0;

		// The number 1 in the "simplex" array is at the second smallest coordinate.
		i3 = simplex[c][0] >= 1 ? 1 : 0;
		j3 = simplex[c][1] >= 1 ? 1 : 0;
		k3 = simplex[c][2] >= 1 ? 1 : 0;
		l3 = simplex[c][3] >= 1 ? 1 : 0;

		// The fifth corner has all coordinate offsets = 1, so no need to look that up.

		x1 = x0 - i1 + self::$G4; // Offsets for second corner in (x,y,z,w) coords
		y1 = y0 - j1 + self::$G4;
		z1 = z0 - k1 + self::$G4;
		w1 = w0 - l1 + self::$G4;

		x2 = x0 - i2 + self::$G42; // Offsets for third corner in (x,y,z,w) coords
		y2 = y0 - j2 + self::$G42;
		z2 = z0 - k2 + self::$G42;
		w2 = w0 - l2 + self::$G42;

		x3 = x0 - i3 + self::$G43; // Offsets for fourth corner in (x,y,z,w) coords
		y3 = y0 - j3 + self::$G43;
		z3 = z0 - k3 + self::$G43;
		w3 = w0 - l3 + self::$G43;

		x4 = x0 + self::$G44; // Offsets for last corner in (x,y,z,w) coords
		y4 = y0 + self::$G44;
		z4 = z0 + self::$G44;
		w4 = w0 + self::$G44;

		// Work out the hashed gradient indices of the five simplex corners
		ii = i & 255;
		jj = j & 255;
		kk = k & 255;
		ll = l & 255;

		gi0 = $this->perm[ii + $this->perm[jj + $this->perm[kk + $this->perm[ll]]]] % 32;
		gi1 = $this->perm[ii + i1 + $this->perm[jj + j1 + $this->perm[kk + k1 + $this->perm[ll + l1]]]] % 32;
		gi2 = $this->perm[ii + i2 + $this->perm[jj + j2 + $this->perm[kk + k2 + $this->perm[ll + l2]]]] % 32;
		gi3 = $this->perm[ii + i3 + $this->perm[jj + j3 + $this->perm[kk + k3 + $this->perm[ll + l3]]]] % 32;
		gi4 = $this->perm[ii + 1 + $this->perm[jj + 1 + $this->perm[kk + 1 + $this->perm[ll + 1]]]] % 32;

		// Calculate the contribution from the five corners
		t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0;
		if(t0 < 0){
			n0 = 0.0;
		}else{
			t0 *= t0;
			n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0);
		}

		t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1;
		if(t1 < 0){
			n1 = 0.0;
		}else{
			t1 *= t1;
			n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1);
		}

		t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2;
		if(t2 < 0){
			n2 = 0.0;
		}else{
			t2 *= t2;
			n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2);
		}

		t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3;
		if(t3 < 0){
			n3 = 0.0;
		}else{
			t3 *= t3;
			n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3);
		}

		t4 = 0.6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4;
		if(t4 < 0){
			n4 = 0.0;
		}else{
			t4 *= t4;
			n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4);
		}

		// Sum up and scale the result to cover the range [-1,1]
		return 27.0 * (n0 + n1 + n2 + n3 + n4);
	}*/
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 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\noise;

use pocketmine\utils\Random;

class Perlin extends Noise{
	/** @var int[][] */
	public static $grad3 = [
		[1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0],
		[1, 0, 1], [-1, 0, 1], [1, 0, -1], [-1, 0, -1],
		[0, 1, 1], [0, -1, 1], [0, 1, -1], [0, -1, -1]
	];

	/**
	 * @param int    $octaves
	 * @param float  $persistence
	 * @param float  $expansion
	 */
	public function __construct(Random $random, $octaves, $persistence, $expansion = 1){
		$this->octaves = $octaves;
		$this->persistence = $persistence;
		$this->expansion = $expansion;
		$this->offsetX = $random->nextFloat() * 256;
		$this->offsetY = $random->nextFloat() * 256;
		$this->offsetZ = $random->nextFloat() * 256;

		for($i = 0; $i < 512; ++$i){
			$this->perm[$i] = 0;
		}

		for($i = 0; $i < 256; ++$i){
			$this->perm[$i] = $random->nextBoundedInt(256);
		}

		for($i = 0; $i < 256; ++$i){
			$pos = $random->nextBoundedInt(256 - $i) + $i;
			$old = $this->perm[$i];

			$this->perm[$i] = $this->perm[$pos];
			$this->perm[$pos] = $old;
			$this->perm[$i + 256] = $this->perm[$i];
		}

	}

	public function getNoise3D($x, $y, $z){
		$x += $this->offsetX;
		$y += $this->offsetY;
		$z += $this->offsetZ;

		$floorX = (int) $x;
		$floorY = (int) $y;
		$floorZ = (int) $z;

		$X = $floorX & 0xFF;
		$Y = $floorY & 0xFF;
		$Z = $floorZ & 0xFF;

		$x -= $floorX;
		$y -= $floorY;
		$z -= $floorZ;

		//Fade curves
		//$fX = self::fade($x);
		//$fY = self::fade($y);
		//$fZ = self::fade($z);
		$fX = $x * $x * $x * ($x * ($x * 6 - 15) + 10);
		$fY = $y * $y * $y * ($y * ($y * 6 - 15) + 10);
		$fZ = $z * $z * $z * ($z * ($z * 6 - 15) + 10);

		//Cube corners
		$A = $this->perm[$X] + $Y;
		$B = $this->perm[$X + 1] + $Y;

		$AA = $this->perm[$A] + $Z;
		$AB = $this->perm[$A + 1] + $Z;
		$BA = $this->perm[$B] + $Z;
		$BB = $this->perm[$B + 1] + $Z;

		$AA1 = self::grad($this->perm[$AA], $x, $y, $z);
		$BA1 = self::grad($this->perm[$BA], $x - 1, $y, $z);
		$AB1 = self::grad($this->perm[$AB], $x, $y - 1, $z);
		$BB1 = self::grad($this->perm[$BB], $x - 1, $y - 1, $z);
		$AA2 = self::grad($this->perm[$AA + 1], $x, $y, $z - 1);
		$BA2 = self::grad($this->perm[$BA + 1], $x - 1, $y, $z - 1);
		$AB2 = self::grad($this->perm[$AB + 1], $x, $y - 1, $z - 1);
		$BB2 = self::grad($this->perm[$BB + 1], $x - 1, $y - 1, $z - 1);

		$xLerp11 = $AA1 + $fX * ($BA1 - $AA1);

		$zLerp1 = $xLerp11 + $fY * ($AB1 + $fX * ($BB1 - $AB1) - $xLerp11);

		$xLerp21 = $AA2 + $fX * ($BA2 - $AA2);

		return $zLerp1 + $fZ * ($xLerp21 + $fY * ($AB2 + $fX * ($BB2 - $AB2) - $xLerp21) - $zLerp1);

		/*
		return self::lerp(
			$fZ,
			self::lerp(
				$fY,
				self::lerp(
					$fX,
					self::grad($this->perm[$AA], $x, $y, $z),
					self::grad($this->perm[$BA], $x - 1, $y, $z)
				),
				self::lerp(
					$fX,
					self::grad($this->perm[$AB], $x, $y - 1, $z),
					self::grad($this->perm[$BB], $x - 1, $y - 1, $z)
				)
			),
			self::lerp(
				$fY,
				self::lerp(
					$fX,
					self::grad($this->perm[$AA + 1], $x, $y, $z - 1),
					self::grad($this->perm[$BA + 1], $x - 1, $y, $z - 1)
				),
				self::lerp(
					$fX,
					self::grad($this->perm[$AB + 1], $x, $y - 1, $z - 1),
					self::grad($this->perm[$BB + 1], $x - 1, $y - 1, $z - 1)
				)
			)
		);
		*/
	}

	/**
	 * @param float $x
	 * @param float $y
	 *
	 * @return float
	 */
	public function getNoise2D($x, $y){
		return $this->getNoise3D($x, $y, 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);

/**
 * Different noise generators for level generation
 */
namespace pocketmine\level\generator\noise;

use function array_fill;
use function assert;

abstract class Noise{
	/** @var int[] */
	protected $perm = [];
	/** @var float */
	protected $offsetX = 0;
	/** @var float */
	protected $offsetY = 0;
	/** @var float */
	protected $offsetZ = 0;
	/** @var int */
	protected $octaves = 8;
	/** @var float */
	protected $persistence;
	/** @var float */
	protected $expansion;

	/**
	 * @param float $x
	 */
	public static function floor($x) : int{
		return $x >= 0 ? (int) $x : (int) ($x - 1);
	}

	/**
	 * @param float $x
	 *
	 * @return float
	 */
	public static function fade($x){
		return $x * $x * $x * ($x * ($x * 6 - 15) + 10);
	}

	/**
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return float
	 */
	public static function lerp($x, $y, $z){
		return $y + $x * ($z - $y);
	}

	/**
	 * @param float $x
	 * @param float $x1
	 * @param float $x2
	 * @param float $q0
	 * @param float $q1
	 *
	 * @return float
	 */
	public static function linearLerp($x, $x1, $x2, $q0, $q1){
		return (($x2 - $x) / ($x2 - $x1)) * $q0 + (($x - $x1) / ($x2 - $x1)) * $q1;
	}

	/**
	 * @param float $x
	 * @param float $y
	 * @param float $q00
	 * @param float $q01
	 * @param float $q10
	 * @param float $q11
	 * @param float $x1
	 * @param float $x2
	 * @param float $y1
	 * @param float $y2
	 *
	 * @return float
	 */
	public static function bilinearLerp($x, $y, $q00, $q01, $q10, $q11, $x1, $x2, $y1, $y2){
		$dx1 = (($x2 - $x) / ($x2 - $x1));
		$dx2 = (($x - $x1) / ($x2 - $x1));

		return (($y2 - $y) / ($y2 - $y1)) * (
			$dx1 * $q00 + $dx2 * $q10
		) + (($y - $y1) / ($y2 - $y1)) * (
			$dx1 * $q01 + $dx2 * $q11
		);
	}

	/**
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 * @param float $q000
	 * @param float $q001
	 * @param float $q010
	 * @param float $q011
	 * @param float $q100
	 * @param float $q101
	 * @param float $q110
	 * @param float $q111
	 * @param float $x1
	 * @param float $x2
	 * @param float $y1
	 * @param float $y2
	 * @param float $z1
	 * @param float $z2
	 *
	 * @return float
	 */
	public static function trilinearLerp($x, $y, $z, $q000, $q001, $q010, $q011, $q100, $q101, $q110, $q111, $x1, $x2, $y1, $y2, $z1, $z2){
		$dx1 = (($x2 - $x) / ($x2 - $x1));
		$dx2 = (($x - $x1) / ($x2 - $x1));
		$dy1 = (($y2 - $y) / ($y2 - $y1));
		$dy2 = (($y - $y1) / ($y2 - $y1));

		return (($z2 - $z) / ($z2 - $z1)) * (
			$dy1 * (
				$dx1 * $q000 + $dx2 * $q100
			) + $dy2 * (
				$dx1 * $q001 + $dx2 * $q101
			)
		) + (($z - $z1) / ($z2 - $z1)) * (
			$dy1 * (
				$dx1 * $q010 + $dx2 * $q110
			) + $dy2 * (
				$dx1 * $q011 + $dx2 * $q111
			)
		);
	}

	/**
	 * @param int   $hash
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return float
	 */
	public static function grad($hash, $x, $y, $z){
		$hash &= 15;
		$u = $hash < 8 ? $x : $y;
		$v = $hash < 4 ? $y : (($hash === 12 or $hash === 14) ? $x : $z);

		return (($hash & 1) === 0 ? $u : -$u) + (($hash & 2) === 0 ? $v : -$v);
	}

	/**
	 * @param float $x
	 * @param float $z
	 *
	 * @return float
	 */
	abstract public function getNoise2D($x, $z);

	/**
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return float
	 */
	abstract public function getNoise3D($x, $y, $z);

	/**
	 * @param float $x
	 * @param float $z
	 * @param bool  $normalized
	 *
	 * @return float
	 */
	public function noise2D($x, $z, $normalized = false){
		$result = 0;
		$amp = 1;
		$freq = 1;
		$max = 0;

		$x *= $this->expansion;
		$z *= $this->expansion;

		for($i = 0; $i < $this->octaves; ++$i){
			$result += $this->getNoise2D($x * $freq, $z * $freq) * $amp;
			$max += $amp;
			$freq *= 2;
			$amp *= $this->persistence;
		}

		if($normalized === true){
			$result /= $max;
		}

		return $result;
	}

	/**
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 * @param bool  $normalized
	 *
	 * @return float
	 */
	public function noise3D($x, $y, $z, $normalized = false){
		$result = 0;
		$amp = 1;
		$freq = 1;
		$max = 0;

		$x *= $this->expansion;
		$y *= $this->expansion;
		$z *= $this->expansion;

		for($i = 0; $i < $this->octaves; ++$i){
			$result += $this->getNoise3D($x * $freq, $y * $freq, $z * $freq) * $amp;
			$max += $amp;
			$freq *= 2;
			$amp *= $this->persistence;
		}

		if($normalized === true){
			$result /= $max;
		}

		return $result;
	}

	/**
	 * @return \SplFixedArray|float[]
	 * @phpstan-return \SplFixedArray<float>
	 */
	public function getFastNoise1D(int $xSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
		if($samplingRate === 0){
			throw new \InvalidArgumentException("samplingRate cannot be 0");
		}
		if($xSize % $samplingRate !== 0){
			throw new \InvalidArgumentException("xSize % samplingRate must return 0");
		}

		$noiseArray = new \SplFixedArray($xSize + 1);

		for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
			$noiseArray[$xx] = $this->noise3D($xx + $x, $y, $z);
		}

		for($xx = 0; $xx < $xSize; ++$xx){
			if($xx % $samplingRate !== 0){
				$nx = (int) ($xx / $samplingRate) * $samplingRate;
				$noiseArray[$xx] = self::linearLerp($xx, $nx, $nx + $samplingRate, $noiseArray[$nx], $noiseArray[$nx + $samplingRate]);
			}
		}

		return $noiseArray;
	}

	/**
	 * @return \SplFixedArray|float[][]
	 * @phpstan-return \SplFixedArray<\SplFixedArray<float>>
	 */
	public function getFastNoise2D(int $xSize, int $zSize, int $samplingRate, int $x, int $y, int $z) : \SplFixedArray{
		assert($samplingRate !== 0, new \InvalidArgumentException("samplingRate cannot be 0"));

		assert($xSize % $samplingRate === 0, new \InvalidArgumentException("xSize % samplingRate must return 0"));
		assert($zSize % $samplingRate === 0, new \InvalidArgumentException("zSize % samplingRate must return 0"));

		$noiseArray = new \SplFixedArray($xSize + 1);

		for($xx = 0; $xx <= $xSize; $xx += $samplingRate){
			$noiseArray[$xx] = new \SplFixedArray($zSize + 1);
			for($zz = 0; $zz <= $zSize; $zz += $samplingRate){
				$noiseArray[$xx][$zz] = $this->noise3D($x + $xx, $y, $z + $zz);
			}
		}

		for($xx = 0; $xx < $xSize; ++$xx){
			if($xx % $samplingRate !== 0){
				$noiseArray[$xx] = new \SplFixedArray($zSize + 1);
			}

			for($zz = 0; $zz < $zSize; ++$zz){
				if($xx % $samplingRate !== 0 or $zz % $samplingRate !== 0){
					$nx = (int) ($xx / $samplingRate) * $samplingRate;
					$nz = (int) ($zz / $samplingRate) * $samplingRate;
					$noiseArray[$xx][$zz] = Noise::bilinearLerp(
						$xx, $zz, $noiseArray[$nx][$nz], $noiseArray[$nx][$nz + $samplingRate],
						$noiseArray[$nx + $samplingRate][$nz], $noiseArray[$nx + $samplingRate][$nz + $samplingRate],
						$nx, $nx + $samplingRate, $nz, $nz + $samplingRate
					);
				}
			}
		}

		return $noiseArray;
	}

	/**
	 * @return float[][][]
	 */
	public function getFastNoise3D(int $xSize, int $ySize, int $zSize, int $xSamplingRate, int $ySamplingRate, int $zSamplingRate, int $x, int $y, int $z) : array{

		assert($xSamplingRate !== 0, new \InvalidArgumentException("xSamplingRate cannot be 0"));
		assert($zSamplingRate !== 0, new \InvalidArgumentException("zSamplingRate cannot be 0"));
		assert($ySamplingRate !== 0, new \InvalidArgumentException("ySamplingRate cannot be 0"));

		assert($xSize % $xSamplingRate === 0, new \InvalidArgumentException("xSize % xSamplingRate must return 0"));
		assert($zSize % $zSamplingRate === 0, new \InvalidArgumentException("zSize % zSamplingRate must return 0"));
		assert($ySize % $ySamplingRate === 0, new \InvalidArgumentException("ySize % ySamplingRate must return 0"));

		$noiseArray = array_fill(0, $xSize + 1, array_fill(0, $zSize + 1, []));

		for($xx = 0; $xx <= $xSize; $xx += $xSamplingRate){
			for($zz = 0; $zz <= $zSize; $zz += $zSamplingRate){
				for($yy = 0; $yy <= $ySize; $yy += $ySamplingRate){
					$noiseArray[$xx][$zz][$yy] = $this->noise3D($x + $xx, $y + $yy, $z + $zz, true);
				}
			}
		}

		for($xx = 0; $xx < $xSize; ++$xx){
			for($zz = 0; $zz < $zSize; ++$zz){
				for($yy = 0; $yy < $ySize; ++$yy){
					if($xx % $xSamplingRate !== 0 or $zz % $zSamplingRate !== 0 or $yy % $ySamplingRate !== 0){
						$nx = (int) ($xx / $xSamplingRate) * $xSamplingRate;
						$ny = (int) ($yy / $ySamplingRate) * $ySamplingRate;
						$nz = (int) ($zz / $zSamplingRate) * $zSamplingRate;

						$nnx = $nx + $xSamplingRate;
						$nny = $ny + $ySamplingRate;
						$nnz = $nz + $zSamplingRate;

						$dx1 = (($nnx - $xx) / ($nnx - $nx));
						$dx2 = (($xx - $nx) / ($nnx - $nx));
						$dy1 = (($nny - $yy) / ($nny - $ny));
						$dy2 = (($yy - $ny) / ($nny - $ny));

						$noiseArray[$xx][$zz][$yy] = (($nnz - $zz) / ($nnz - $nz)) * (
								$dy1 * (
									$dx1 * $noiseArray[$nx][$nz][$ny] + $dx2 * $noiseArray[$nnx][$nz][$ny]
								) + $dy2 * (
									$dx1 * $noiseArray[$nx][$nz][$nny] + $dx2 * $noiseArray[$nnx][$nz][$nny]
								)
							) + (($zz - $nz) / ($nnz - $nz)) * (
								$dy1 * (
									$dx1 * $noiseArray[$nx][$nnz][$ny] + $dx2 * $noiseArray[$nnx][$nnz][$ny]
								) + $dy2 * (
									$dx1 * $noiseArray[$nx][$nnz][$nny] + $dx2 * $noiseArray[$nnx][$nnz][$nny]
								)
							);
					}
				}
			}
		}

		return $noiseArray;
	}

	/**
	 * @param float $x
	 * @param float $y
	 * @param float $z
	 *
	 * @return void
	 */
	public function setOffset($x, $y, $z){
		$this->offsetX = $x;
		$this->offsetY = $y;
		$this->offsetZ = $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\generator\biome;

use pocketmine\level\biome\Biome;
use pocketmine\level\biome\UnknownBiome;
use pocketmine\level\generator\noise\Simplex;
use pocketmine\utils\Random;

abstract class BiomeSelector{
	/** @var Simplex */
	private $temperature;
	/** @var Simplex */
	private $rainfall;

	/**
	 * @var Biome[]|\SplFixedArray
	 * @phpstan-var \SplFixedArray<Biome>
	 */
	private $map = null;

	public function __construct(Random $random){
		$this->temperature = new Simplex($random, 2, 1 / 16, 1 / 512);
		$this->rainfall = new Simplex($random, 2, 1 / 16, 1 / 512);
	}

	/**
	 * Lookup function called by recalculate() to determine the biome to use for this temperature and rainfall.
	 *
	 * @return int biome ID 0-255
	 */
	abstract protected function lookup(float $temperature, float $rainfall) : int;

	/**
	 * @return void
	 */
	public function recalculate(){
		$this->map = new \SplFixedArray(64 * 64);

		for($i = 0; $i < 64; ++$i){
			for($j = 0; $j < 64; ++$j){
				$biome = Biome::getBiome($this->lookup($i / 63, $j / 63));
				if($biome instanceof UnknownBiome){
					throw new \RuntimeException("Unknown biome returned by selector with ID " . $biome->getId());
				}
				$this->map[$i + ($j << 6)] = $biome;
			}
		}
	}

	/**
	 * @param float $x
	 * @param float $z
	 *
	 * @return float
	 */
	public function getTemperature($x, $z){
		return ($this->temperature->noise2D($x, $z, true) + 1) / 2;
	}

	/**
	 * @param float $x
	 * @param float $z
	 *
	 * @return float
	 */
	public function getRainfall($x, $z){
		return ($this->rainfall->noise2D($x, $z, true) + 1) / 2;
	}

	/**
	 * @param int $x
	 * @param int $z
	 */
	public function pickBiome($x, $z) : Biome{
		$temperature = (int) ($this->getTemperature($x, $z) * 63);
		$rainfall = (int) ($this->getRainfall($x, $z) * 63);

		return $this->map[$temperature + ($rainfall << 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\level\generator\populator;

use pocketmine\block\BlockFactory;
use pocketmine\block\Liquid;
use pocketmine\level\biome\Biome;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;
use function count;
use function min;
use function ord;

class GroundCover extends Populator{

	public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){
		$chunk = $level->getChunk($chunkX, $chunkZ);
		for($x = 0; $x < 16; ++$x){
			for($z = 0; $z < 16; ++$z){
				$biome = Biome::getBiome($chunk->getBiomeId($x, $z));
				$cover = $biome->getGroundCover();
				if(count($cover) > 0){
					$diffY = 0;
					if(!$cover[0]->isSolid()){
						$diffY = 1;
					}

					$column = $chunk->getBlockIdColumn($x, $z);
					$startY = 127;
					for(; $startY > 0; --$startY){
						if($column[$startY] !== "\x00" and !BlockFactory::get(ord($column[$startY]))->isTransparent()){
							break;
						}
					}
					$startY = min(127, $startY + $diffY);
					$endY = $startY - count($cover);
					for($y = $startY; $y > $endY and $y >= 0; --$y){
						$b = $cover[$startY - $y];
						if($column[$y] === "\x00" and $b->isSolid()){
							break;
						}
						if($b->canBeFlowedInto() and BlockFactory::get(ord($column[$y])) instanceof Liquid){
							continue;
						}
						if($b->getDamage() === 0){
							$chunk->setBlockId($x, $y, $z, $b->getId());
						}else{
							$chunk->setBlock($x, $y, $z, $b->getId(), $b->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\level\generator\populator;

use pocketmine\level\ChunkManager;
use pocketmine\level\generator\object\Ore as ObjectOre;
use pocketmine\level\generator\object\OreType;
use pocketmine\utils\Random;

class Ore extends Populator{
	/** @var OreType[] */
	private $oreTypes = [];

	public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){
		foreach($this->oreTypes as $type){
			$ore = new ObjectOre($random, $type);
			for($i = 0; $i < $ore->type->clusterCount; ++$i){
				$x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15);
				$y = $random->nextRange($ore->type->minHeight, $ore->type->maxHeight);
				$z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15);
				if($ore->canPlaceObject($level, $x, $y, $z)){
					$ore->placeObject($level, $x, $y, $z);
				}
			}
		}
	}

	/**
	 * @param OreType[] $types
	 *
	 * @return void
	 */
	public function setOreTypes(array $types){
		$this->oreTypes = $types;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 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\object;

use pocketmine\block\Block;

class OreType{
	/** @var Block */
	public $material;
	/** @var int */
	public $clusterCount;
	/** @var int */
	public $clusterSize;
	/** @var int */
	public $maxHeight;
	/** @var int */
	public $minHeight;

	public function __construct(Block $material, int $clusterCount, int $clusterSize, int $minHeight, int $maxHeight){
		$this->material = $material;
		$this->clusterCount = $clusterCount;
		$this->clusterSize = $clusterSize;
		$this->maxHeight = $maxHeight;
		$this->minHeight = $minHeight;
	}
}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the 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\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\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\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\level\generator\object;

use pocketmine\block\Block;
use pocketmine\level\ChunkManager;
use pocketmine\math\VectorMath;
use pocketmine\utils\Random;
use function sin;
use const M_PI;

class Ore{
	/** @var Random */
	private $random;
	/** @var OreType */
	public $type;

	public function __construct(Random $random, OreType $type){
		$this->type = $type;
		$this->random = $random;
	}

	public function getType() : OreType{
		return $this->type;
	}

	public function canPlaceObject(ChunkManager $level, int $x, int $y, int $z) : bool{
		return $level->getBlockIdAt($x, $y, $z) === Block::STONE;
	}

	/**
	 * @return void
	 */
	public function placeObject(ChunkManager $level, int $x, int $y, int $z){
		$clusterSize = $this->type->clusterSize;
		$angle = $this->random->nextFloat() * M_PI;
		$offset = VectorMath::getDirection2D($angle)->multiply($clusterSize / 8);
		$x1 = $x + 8 + $offset->x;
		$x2 = $x + 8 - $offset->x;
		$z1 = $z + 8 + $offset->y;
		$z2 = $z + 8 - $offset->y;
		$y1 = $y + $this->random->nextBoundedInt(3) + 2;
		$y2 = $y + $this->random->nextBoundedInt(3) + 2;
		for($count = 0; $count <= $clusterSize; ++$count){
			$seedX = $x1 + ($x2 - $x1) * $count / $clusterSize;
			$seedY = $y1 + ($y2 - $y1) * $count / $clusterSize;
			$seedZ = $z1 + ($z2 - $z1) * $count / $clusterSize;
			$size = ((sin($count * (M_PI / $clusterSize)) + 1) * $this->random->nextFloat() * $clusterSize / 16 + 1) / 2;

			$startX = (int) ($seedX - $size);
			$startY = (int) ($seedY - $size);
			$startZ = (int) ($seedZ - $size);
			$endX = (int) ($seedX + $size);
			$endY = (int) ($seedY + $size);
			$endZ = (int) ($seedZ + $size);

			for($xx = $startX; $xx <= $endX; ++$xx){
				$sizeX = ($xx + 0.5 - $seedX) / $size;
				$sizeX *= $sizeX;

				if($sizeX < 1){
					for($yy = $startY; $yy <= $endY; ++$yy){
						$sizeY = ($yy + 0.5 - $seedY) / $size;
						$sizeY *= $sizeY;

						if($yy > 0 and ($sizeX + $sizeY) < 1){
							for($zz = $startZ; $zz <= $endZ; ++$zz){
								$sizeZ = ($zz + 0.5 - $seedZ) / $size;
								$sizeZ *= $sizeZ;

								if(($sizeX + $sizeY + $sizeZ) < 1 and $level->getBlockIdAt($xx, $yy, $zz) === Block::STONE){
									$level->setBlockIdAt($xx, $yy, $zz, $this->type->material->getId());
									if($this->type->material->getDamage() !== 0){
										$level->setBlockDataAt($xx, $yy, $zz, $this->type->material->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\math;

use function cos;
use function sin;

abstract class VectorMath{

	public static function getDirection2D(float $azimuth) : Vector2{
		return new Vector2(cos($azimuth), sin($azimuth));
	}

}
<?php

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 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\level\generator\object;

use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\block\Sapling;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;
use function abs;

abstract class Tree{
	/** @var bool[] */
	public $overridable = [
		Block::AIR => true,
		Block::SAPLING => true,
		Block::LEAVES => true,
		Block::SNOW_LAYER => true,
		Block::LEAVES2 => true
	];

	/** @var int */
	public $type = 0;
	/** @var int */
	public $trunkBlock = Block::LOG;
	/** @var int */
	public $leafBlock = Block::LEAVES;
	/** @var int */
	public $treeHeight = 7;

	/**
	 * @return void
	 */
	public static function growTree(ChunkManager $level, int $x, int $y, int $z, Random $random, int $type = 0){
		switch($type){
			case Sapling::SPRUCE:
				$tree = new SpruceTree();
				break;
			case Sapling::BIRCH:
				if($random->nextBoundedInt(39) === 0){
					$tree = new BirchTree(true);
				}else{
					$tree = new BirchTree();
				}
				break;
			case Sapling::JUNGLE:
				$tree = new JungleTree();
				break;
			case Sapling::ACACIA:
			case Sapling::DARK_OAK:
				return; //TODO
			default:
				$tree = new OakTree();
				/*if($random->nextRange(0, 9) === 0){
					$tree = new BigTree();
				}else{*/

				//}
				break;
		}
		if($tree->canPlaceObject($level, $x, $y, $z, $random)){
			$tree->placeObject($level, $x, $y, $z, $random);
		}
	}

	public function canPlaceObject(ChunkManager $level, int $x, int $y, int $z, Random $random) : bool{
		$radiusToCheck = 0;
		for($yy = 0; $yy < $this->treeHeight + 3; ++$yy){
			if($yy === 1 or $yy === $this->treeHeight){
				++$radiusToCheck;
			}
			for($xx = -$radiusToCheck; $xx < ($radiusToCheck + 1); ++$xx){
				for($zz = -$radiusToCheck; $zz < ($radiusToCheck + 1); ++$zz){
					if(!isset($this->overridable[$level->getBlockIdAt($x + $xx, $y + $yy, $z + $zz)])){
						return false;
					}
				}
			}
		}

		return true;
	}

	/**
	 * @return void
	 */
	public function placeObject(ChunkManager $level, int $x, int $y, int $z, Random $random){

		$this->placeTrunk($level, $x, $y, $z, $random, $this->treeHeight - 1);

		for($yy = $y - 3 + $this->treeHeight; $yy <= $y + $this->treeHeight; ++$yy){
			$yOff = $yy - ($y + $this->treeHeight);
			$mid = (int) (1 - $yOff / 2);
			for($xx = $x - $mid; $xx <= $x + $mid; ++$xx){
				$xOff = abs($xx - $x);
				for($zz = $z - $mid; $zz <= $z + $mid; ++$zz){
					$zOff = abs($zz - $z);
					if($xOff === $mid and $zOff === $mid and ($yOff === 0 or $random->nextBoundedInt(2) === 0)){
						continue;
					}
					if(!BlockFactory::$solid[$level->getBlockIdAt($xx, $yy, $zz)]){
						$level->setBlockIdAt($xx, $yy, $zz, $this->leafBlock);
						$level->setBlockDataAt($xx, $yy, $zz, $this->type);
					}
				}
			}
		}
	}

	/**
	 * @return void
	 */
	protected function placeTrunk(ChunkManager $level, int $x, int $y, int $z, Random $random, int $trunkHeight){
		// The base dirt block
		$level->setBlockIdAt($x, $y - 1, $z, Block::DIRT);

		for($yy = 0; $yy < $trunkHeight; ++$yy){
			$blockId = $level->getBlockIdAt($x, $y + $yy, $z);
			if(isset($this->overridable[$blockId])){
				$level->setBlockIdAt($x, $y + $yy, $z, $this->trunkBlock);
				$level->setBlockDataAt($x, $y + $yy, $z, $this->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\level\generator\object;

use pocketmine\block\Block;
use pocketmine\block\Wood;
use pocketmine\level\ChunkManager;
use pocketmine\utils\Random;

class OakTree extends Tree{

	public function __construct(){
		$this->trunkBlock = Block::LOG;
		$this->leafBlock = Block::LEAVES;
		$this->type = Wood::OAK;
	}

	/**
	 * @return void
	 */
	public function placeObject(ChunkManager $level, int $x, int $y, int $z, Random $random){
		$this->treeHeight = $random->nextBoundedInt(3) + 4;
		parent::placeObject($level, $x, $y, $z, $random);
	}
}
