diff --git a/src/pocketmine/block/BlockFactory.php b/src/pocketmine/block/BlockFactory.php index 8881f923e..80347af5f 100644 --- a/src/pocketmine/block/BlockFactory.php +++ b/src/pocketmine/block/BlockFactory.php @@ -36,6 +36,7 @@ use pocketmine\block\tile\EnchantTable as TileEnchantingTable; use pocketmine\block\tile\EnderChest as TileEnderChest; use pocketmine\block\tile\FlowerPot as TileFlowerPot; use pocketmine\block\tile\Furnace as TileFurnace; +use pocketmine\block\tile\Hopper as TileHopper; use pocketmine\block\tile\ItemFrame as TileItemFrame; use pocketmine\block\tile\MonsterSpawner as TileMonsterSpawner; use pocketmine\block\tile\Note as TileNote; @@ -178,6 +179,7 @@ class BlockFactory{ self::register(new HardenedGlass(new BID(Ids::HARD_GLASS), "Hardened Glass")); self::register(new HardenedGlassPane(new BID(Ids::HARD_GLASS_PANE), "Hardened Glass Pane")); self::register(new HayBale(new BID(Ids::HAY_BALE), "Hay Bale")); + self::register(new Hopper(new BID(Ids::HOPPER_BLOCK, 0, ItemIds::HOPPER, TileHopper::class), "Hopper", new BlockBreakInfo(3.0, BlockToolType::TYPE_PICKAXE, TieredTool::TIER_WOODEN, 15.0))); self::register(new Ice(new BID(Ids::ICE), "Ice")); self::register(new class(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE), "Infested Stone") extends InfestedStone{ public function getSilkTouchDrops(Item $item) : array{ diff --git a/src/pocketmine/block/BlockLegacyMetadata.php b/src/pocketmine/block/BlockLegacyMetadata.php index 5bad76438..899e93554 100644 --- a/src/pocketmine/block/BlockLegacyMetadata.php +++ b/src/pocketmine/block/BlockLegacyMetadata.php @@ -84,6 +84,8 @@ interface BlockLegacyMetadata{ public const FLOWER_POT_FLAG_OCCUPIED = 0x01; + public const HOPPER_FLAG_POWERED = 0x08; + public const INFESTED_STONE = 0; public const INFESTED_COBBLESTONE = 1; public const INFESTED_STONE_BRICK = 2; diff --git a/src/pocketmine/block/Hopper.php b/src/pocketmine/block/Hopper.php new file mode 100644 index 000000000..d626534f2 --- /dev/null +++ b/src/pocketmine/block/Hopper.php @@ -0,0 +1,88 @@ +facing = $facing; + $this->powered = ($stateMeta & BlockLegacyMetadata::HOPPER_FLAG_POWERED) !== 0; + } + + protected function writeStateToMeta() : int{ + return $this->facing | ($this->powered ? BlockLegacyMetadata::HOPPER_FLAG_POWERED : 0); + } + + public function getStateBitmask() : int{ + return 0b1111; + } + + protected function recalculateCollisionBoxes() : array{ + $result = [ + AxisAlignedBB::one()->trim(Facing::UP, 6 / 16) //the empty area around the bottom is currently considered solid + ]; + + foreach(Facing::HORIZONTAL as $f){ //add the frame parts around the bowl + $result[] = AxisAlignedBB::one()->trim($f, 14 / 16); + } + return $result; + } + + public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ + $this->facing = $face === Facing::DOWN ? Facing::DOWN : Facing::opposite($face); + + return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player); + } + + public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ + if($player !== null){ + $tile = $this->world->getTile($this); + if($tile instanceof TileHopper){ //TODO: find a way to have inventories open on click without this boilerplate in every block + $player->addWindow($tile->getInventory()); + } + return true; + } + return false; + } + + //TODO: redstone logic, sucking logic +} diff --git a/src/pocketmine/block/tile/Hopper.php b/src/pocketmine/block/tile/Hopper.php new file mode 100644 index 000000000..496975a79 --- /dev/null +++ b/src/pocketmine/block/tile/Hopper.php @@ -0,0 +1,84 @@ +inventory = new HopperInventory($this); + parent::__construct($world, $pos); + } + + public function readSaveData(CompoundTag $nbt) : void{ + $this->loadItems($nbt); + $this->loadName($nbt); + + $this->transferCooldown = $nbt->getInt(self::TAG_TRANSFER_COOLDOWN, 0); + } + + protected function writeSaveData(CompoundTag $nbt) : void{ + $this->saveItems($nbt); + $this->saveName($nbt); + + $nbt->setInt(self::TAG_TRANSFER_COOLDOWN, $this->transferCooldown); + } + + public function getDefaultName() : string{ + return "Hopper"; + } + + /** + * @return HopperInventory + */ + public function getInventory(){ + return $this->inventory; + } + + /** + * @return HopperInventory + */ + public function getRealInventory(){ + return $this->inventory; + } + + public function onUpdate() : bool{ + return false; //TODO + } +} diff --git a/src/pocketmine/block/tile/TileFactory.php b/src/pocketmine/block/tile/TileFactory.php index a6c5217aa..e804dbf0d 100644 --- a/src/pocketmine/block/tile/TileFactory.php +++ b/src/pocketmine/block/tile/TileFactory.php @@ -55,6 +55,7 @@ final class TileFactory{ self::register(EnderChest::class, ["EnderChest", "minecraft:ender_chest"]); self::register(FlowerPot::class, ["FlowerPot", "minecraft:flower_pot"]); self::register(Furnace::class, ["Furnace", "minecraft:furnace"]); + self::register(Hopper::class, ["Hopper", "minecraft:hopper"]); self::register(ItemFrame::class, ["ItemFrame"]); //this is an entity in PC self::register(MonsterSpawner::class, ["MobSpawner", "minecraft:mob_spawner"]); self::register(Note::class, ["Music", "minecraft:noteblock"]); @@ -76,7 +77,6 @@ final class TileFactory{ //TODO: Dropper //TODO: EndGateway //TODO: EndPortal - //TODO: Hopper //TODO: JigsawBlock //TODO: Jukebox //TODO: Lectern diff --git a/src/pocketmine/inventory/HopperInventory.php b/src/pocketmine/inventory/HopperInventory.php new file mode 100644 index 000000000..728453c9c --- /dev/null +++ b/src/pocketmine/inventory/HopperInventory.php @@ -0,0 +1,38 @@ +