Skip to content

Instantly share code, notes, and snippets.

@Muqsit
Created June 28, 2025 16:06
Show Gist options
  • Save Muqsit/8884e0f75b317c332a56e01740bbfe98 to your computer and use it in GitHub Desktop.
Save Muqsit/8884e0f75b317c332a56e01740bbfe98 to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
/**
* @name DispenserInvMenuPlugin
* @main muqsit\dispenserinvmenuplugin\Loader
* @api 5.0.0
* @version 0.0.1
*/
namespace muqsit\dispenserinvmenuplugin{
use muqsit\invmenu\InvMenu;
use muqsit\invmenu\InvMenuHandler;
use muqsit\invmenu\type\util\InvMenuTypeBuilders;
use pocketmine\block\Block;
use pocketmine\block\BlockBreakInfo;
use pocketmine\block\BlockIdentifier;
use pocketmine\block\BlockTypeIds;
use pocketmine\block\BlockTypeInfo;
use pocketmine\block\Opaque;
use pocketmine\block\RuntimeBlockStateRegistry;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\PluginCommand;
use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
use pocketmine\data\bedrock\block\BlockTypeNames as Ids;
use pocketmine\data\bedrock\block\convert\BlockStateReader as Reader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter as Writer;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\Listener;
use pocketmine\item\VanillaItems;
use pocketmine\network\mcpe\protocol\types\inventory\WindowTypes;
use pocketmine\permission\DefaultPermissions;
use pocketmine\player\Player;
use pocketmine\plugin\PluginBase;
use pocketmine\utils\CloningRegistryTrait;
use pocketmine\world\format\io\GlobalBlockStateHandlers;
final class Dispenser extends Opaque{
use AnyFacingTrait { describeBlockOnlyState as facingDescribeBlockOnlyState; }
use PoweredByRedstoneTrait;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$this->facingDescribeBlockOnlyState($w);
$w->bool($this->powered);
}
}
/**
* @method static Dispenser DISPENSER()
*/
final class ExtraVanillaBlocks{
use CloningRegistryTrait;
private function __construct(){
//NOOP
}
protected static function register(string $name, Block $block) : void{
self::_registryRegister($name, $block);
}
/**
* @return Block[]
* @phpstan-return array<string, Block>
*/
public static function getAll() : array{
//phpstan doesn't support generic traits yet :(
/** @var Block[] $result */
$result = self::_registryGetAll();
return $result;
}
protected static function setup() : void{
$targetTypeId = BlockTypeIds::newId();
self::register("dispenser", new Dispenser(new BlockIdentifier($targetTypeId), "Dispenser", new BlockTypeInfo(BlockBreakInfo::instant())));
}
}
final class Loader extends PluginBase implements Listener{
public const TYPE_DISPENSER = "dispenserinvmenuplugin:dispenser";
protected function onEnable() : void{
if(!InvMenuHandler::isRegistered()){
InvMenuHandler::register($this);
}
$this->registerDispenserBlock();
InvMenuHandler::getTypeRegistry()->register(self::TYPE_DISPENSER, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED()
->setBlock(ExtraVanillaBlocks::DISPENSER())
->setSize(9)
->setBlockActorId("Dispenser")
->setNetworkWindowType(WindowTypes::DISPENSER)
->build());
$command = new PluginCommand("dispenser", $this, $this);
$command->setPermission(DefaultPermissions::ROOT_USER);
$this->getServer()->getCommandMap()->register($this->getName(), $command);
}
public function registerDispenserBlock() : void{
RuntimeBlockStateRegistry::getInstance()->register(ExtraVanillaBlocks::DISPENSER());
GlobalBlockStateHandlers::getDeserializer()->map(Ids::DISPENSER, function(Reader $in) : Block{
return ExtraVanillaBlocks::DISPENSER()
->setFacing($in->readFacingDirection())
->setPowered($in->readBool(StateNames::TRIGGERED_BIT));
});
GlobalBlockStateHandlers::getSerializer()->map(ExtraVanillaBlocks::DISPENSER(), function(Dispenser $block) : Writer{
return Writer::create(Ids::DISPENSER)
->writeBool(StateNames::TRIGGERED_BIT, $block->isPowered())
->writeFacingDirection($block->getFacing());
});
}
public function onCommand(CommandSender $sender, Command $command, string $label, array $args) : bool{
if(!($sender instanceof Player)){
$sender->sendMessage("This command can only be used in-game.");
return true;
}
$contents = [
VanillaItems::APPLE(), VanillaItems::CARROT(), VanillaItems::STONE_AXE(),
VanillaItems::GOLDEN_APPLE(), VanillaItems::GOLDEN_CARROT(), VanillaItems::GOLDEN_AXE(),
VanillaItems::FEATHER(), VanillaItems::ARROW(), VanillaItems::BONE()
];
$menu = InvMenu::create(self::TYPE_DISPENSER);
$menu->getInventory()->setContents($contents);
$menu->send($sender);
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment