From b912b9173c9dd6d977b1aeb5a5271f66e3a13731 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 3 Aug 2017 16:46:31 +0100 Subject: [PATCH] Changed how blocks are registered, add API to allow registering custom blocks --- src/pocketmine/block/Block.php | 391 ++++++++++++++------------ src/pocketmine/level/Level.php | 2 +- tests/plugins/PocketMine-TesterPlugin | 2 +- 3 files changed, 207 insertions(+), 188 deletions(-) diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index 237afc249..1c3e40c01 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -65,8 +65,14 @@ class Block extends Position implements BlockIds, Metadatable{ /** @var AxisAlignedBB */ public $boundingBox = null; - public static function init(){ - if(self::$list === null){ + /** + * 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. + * + * @param bool $force + */ + public static function init(bool $force = false){ + if(self::$list === null or $force){ self::$list = new \SplFixedArray(256); self::$fullList = new \SplFixedArray(4096); self::$light = new \SplFixedArray(256); @@ -76,214 +82,226 @@ class Block extends Position implements BlockIds, Metadatable{ self::$transparent = new \SplFixedArray(256); self::$diffusesSkyLight = new \SplFixedArray(256); - self::$list[self::AIR] = Air::class; - self::$list[self::STONE] = Stone::class; - self::$list[self::GRASS] = Grass::class; - self::$list[self::DIRT] = Dirt::class; - self::$list[self::COBBLESTONE] = Cobblestone::class; - self::$list[self::PLANKS] = Planks::class; - self::$list[self::SAPLING] = Sapling::class; - self::$list[self::BEDROCK] = Bedrock::class; - self::$list[self::WATER] = Water::class; - self::$list[self::STILL_WATER] = StillWater::class; - self::$list[self::LAVA] = Lava::class; - self::$list[self::STILL_LAVA] = StillLava::class; - self::$list[self::SAND] = Sand::class; - self::$list[self::GRAVEL] = Gravel::class; - self::$list[self::GOLD_ORE] = GoldOre::class; - self::$list[self::IRON_ORE] = IronOre::class; - self::$list[self::COAL_ORE] = CoalOre::class; - self::$list[self::WOOD] = Wood::class; - self::$list[self::LEAVES] = Leaves::class; - self::$list[self::SPONGE] = Sponge::class; - self::$list[self::GLASS] = Glass::class; - self::$list[self::LAPIS_ORE] = LapisOre::class; - self::$list[self::LAPIS_BLOCK] = Lapis::class; + 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()); - self::$list[self::SANDSTONE] = Sandstone::class; - self::$list[self::NOTE_BLOCK] = NoteBlock::class; - self::$list[self::BED_BLOCK] = Bed::class; - self::$list[self::POWERED_RAIL] = PoweredRail::class; - self::$list[self::DETECTOR_RAIL] = DetectorRail::class; + self::registerBlock(new Sandstone()); + self::registerBlock(new NoteBlock()); + self::registerBlock(new Bed()); + self::registerBlock(new PoweredRail()); + self::registerBlock(new DetectorRail()); - self::$list[self::COBWEB] = Cobweb::class; - self::$list[self::TALL_GRASS] = TallGrass::class; - self::$list[self::DEAD_BUSH] = DeadBush::class; + self::registerBlock(new Cobweb()); + self::registerBlock(new TallGrass()); + self::registerBlock(new DeadBush()); - self::$list[self::WOOL] = Wool::class; + self::registerBlock(new Wool()); - self::$list[self::DANDELION] = Dandelion::class; - self::$list[self::RED_FLOWER] = Flower::class; - self::$list[self::BROWN_MUSHROOM] = BrownMushroom::class; - self::$list[self::RED_MUSHROOM] = RedMushroom::class; - self::$list[self::GOLD_BLOCK] = Gold::class; - self::$list[self::IRON_BLOCK] = Iron::class; - self::$list[self::DOUBLE_SLAB] = DoubleSlab::class; - self::$list[self::SLAB] = Slab::class; - self::$list[self::BRICKS_BLOCK] = Bricks::class; - self::$list[self::TNT] = TNT::class; - self::$list[self::BOOKSHELF] = Bookshelf::class; - self::$list[self::MOSS_STONE] = MossStone::class; - self::$list[self::OBSIDIAN] = Obsidian::class; - self::$list[self::TORCH] = Torch::class; - self::$list[self::FIRE] = Fire::class; - self::$list[self::MONSTER_SPAWNER] = MonsterSpawner::class; - self::$list[self::WOOD_STAIRS] = WoodStairs::class; - self::$list[self::CHEST] = Chest::class; + 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 DoubleSlab()); + self::registerBlock(new Slab()); + self::registerBlock(new Bricks()); + self::registerBlock(new TNT()); + self::registerBlock(new Bookshelf()); + self::registerBlock(new MossStone()); + self::registerBlock(new Obsidian()); + self::registerBlock(new Torch()); + self::registerBlock(new Fire()); + self::registerBlock(new MonsterSpawner()); + self::registerBlock(new WoodStairs()); + self::registerBlock(new Chest()); - self::$list[self::DIAMOND_ORE] = DiamondOre::class; - self::$list[self::DIAMOND_BLOCK] = Diamond::class; - self::$list[self::WORKBENCH] = Workbench::class; - self::$list[self::WHEAT_BLOCK] = Wheat::class; - self::$list[self::FARMLAND] = Farmland::class; - self::$list[self::FURNACE] = Furnace::class; - self::$list[self::BURNING_FURNACE] = BurningFurnace::class; - self::$list[self::SIGN_POST] = SignPost::class; - self::$list[self::WOOD_DOOR_BLOCK] = WoodDoor::class; - self::$list[self::LADDER] = Ladder::class; - self::$list[self::RAIL] = Rail::class; - self::$list[self::COBBLESTONE_STAIRS] = CobblestoneStairs::class; - self::$list[self::WALL_SIGN] = WallSign::class; - self::$list[self::LEVER] = Lever::class; - self::$list[self::STONE_PRESSURE_PLATE] = StonePressurePlate::class; - self::$list[self::IRON_DOOR_BLOCK] = IronDoor::class; - self::$list[self::WOODEN_PRESSURE_PLATE] = WoodenPressurePlate::class; - self::$list[self::REDSTONE_ORE] = RedstoneOre::class; - self::$list[self::GLOWING_REDSTONE_ORE] = GlowingRedstoneOre::class; - self::$list[self::UNLIT_REDSTONE_TORCH] = RedstoneTorchUnlit::class; - self::$list[self::LIT_REDSTONE_TORCH] = RedstoneTorch::class; - self::$list[self::STONE_BUTTON] = StoneButton::class; - self::$list[self::SNOW_LAYER] = SnowLayer::class; - self::$list[self::ICE] = Ice::class; - self::$list[self::SNOW_BLOCK] = Snow::class; - self::$list[self::CACTUS] = Cactus::class; - self::$list[self::CLAY_BLOCK] = Clay::class; - self::$list[self::SUGARCANE_BLOCK] = Sugarcane::class; + self::registerBlock(new DiamondOre()); + self::registerBlock(new Diamond()); + self::registerBlock(new Workbench()); + self::registerBlock(new Wheat()); + self::registerBlock(new Farmland()); + self::registerBlock(new Furnace()); + self::registerBlock(new BurningFurnace()); + self::registerBlock(new SignPost()); + self::registerBlock(new WoodDoor()); + 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()); - self::$list[self::FENCE] = Fence::class; - self::$list[self::PUMPKIN] = Pumpkin::class; - self::$list[self::NETHERRACK] = Netherrack::class; - self::$list[self::SOUL_SAND] = SoulSand::class; - self::$list[self::GLOWSTONE_BLOCK] = Glowstone::class; + self::registerBlock(new Fence()); + self::registerBlock(new Pumpkin()); + self::registerBlock(new Netherrack()); + self::registerBlock(new SoulSand()); + self::registerBlock(new Glowstone()); - self::$list[self::LIT_PUMPKIN] = LitPumpkin::class; - self::$list[self::CAKE_BLOCK] = Cake::class; + self::registerBlock(new LitPumpkin()); + self::registerBlock(new Cake()); - self::$list[self::TRAPDOOR] = Trapdoor::class; + self::registerBlock(new Trapdoor()); - self::$list[self::STONE_BRICKS] = StoneBricks::class; + self::registerBlock(new StoneBricks()); - self::$list[self::IRON_BARS] = IronBars::class; - self::$list[self::GLASS_PANE] = GlassPane::class; - self::$list[self::MELON_BLOCK] = Melon::class; - self::$list[self::PUMPKIN_STEM] = PumpkinStem::class; - self::$list[self::MELON_STEM] = MelonStem::class; - self::$list[self::VINE] = Vine::class; - self::$list[self::FENCE_GATE] = FenceGate::class; - self::$list[self::BRICK_STAIRS] = BrickStairs::class; - self::$list[self::STONE_BRICK_STAIRS] = StoneBrickStairs::class; - self::$list[self::MYCELIUM] = Mycelium::class; - self::$list[self::WATER_LILY] = WaterLily::class; - self::$list[self::NETHER_BRICKS] = NetherBrick::class; - self::$list[self::NETHER_BRICK_FENCE] = NetherBrickFence::class; - self::$list[self::NETHER_BRICKS_STAIRS] = NetherBrickStairs::class; + 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()); + self::registerBlock(new BrickStairs()); + self::registerBlock(new StoneBrickStairs()); + self::registerBlock(new Mycelium()); + self::registerBlock(new WaterLily()); + self::registerBlock(new NetherBrick()); + self::registerBlock(new NetherBrickFence()); + self::registerBlock(new NetherBrickStairs()); - self::$list[self::ENCHANTING_TABLE] = EnchantingTable::class; - self::$list[self::BREWING_STAND_BLOCK] = BrewingStand::class; + self::registerBlock(new EnchantingTable()); + self::registerBlock(new BrewingStand()); - self::$list[self::END_PORTAL_FRAME] = EndPortalFrame::class; - self::$list[self::END_STONE] = EndStone::class; + self::registerBlock(new EndPortalFrame()); + self::registerBlock(new EndStone()); - self::$list[self::REDSTONE_LAMP] = RedstoneLamp::class; - self::$list[self::LIT_REDSTONE_LAMP] = LitRedstoneLamp::class; + self::registerBlock(new RedstoneLamp()); + self::registerBlock(new LitRedstoneLamp()); - self::$list[self::ACTIVATOR_RAIL] = ActivatorRail::class; - self::$list[self::COCOA_BLOCK] = CocoaBlock::class; - self::$list[self::SANDSTONE_STAIRS] = SandstoneStairs::class; - self::$list[self::EMERALD_ORE] = EmeraldOre::class; + self::registerBlock(new ActivatorRail()); + self::registerBlock(new CocoaBlock()); + self::registerBlock(new SandstoneStairs()); + self::registerBlock(new EmeraldOre()); - self::$list[self::TRIPWIRE_HOOK] = TripwireHook::class; - self::$list[self::TRIPWIRE] = Tripwire::class; - self::$list[self::EMERALD_BLOCK] = Emerald::class; - self::$list[self::SPRUCE_WOOD_STAIRS] = SpruceWoodStairs::class; - self::$list[self::BIRCH_WOOD_STAIRS] = BirchWoodStairs::class; - self::$list[self::JUNGLE_WOOD_STAIRS] = JungleWoodStairs::class; + self::registerBlock(new TripwireHook()); + self::registerBlock(new Tripwire()); + self::registerBlock(new Emerald()); + self::registerBlock(new SpruceWoodStairs()); + self::registerBlock(new BirchWoodStairs()); + self::registerBlock(new JungleWoodStairs()); - self::$list[self::STONE_WALL] = StoneWall::class; - self::$list[self::FLOWER_POT_BLOCK] = FlowerPot::class; - self::$list[self::CARROT_BLOCK] = Carrot::class; - self::$list[self::POTATO_BLOCK] = Potato::class; - self::$list[self::WOODEN_BUTTON] = WoodenButton::class; - self::$list[self::MOB_HEAD_BLOCK] = MobHead::class; - self::$list[self::ANVIL] = Anvil::class; - self::$list[self::TRAPPED_CHEST] = TrappedChest::class; - self::$list[self::WEIGHTED_PRESSURE_PLATE_LIGHT] = WeightedPressurePlateLight::class; - self::$list[self::WEIGHTED_PRESSURE_PLATE_HEAVY] = WeightedPressurePlateHeavy::class; + self::registerBlock(new StoneWall()); + self::registerBlock(new FlowerPot()); + self::registerBlock(new Carrot()); + self::registerBlock(new Potato()); + self::registerBlock(new WoodenButton()); + self::registerBlock(new MobHead()); + self::registerBlock(new Anvil()); + self::registerBlock(new TrappedChest()); + self::registerBlock(new WeightedPressurePlateLight()); + self::registerBlock(new WeightedPressurePlateHeavy()); - self::$list[self::DAYLIGHT_SENSOR] = DaylightSensor::class; - self::$list[self::REDSTONE_BLOCK] = Redstone::class; + self::registerBlock(new DaylightSensor()); + self::registerBlock(new Redstone()); - self::$list[self::QUARTZ_BLOCK] = Quartz::class; - self::$list[self::QUARTZ_STAIRS] = QuartzStairs::class; - self::$list[self::DOUBLE_WOOD_SLAB] = DoubleWoodSlab::class; - self::$list[self::WOOD_SLAB] = WoodSlab::class; - self::$list[self::STAINED_CLAY] = StainedClay::class; + self::registerBlock(new Quartz()); + self::registerBlock(new QuartzStairs()); + self::registerBlock(new DoubleWoodSlab()); + self::registerBlock(new WoodSlab()); + self::registerBlock(new StainedClay()); - self::$list[self::LEAVES2] = Leaves2::class; - self::$list[self::WOOD2] = Wood2::class; - self::$list[self::ACACIA_WOOD_STAIRS] = AcaciaWoodStairs::class; - self::$list[self::DARK_OAK_WOOD_STAIRS] = DarkOakWoodStairs::class; + self::registerBlock(new Leaves2()); + self::registerBlock(new Wood2()); + self::registerBlock(new AcaciaWoodStairs()); + self::registerBlock(new DarkOakWoodStairs()); - self::$list[self::IRON_TRAPDOOR] = IronTrapdoor::class; - self::$list[self::PRISMARINE] = Prismarine::class; - self::$list[self::SEA_LANTERN] = SeaLantern::class; - self::$list[self::HAY_BALE] = HayBale::class; - self::$list[self::CARPET] = Carpet::class; - self::$list[self::HARDENED_CLAY] = HardenedClay::class; - self::$list[self::COAL_BLOCK] = Coal::class; - self::$list[self::PACKED_ICE] = PackedIce::class; - self::$list[self::DOUBLE_PLANT] = DoublePlant::class; + 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::$list[self::FENCE_GATE_SPRUCE] = FenceGateSpruce::class; - self::$list[self::FENCE_GATE_BIRCH] = FenceGateBirch::class; - self::$list[self::FENCE_GATE_JUNGLE] = FenceGateJungle::class; - self::$list[self::FENCE_GATE_DARK_OAK] = FenceGateDarkOak::class; - self::$list[self::FENCE_GATE_ACACIA] = FenceGateAcacia::class; + self::registerBlock(new FenceGateSpruce()); + self::registerBlock(new FenceGateBirch()); + self::registerBlock(new FenceGateJungle()); + self::registerBlock(new FenceGateDarkOak()); + self::registerBlock(new FenceGateAcacia()); - self::$list[self::GRASS_PATH] = GrassPath::class; - self::$list[self::ITEM_FRAME_BLOCK] = ItemFrame::class; + self::registerBlock(new GrassPath()); + self::registerBlock(new ItemFrame()); - self::$list[self::PODZOL] = Podzol::class; - self::$list[self::BEETROOT_BLOCK] = Beetroot::class; - self::$list[self::STONECUTTER] = Stonecutter::class; - self::$list[self::GLOWING_OBSIDIAN] = GlowingObsidian::class; - - foreach(self::$list as $id => $class){ - if($class !== null){ - /** @var Block $block */ - $block = new $class(); - - for($data = 0; $data < 16; ++$data){ - self::$fullList[($id << 4) | $data] = new $class($data); - } - }else{ - $block = new UnknownBlock($id); - - for($data = 0; $data < 16; ++$data){ - self::$fullList[($id << 4) | $data] = new UnknownBlock($id, $data); - } - } - - self::$solid[$id] = $block->isSolid(); - self::$transparent[$id] = $block->isTransparent(); - self::$hardness[$id] = $block->getHardness(); - self::$light[$id] = $block->getLightLevel(); - self::$lightFilter[$id] = $block->getLightFilter() + 1; - self::$diffusesSkyLight[$id] = $block->diffusesSkyLight(); - } + self::registerBlock(new Podzol()); + self::registerBlock(new Beetroot()); + self::registerBlock(new Stonecutter()); + self::registerBlock(new GlowingObsidian()); } } + /** + * 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){ + $id = $block->getId(); + + if(isset(self::$list[$id]) and !$override){ + throw new \RuntimeException("Trying to overwrite an already registered block"); + } + + self::$list[$id] = clone $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] = $block->getLightFilter(); + self::$diffusesSkyLight[$id] = $block->diffusesSkyLight(); + } + /** * @param int $id * @param int $meta @@ -293,13 +311,14 @@ class Block extends Position implements BlockIds, Metadatable{ */ public static function get($id, $meta = 0, Position $pos = null){ try{ - $block = self::$list[$id]; + $block = self::$fullList[($id << 4) | $meta]; if($block !== null){ - $block = new $block($meta); + $block = clone $block; }else{ $block = new UnknownBlock($id, $meta); } }catch(\RuntimeException $e){ + //TODO: this probably should return null (out of bounds IDs may cause unexpected behaviour) $block = new UnknownBlock($id, $meta); } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index fdb59e817..574f71f30 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -912,7 +912,7 @@ class Level implements ChunkManager, Metadatable{ } public function addRandomTickedBlock(int $id){ - $this->randomTickBlocks[$id] = Block::$list[$id]; + $this->randomTickBlocks[$id] = get_class(Block::$list[$id]); } public function removeRandomTickedBlock(int $id){ diff --git a/tests/plugins/PocketMine-TesterPlugin b/tests/plugins/PocketMine-TesterPlugin index b57891001..6f75fd9b5 160000 --- a/tests/plugins/PocketMine-TesterPlugin +++ b/tests/plugins/PocketMine-TesterPlugin @@ -1 +1 @@ -Subproject commit b57891001a564f6513846e24844f2105fff7a8e1 +Subproject commit 6f75fd9b5c2be8b8a281685df77cea472aa521ff