Create and manage virtual inventories in PocketMine-MP.
Download the compiled .phar file from Poggit CI and place it in your virions/ folder.
Read installation and using in a plugin
for a more elaborate guide on how to setup InvMenu library.
Note
You must register InvMenuHandler before you can use InvMenu.
// in class MyPlugin extends PluginBase:protectedfunctiononEnable() : void{
if(!InvMenuHandler::isRegistered()){
InvMenuHandler::register($this);
}
}Quick start, use InvMenu::create(InvMenu::TYPE_CHEST)->send($player); to display a virtual chest inventory to a player.
InvMenu::create($identifier) creates an InvMenu instance. $identifier may be an identifier of a registered InvMenuType object.
InvMenu comes with 3 pre-registered inventory types of different sizes:
InvMenu::TYPE_CHEST- a 27-slot normal chest inventoryInvMenu::TYPE_DOUBLE_CHEST- a 54-slot double chest inventoryInvMenu::TYPE_HOPPER- a 5-slot hopper inventory
$menu = InvMenu::create(InvMenu::TYPE_CHEST);
$inventory = $menu->getInventory();As $inventory implements PocketMine's Inventory interface, you get to access all the fancy PocketMine inventory methods.
$menu->getInventory()->setContents([
VanillaItems::DIAMOND_SWORD(),
VanillaItems::DIAMOND_PICKAXE()
]);
$menu->getInventory()->addItem(VanillaItems::DIAMOND_AXE());
$menu->getInventory()->setItem(3, VanillaItems::GOLD_INGOT());To send a menu to a player, use:
/** @var Player $player */$menu->send($player);Tip
One InvMenu can be sent to multiple players—even 2 players in different worlds, so everyone views and edits the same inventory as if it were one chest.
There are two ways to name an InvMenu. You can either specify a global name (see method A), or you can set a name at the time you send the menu (see method B).
$menu->setName("Custom Name"); // method A$menu->send($player, "Greetings, " . $player->getName()); // method BInvMenu::send() is not guaranteed to succeed. A failure may arise from plugins cancelling InventoryOpenEvent, a disconnected player, or the player refusing the request (e.g., because they are in pause menu).
Use the $callback parameter to verify whether a menu has been opened.
$menu->send($player, callback: function(bool$success) : void{
if($success){
// player is viewing the menu
}
});InvMenu comes with a listener whereby developers can write logic to monitor movement of items in and out of inventory, and thereby take action. A listener is a callback with the following signature:
/** * @param InvMenuTransaction $transaction * * Return $transaction->continue() to continue the transaction. * Return $transaction->discard() to cancel the transaction. * @return InvMenuTransactionResult */Closure(InvMenuTransaction $transaction) : InvMenuTransactionResult;InvMenuTransaction::getPlayer()returns thePlayerthat triggered the transaction.InvMenuTransaction::getItemClicked()returns theItemthe player clicked in the menu. You may also useInvMenuTransaction::getOut().InvMenuTransaction::getItemClickedWith()returns theItemthe player had in their hand when clicking an item. You may also useInvMenuTransaction::getIn().InvMenuTransaction::getAction()returnsSlotChangeAction- you can get the slot that the player clicked in the menu.InvMenuTransaction::getTransaction()returns the completeInventoryTransactionholding all the above information.
$menu->setListener(function(InvMenuTransaction$transaction) : InvMenuTransactionResult{
$player = $transaction->getPlayer();
$itemClicked = $transaction->getItemClicked();
$itemClickedWith = $transaction->getItemClickedWith();
$action = $transaction->getAction();
$txn = $transaction->getTransaction();
return$transaction->continue();
});The listener below does not allow players to take out apples from the menu:
$menu->setListener(function(InvMenuTransaction$transaction) : InvMenuTransactionResult{
if($transaction->getItemClicked()->getTypeId() === ItemTypeIds::APPLE){
$player->sendMessage("You cannot take apples out of that inventory.");
return$transaction->discard();
}
return$transaction->continue();
});There are two methods you can use to prevent players from editing the menu. Either create a listener that discard()s
the transaction, or use InvMenu::readonly().
$menu->setListener(function(InvMenuTransaction$transaction) : InvMenuTransactionResult{
return$transaction->discard();
});
$menu->setListener(InvMenu::readonly()); // equivalent shorthand of the above// you can also pass a callback in InvMenu::readonly()$menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction$transaction) : void{
// do something
}));Alternatively, you may choose to write your own InventoryTransactionEvent listener that works on transactions on
$menu->getInventory(). However, an InvMenu listener is enough to fulfil most tasks.
Few actions are not possible to invoke at the time a player is viewing an inventory, such as sending a form—a player
cannot view a form while viewing an inventory. Close the menu and utilize InvMenuTransactionResult::then() callback to
achieve this.
$menu->setListener(function(InvMenuTransaction$transaction) : InvMenuTransactionResult{
$transaction->getPlayer()->removeCurrentWindow();
return$transaction->discard()->then(function(Player$player) : void{
$player->sendForm(newForm());
});
});
// or if you are using InvMenu::readonly():$menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction$transaction) : void{
$transaction->getPlayer()->removeCurrentWindow();
$transaction->then(function(Player$player) : void{
$player->sendForm(newForm());
});
}));Register an inventory close callback to run whenever a player closes the menu. An inventory close callback takes the following signature:
/** * @param Player $player the player that closed the menu * @param Inventory $inventory the inventory of the menu */Closure(Player $player, Inventory $inventory) : void;$menu->setInventoryCloseListener(function(Player$player, Inventory$inventory) : void{
$player->sendMessage("You are no longer viewing the menu.");
});Inventory close listener is fired during both—server-initiated requests (i.e., $player->removeCurrentWindow()) and
when the player closes the inventory on their end.
Important
PocketMine does not register a dispenser block. As of PocketMine v5, the task of registering missing vanilla blocks is
excessively laborious and hence beyond the scope of this guide. pmmp/RegisterBlocksDemoPM5
has a nice guide on how to achieve this. Still overwhelmed? I wrote a drag-n-drop example plugin
that does all of it and registers a /dispenser command. With DevTools plugin installed, simply copy the code and
paste it in a new "DispenserInvMenuPlugin.php" file in your server's plugin folder.
InvMenu does not provide a 9-slot dispenser inventory. But you can still achieve this by registering a dispenser InvMenuType. You'll need to specify inventory size, block actor identifier (tile identifier), and the window type (network property) for the creation of the graphic (block) and inventory parts.
publicconstTYPE_DISPENSER = "myplugin:dispenser";
protectedfunctiononEnable() : void{
InvMenuHandler::getTypeRegistry()->register(self::TYPE_DISPENSER, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED()
->setBlock(ExtraVanillaBlocks::DISPENSER())
->setSize(9)
->setBlockActorId("Dispenser")
->setNetworkWindowType(WindowTypes::DISPENSER)
->build());
}Sweet! Now you can create a dispenser menu using:
$menu = InvMenu::create(self::TYPE_DISPENSER);Applications, examples, tutorials and featured projects using InvMenu can be found on the InvMenu Wiki.