Files
PocketMine-MP/src/pocketmine/block/BlockFactory.php
Dylan K. Taylor 4b9a142a5d Import global functions and constants for enhanced performance
This is better for performance because these then don't need to be reevaluated every time they are called.

When encountering an unqualified function or constant reference, PHP will first try to locate a symbol in the current namespace by that name, and then fall back to the global namespace.
This short-circuits the check, which has substantial performance effects in some cases - in particular, ord(), chr() and strlen() show ~1500x faster calls when they are fully qualified.

However, this doesn't mean that PM is getting a massive amount faster. In real world terms, this translates to about 10-15% performance improvement.
But before anyone gets excited, you should know that the CodeOptimizer in the PreProcessor repo has been applying fully-qualified symbol optimizations to Jenkins builds for years, which is one of the reasons why Jenkins builds have better performance than home-built or source installations.
We're choosing to do this for the sake of future SafePHP integration and also to be able to get rid of the buggy CodeOptimizer, so that phar and source are more consistent.
2019-01-04 20:43:15 +00:00

473 lines
17 KiB
PHP

<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, 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 function file_get_contents;
use function json_decode;
use function max;
use function min;
/**
* Manages block registration and instance creation
*/
class BlockFactory{
/** @var \SplFixedArray<Block> */
private static $fullList = null;
/** @var \SplFixedArray<bool> */
public static $solid = null;
/** @var \SplFixedArray<bool> */
public static $transparent = null;
/** @var \SplFixedArray<float> */
public static $hardness = null;
/** @var \SplFixedArray<int> */
public static $light = null;
/** @var \SplFixedArray<int> */
public static $lightFilter = null;
/** @var \SplFixedArray<bool> */
public static $diffusesSkyLight = null;
/** @var \SplFixedArray<float> */
public static $blastResistance = null;
/** @var int[] */
public static $staticRuntimeIdMap = [];
/** @var int[] */
public static $legacyIdMap = [];
/** @var int */
private static $lastRuntimeId = 0;
/**
* 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
//TODO: 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());
//TODO: INFO_UPDATE
//TODO: INFO_UPDATE2
//TODO: MOVINGBLOCK
//TODO: OBSERVER
//TODO: STRUCTURE_BLOCK
//TODO: 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 Block $block
* @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.
*
* @param int $id
* @param int $meta
* @param Position $pos
*
* @return Block
*/
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
* @return \SplFixedArray
*/
public static function getBlockStatesArray() : \SplFixedArray{
return self::$fullList;
}
/**
* Returns whether a specified block ID is already registered in the block factory.
*
* @param int $id
*
* @return bool
*/
public static function isRegistered(int $id) : bool{
$b = self::$fullList[$id << 4];
return $b !== null and !($b instanceof UnknownBlock);
}
public static function registerStaticRuntimeIdMappings() : void{
/** @var mixed[] $runtimeIdMap */
$runtimeIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true);
foreach($runtimeIdMap as $k => $obj){
self::registerMapping($k, $obj["id"], $obj["data"]);
}
}
/**
* @internal
*
* @param int $id
* @param int $meta
*
* @return int
*/
public static function toStaticRuntimeId(int $id, int $meta = 0) : int{
/*
* try id+meta first
* if not found, try id+0 (strip meta)
* if still not found, return update! block
*/
return self::$staticRuntimeIdMap[($id << 4) | $meta] ?? self::$staticRuntimeIdMap[$id << 4] ?? self::$staticRuntimeIdMap[BlockIds::INFO_UPDATE << 4];
}
/**
* @internal
*
* @param int $runtimeId
*
* @return int[] [id, meta]
*/
public static function fromStaticRuntimeId(int $runtimeId) : array{
$v = self::$legacyIdMap[$runtimeId];
return [$v >> 4, $v & 0xf];
}
private static function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{
self::$staticRuntimeIdMap[($legacyId << 4) | $legacyMeta] = $staticRuntimeId;
self::$legacyIdMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta;
self::$lastRuntimeId = max(self::$lastRuntimeId, $staticRuntimeId);
}
}