### Create Recursive/Nested Menus Source: https://context7.com/muqsit/invmenu/llms.txt This example shows how to build multi-level menu systems where interacting with items in one menu can open another. It includes navigation between main and sub-menus using 'Back' buttons. ```php setName("Main Menu"); // Create sub menus $shopMenu = InvMenu::create(InvMenu::TYPE_DOUBLE_CHEST); $shopMenu->setName("Shop"); $settingsMenu = InvMenu::create(InvMenu::TYPE_HOPPER); $settingsMenu->setName("Settings"); // Setup navigation $mainMenu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) use ($shopMenu, $settingsMenu): void { $slot = $transaction->getAction()->getSlot(); $player = $transaction->getPlayer(); match ($slot) { 11 => $shopMenu->send($player), 15 => $settingsMenu->send($player), default => null }; })); // Back navigation for sub menus $backToMain = InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) use ($mainMenu): void { if ($transaction->getAction()->getSlot() === 0) { $mainMenu->send($transaction->getPlayer()); } }); $shopMenu->setListener($backToMain); $settingsMenu->setListener($backToMain); // Add navigation items $mainMenu->getInventory()->setItem(11, VanillaItems::EMERALD()->setCustomName("Shop")); $mainMenu->getInventory()->setItem(15, VanillaItems::REDSTONE()->setCustomName("Settings")); $backItem = VanillaItems::ARROW()->setCustomName("Back to Main Menu"); $shopMenu->getInventory()->setItem(0, $backItem); $settingsMenu->getInventory()->setItem(0, $backItem); $mainMenu->send($player); ``` -------------------------------- ### Clone InvMenu from Source Source: https://github.com/muqsit/invmenu/wiki/Installation Use this git command to clone the InvMenu repository into your virions folder when installing from source. ```git git clone git@github.com:Muqsit/InvMenu.git virions/InvMenu ``` -------------------------------- ### Directory Structure Source: https://github.com/muqsit/invmenu/wiki/Installation This shows the expected folder structure after installing the DEVirion plugin. ```text pmmp_folder |-- plugins | `-- devirion.phar |-- virions ``` -------------------------------- ### Create a Chest Inventory Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Create a virtual chest inventory and get its associated PocketMine Inventory object. ```php $menu = InvMenu::create(InvMenu::TYPE_CHEST); $inventory = $menu->getInventory(); ``` -------------------------------- ### Poggit CI Manifest for InvMenu Virion Source: https://github.com/muqsit/invmenu/wiki/Using-InvMenu-in-a-plugin Example of how to declare the InvMenu virion in your .poggit.yml file for automatic injection during Poggit CI builds. Specify the library path, branch, and version. ```yaml --- # Poggit-CI Manifest. Open the CI at https://poggit.pmmp.io/ci/Muqsit/PlayerVaults branches: - master projects: PlayerVaults: path: "" libs: - src: muqsit/InvMenu/InvMenu branch: "4.0" version: ^4.4.1 # refer to InvMenu's virion.yml to find the latest version ... ``` -------------------------------- ### Restrict Item Interaction in InvMenu Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Example of preventing specific items from being taken out of the inventory. ```php $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(); }); ``` -------------------------------- ### Create a Simple Hello World GUI Source: https://github.com/muqsit/invmenu/wiki/Examples---InvMenu-v4 Demonstrates a basic read-only menu that triggers a message when a specific item is clicked. ```php $menu = InvMenu::create(InvMenu::TYPE_CHEST); // use TYPE_HOPPER for hopper, TYPE_DOUBLE_CHEST for double chest $menu->setName("Click the diamond!"); $menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{ $player = $transaction->getPlayer(); $itemTakenOut = $transaction->getItemClicked(); // or $transaction->getOut(); if($itemTakenOut->getTypeId() === ItemTypeIds::DIAMOND){ $player->removeCurrentWindow(); $player->sendMessage("Hello, world!"); } })); $menu->getInventory()->addItem(VanillaItems::DIAMOND()); /** @var Player $player */ $menu->send($player); ``` -------------------------------- ### Implement a Server-Selector GUI Source: https://github.com/muqsit/invmenu/wiki/Examples---InvMenu-v4 Uses NamedTags on items to store server connection data, allowing players to transfer servers upon clicking. ```php $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setName("Server Selector"); $menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{ $player = $transaction->getPlayer(); $itemClicked = $transaction->getItemClicked(); $server_tag = $itemClicked->getNamedTag()->getCompoundTag("server"); if($server_tag === null){ return; } $ip = $server_tag->getString("address"); $port = $server_tag->getInt("port"); $player->transfer($ip, $port); })); $item = VanillaItems::APPLE(); $item->getNamedTag()->setTag("server", CompoundTag::create() ->setString("ip", "play.serverip.com") ->setInt("port", 19132) ); $inventory = $menu->getInventory(); $inventory->addItem($item); /** @var Player $player */ $menu->send($player); ``` -------------------------------- ### Directory Structure for Running from Source Source: https://github.com/muqsit/invmenu/wiki/Using-InvMenu-in-a-plugin Shows the file structure for running InvMenu from source in a development environment, placing the source folder within the virions directory alongside DEVirion. ```text pmmp_folder |-- plugins | `-- devirion.phar |-- virions | |-- InvMenu-master | |-- src | `-- virion.yml ``` -------------------------------- ### Create Server Selector GUI with Custom NBT Data Source: https://context7.com/muqsit/invmenu/llms.txt This snippet demonstrates how to create a server selector GUI by storing server connection details (IP, port, name) in custom NBT tags within item data. Clicking an item transfers the player to the specified server. ```php setName("Server Selector"); $menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction): void { $player = $transaction->getPlayer(); $itemClicked = $transaction->getItemClicked(); $serverTag = $itemClicked->getNamedTag()->getCompoundTag("server"); if ($serverTag === null) { return; // Clicked item has no server data } $ip = $serverTag->getString("address"); $port = $serverTag->getInt("port"); $serverName = $serverTag->getString("name", "Unknown Server"); $player->sendMessage("Transferring to {$serverName}..."); $player->transfer($ip, $port); })); // Create server items with embedded connection data $servers = [ ["name" => "Survival", "ip" => "survival.example.com", "port" => 19132, "slot" => 11], ["name" => "SkyBlock", "ip" => "skyblock.example.com", "port" => 19132, "slot" => 13], ["name" => "Creative", "ip" => "creative.example.com", "port" => 19132, "slot" => 15], ]; foreach ($servers as $serverData) { $item = VanillaItems::ENDER_PEARL(); $item->setCustomName($serverData["name"]); $item->getNamedTag()->setTag("server", CompoundTag::create() ->setString("address", $serverData["ip"]) ->setInt("port", $serverData["port"]) ->setString("name", $serverData["name"]) ); $menu->getInventory()->setItem($serverData["slot"], $item); } $menu->send($player); ``` -------------------------------- ### Create a Chest InvMenu Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Create a standard chest inventory menu using InvMenu::create() with the predefined TYPE_CHEST identifier. ```php $menu = InvMenu::create(InvMenu::TYPE_CHEST); ``` -------------------------------- ### Directory Structure for Development Environment Source: https://github.com/muqsit/invmenu/wiki/Using-InvMenu-in-a-plugin Illustrates the expected file structure when running InvMenu from a PHAR in a development environment with the DEVirion plugin. ```text pmmp_folder |-- plugins | `-- devirion.phar |-- virions | `-- InvMenu.phar ``` -------------------------------- ### Create InvMenu Instances Source: https://context7.com/muqsit/invmenu/llms.txt Use InvMenu::create() with pre-registered types like TYPE_CHEST (27 slots), TYPE_DOUBLE_CHEST (54 slots), or TYPE_HOPPER (5 slots). Access the inventory to add or set items. ```php getInventory(); $inventory->setContents([ VanillaItems::DIAMOND_SWORD(), VanillaItems::DIAMOND_PICKAXE(), VanillaItems::DIAMOND_AXE() ]); $inventory->setItem(13, VanillaItems::GOLD_INGOT()->setCount(64)); $inventory->addItem(VanillaItems::EMERALD()); ``` -------------------------------- ### Verify Menu Opening Success Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Use the callback parameter in the send method to verify if the menu was successfully opened by the player. ```php $menu->send($player, callback: function(bool $success) : void{ if( $success){ // player is viewing the menu } }); ``` -------------------------------- ### Create Recursive Chest Menus Source: https://github.com/muqsit/invmenu/wiki/Examples---InvMenu-v4 Sets up two chest menus that can navigate between each other when an item is clicked. Ensure the player object is available. ```php $menu1 = InvMenu::create(InvMenu::TYPE_CHEST); $menu1->setName("Menu 1"); $menu2 = InvMenu::create(InvMenu::TYPE_CHEST); $menu2->setName("Menu 2"); $menu1->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) use($menu2) : void{ $menu2->send($transaction->getPlayer()); })); $menu2->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) use($menu1) : void{ $menu1->send($transaction->getPlayer()); })); $menu1->getInventory()->addItem(VanillaItems::APPLE()); $menu2->getInventory()->addItem(VanillaItems::STEAK()); /** @var Player $player */ $menu1->send($player); ``` -------------------------------- ### Create a custom menu instance Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Instantiates a menu using a previously registered custom type identifier. ```php $menu = InvMenu::create(self::TYPE_DISPENSER); ``` -------------------------------- ### Implement Basic InvMenu Transaction Listener Source: https://github.com/muqsit/invmenu/blob/pm5/README.md A standard listener implementation accessing transaction details. ```php $menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ $player = $transaction->getPlayer(); $itemClicked = $transaction->getItemClicked(); $itemClickedWith = $transaction->getItemClickedWith(); $action = $transaction->getAction(); $txn = $transaction->getTransaction(); return $transaction->continue(); }); ``` -------------------------------- ### Send Menu with Custom Name (Method B) Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Send the menu to a player with a custom name specified at the time of sending. ```php $menu->send($player, "Greetings, " . $player->getName()); // method B ``` -------------------------------- ### Send an InvMenu to a player Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Use the send method to display an InvMenu instance to a player. Multiple players can view the same instance simultaneously. ```php $menu->send($player); ``` ```php $menu->send($player1); $menu->send($player2); ``` -------------------------------- ### Registering Custom InvMenu Types Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.3-Changelog-and-Migration-Notes Compares the legacy registration method with the new v4.3.0 builder pattern approach. ```php // InvMenu <= v4.2.x $type = new SingleBlockMenuMetadata( self::TYPE_DISPENSER, // identifier 9, // number of slots WindowTypes::DISPENSER, // mcpe window type id BlockFactory::get(Block::DISPENSER), // Block "Dispenser" // block entity identifier ); InvMenuHandler::registerMenuType($type); // InvMenu v4.3.0 InvMenuHandler::getTypeRegistry()->register(self::TYPE_DISPENSER, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED() ->setBlock(BlockFactory::getInstance()->get(BlockLegacyIds::DISPENSER, 0)) ->setBlockActorId("Dispenser") ->setSize(9) ->setNetworkWindowType(WindowTypes::DISPENSER) ->build()); ``` -------------------------------- ### Handle Form Transitions in InvMenu Source: https://github.com/muqsit/invmenu/wiki/Examples---InvMenu-v4 Use the then() method to ensure forms are displayed correctly after closing an inventory, as direct calls may fail due to client-side behavior. ```php $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{ $player = $transaction->getPlayer(); $player->removeCurrentWindow(); $transaction->then(function(Player $player) : void{ $player->sendForm(new class() implements Form{}); }); })); $menu->getInventory()->addItem(VanillaItems::APPLE()); $menu->send($player); // for non-readonly menus $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ $player = $transaction->getPlayer(); $player->removeCurrentWindow(); return $transaction->discard()->then(function(Player $player) : void{ $player->sendForm(new class() implements Form{}); }); }); $menu->getInventory()->addItem(VanillaItems::APPLE()); $menu->send($player); ``` -------------------------------- ### Implement Inventory Close Listener Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Registers a callback to execute when a player closes the menu. ```php $menu->setInventoryCloseListener(function(Player $player, Inventory $inventory) : void{ $player->sendMessage("You are no longer viewing the menu."); }); ``` -------------------------------- ### Sharing Menus Between Players Source: https://context7.com/muqsit/invmenu/llms.txt Send a single InvMenu instance to multiple players to allow synchronized viewing and interaction. Use listeners to track transactions across all participants. ```php setName("Community Trading Post"); // Optional: Add transaction logging $tradingPost->setListener(function(InvMenuTransaction $transaction): InvMenuTransactionResult { $player = $transaction->getPlayer(); $itemOut = $transaction->getItemClicked(); $itemIn = $transaction->getItemClickedWith(); if (!$itemOut->isNull()) { // Log: player took an item $player->getServer()->getLogger()->info( "{$player->getName()} took {$itemOut->getName()} from trading post" ); } if (!$itemIn->isNull()) { // Log: player added an item $player->getServer()->getLogger()->info( "{$player->getName()} added {$itemIn->getName()} to trading post" ); } return $transaction->continue(); }); // Send to multiple players - they all see the same inventory /** @var Player[] $players */ foreach ($players as $player) { $tradingPost->send($player, "Trading Post - " . count($players) . " viewers"); } ``` -------------------------------- ### Set InvMenu Transaction Listener Source: https://context7.com/muqsit/invmenu/llms.txt Implement a listener to monitor and control item movements within the menu. Return continue() to allow actions or discard() to cancel them. ```php setListener(function(InvMenuTransaction $transaction): InvMenuTransactionResult { $player = $transaction->getPlayer(); $itemClicked = $transaction->getItemClicked(); // Item being taken out $itemClickedWith = $transaction->getItemClickedWith(); // Item being placed in $action = $transaction->getAction(); // SlotChangeAction with slot info $slot = $action->getSlot(); // Prevent taking diamonds out of the menu if ($itemClicked->getTypeId() === ItemTypeIds::DIAMOND) { $player->sendMessage("You cannot take diamonds from this menu!"); return $transaction->discard(); } // Prevent placing items in slot 0 if ($slot === 0 && !$itemClickedWith->isNull()) { $player->sendMessage("Slot 0 is reserved!"); return $transaction->discard(); } return $transaction->continue(); }); ``` -------------------------------- ### Execute Post-Transaction Tasks Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Use then() to perform actions like sending forms after closing the menu. ```php $menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ $transaction->getPlayer()->removeCurrentWindow(); return $transaction->discard()->then(function(Player $player) : void{ $player->sendForm(new Form()); }); }); // 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(new Form()); }); })); ``` -------------------------------- ### Setting an Inventory Close Listener Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation This snippet demonstrates how to attach a closure to an InvMenu instance that will be executed when the player closes the inventory. ```APIDOC ## Setting an Inventory Close Listener ### Description Attaches a closure to be executed when the associated inventory is closed by the player. ### Method `InvMenu::setInventoryCloseListener(Closure $listener = null): void` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```php $menu->setInventoryCloseListener(function(Player $player, Inventory $inventory) : void{ echo $player->getName(), " closed the inventory!"; }); ``` ### Response None. This method does not return a value. ``` -------------------------------- ### Handle Asynchronous Menu Sending Source: https://github.com/muqsit/invmenu/wiki/Examples---InvMenu-v4 Pass a closure to the send method to verify if the inventory was successfully sent to the player. ```php /** * @var InvMenu $menu * @var Player $player * @var string|null $name */ $menu->send($player, $name, function(bool $success) : void{ if($success){ // menu sent successfully }else{ // menu failed to send } }); ``` -------------------------------- ### Create a Read-Only Menu in PHP Source: https://context7.com/muqsit/invmenu/llms.txt Use InvMenu::readonly() to prevent players from modifying inventory contents. This is ideal for shop displays or informational GUIs. ```php setName("Click the diamond!"); // Simple readonly - no items can be moved $menu->setListener(InvMenu::readonly()); // Readonly with click handler $menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction): void { $player = $transaction->getPlayer(); $itemClicked = $transaction->getItemClicked(); if ($itemClicked->getTypeId() === ItemTypeIds::DIAMOND) { $player->removeCurrentWindow(); $player->sendMessage("You clicked the diamond! Here's your reward."); $player->getInventory()->addItem(VanillaItems::DIAMOND()); } elseif ($itemClicked->getTypeId() === ItemTypeIds::EMERALD) { $player->sendMessage("You clicked an emerald!"); } })); $menu->getInventory()->setItem(13, VanillaItems::DIAMOND()->setCustomName("Click Me!")); $menu->getInventory()->setItem(11, VanillaItems::EMERALD()); $menu->getInventory()->setItem(15, VanillaItems::EMERALD()); $menu->send($player); ``` -------------------------------- ### Initialize InvMenuHandler Source: https://context7.com/muqsit/invmenu/llms.txt Register the InvMenuHandler in your plugin's onEnable method. This should only be done once across all plugins. ```php getLogger()->info("InvMenu is ready to use!"); } } ``` -------------------------------- ### Set Custom Menu Name (Method A) Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Set a global custom name for the inventory menu. ```php $menu->setName("Custom Name"); // method A ``` -------------------------------- ### Send Menu to Player Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Send the created virtual inventory menu to a specific player. ```php /** @var Player $player */ $menu->send($player); ``` -------------------------------- ### Set Inventory Contents Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Set the contents of the virtual inventory using PocketMine's Inventory interface methods. ```php $menu->getInventory()->setContents([ VanillaItems::DIAMOND_SWORD(), VanillaItems::DIAMOND_PICKAXE() ]); $menu->getInventory()->addItem(VanillaItems::DIAMOND_AXE()); $menu->getInventory()->setItem(3, VanillaItems::GOLD_INGOT()); ``` -------------------------------- ### Disposing an InvMenu Instance Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation This snippet shows the recommended way to dispose of an InvMenu instance to prevent potential memory leaks caused by circular references. ```APIDOC ## Disposing an InvMenu Instance ### Description Properly disposes of an InvMenu instance by clearing its listeners to prevent circular references and potential memory leaks. ### Method `InvMenu::setListener(Closure $listener = null): void` and `InvMenu::setInventoryCloseListener(Closure $listener = null): void` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```php // Dispose an InvMenu $menu->setListener(InvMenu::readonly() /* or null */); $menu->setInventoryCloseListener(null); ``` ### Response None. This method does not return a value. ``` -------------------------------- ### Injecting Virion into Plugin PHAR Source: https://github.com/muqsit/invmenu/wiki/Using-InvMenu-in-a-plugin Command to inject the InvMenu virion into your plugin's PHAR file for production deployment. Ensure you have the correct paths to the InvMenu.phar and your plugin's PHAR. ```bash bin/php7/bin/php path/to/InvMenu.phar path/to/yourplugin.phar ``` -------------------------------- ### Set InvMenu Inventory Close Listener Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Register a closure to be executed when a player closes the inventory. ```php $menu->setInventoryCloseListener(function(Player $player, Inventory $inventory) : void{ echo $player->getName(), " closed the inventory!"; }); ``` -------------------------------- ### Configure Read-only InvMenu Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Methods to prevent menu editing using listeners or the readonly shorthand. ```php $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 })); ``` -------------------------------- ### Migrate InvMenu::setListener() signature from v3 to v4 Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-Changelog-and-Migration-Notes The listener signature in v4 is simplified to accept a single InvMenuTransaction object. The return type changes from bool to InvMenuTransactionResult. ```php // InvMenu v3.0 $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setListener(function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action, InventoryTransaction $invTransaction) : bool{ if($itemClicked->getId() === ItemIds::APPLE){ return true; // allow transaction to process } return false; // cancel transaction }); // InvMenu v4.0 $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ $player = $transaction->getPlayer(); $itemClicked = $transaction->getItemClicked(); $itemClickedWith = $transaction->getItemClickedWith(); $action = $transaction->getAction(); $invTransaction = $transaction->getInventoryTransaction(); if($itemClicked->getId() === ItemIds::APPLE){ return $transaction->continue(); } return $transaction->discard(); }); ``` -------------------------------- ### Define InvMenu Transaction Listener Signature Source: https://github.com/muqsit/invmenu/blob/pm5/README.md The required closure signature for handling inventory transactions. ```php /** * @param InvMenuTransaction $transaction * * Return $transaction->continue() to continue the transaction. * Return $transaction->discard() to cancel the transaction. * @return InvMenuTransactionResult */ Closure(InvMenuTransaction $transaction) : InvMenuTransactionResult; ``` -------------------------------- ### Define InvMenu Close Listener Signature Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation The signature required for a closure used as an inventory close listener. ```php Closure(Player $player, Inventory $inventory) : void; ``` -------------------------------- ### Use readonly mode for InvMenu Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation The readonly helper provides a quick way to discard all transactions, with an optional callback for post-transaction logic. ```php $menu->setListener(InvMenu::readonly()); // disallow modifying the inventory ``` ```php $menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{ // do anything })); ``` -------------------------------- ### Create Trash Can Inventory Source: https://github.com/muqsit/invmenu/wiki/Examples---InvMenu-v4 Creates a chest inventory that disposes of all items within it when the inventory is closed. The player receives a message indicating the number of disposed items. Ensure the player and inventory objects are available. ```php $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setName("Trash Can - Place Trash Here!"); $menu->setInventoryCloseListener(function(Player $player, Inventory $inventory) : void{ $items = 0; foreach($inventory->getContents() as $item){ $items += $item->getCount(); } $inventory->clearAll(); $player->sendMessage("Disposed {" . $items . "} item(s)!"); }); /** @var Player $player */ $menu->send($player); ``` -------------------------------- ### Handle transactions with then() Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-Changelog-and-Migration-Notes Use then() to trigger actions after the event and network stacks have cleared, such as sending forms. Note that the callback will not execute if the player disconnects before confirmation. ```php $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ if($transaction->getItemClicked()->getId() === ItemIds::APPLE){ return $transaction->continue()->then(function(Player $player) : void{ $player->sendForm(new AppleForm()); }); } return $transaction->discard()->then(function(Player $player) : void{ $player->sendForm(new FallbackForm()); })); }); ``` -------------------------------- ### Register a custom InvMenuType Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Registers a new menu type using InvMenuTypeBuilders. Requires defining the block, size, block actor ID, and network window type. ```php public const TYPE_DISPENSER = "myplugin:dispenser"; protected function onEnable() : void{ InvMenuHandler::getTypeRegistry()->register(self::TYPE_DISPENSER, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED() ->setBlock(ExtraVanillaBlocks::DISPENSER()) ->setSize(9) ->setBlockActorId("Dispenser") ->setNetworkWindowType(WindowTypes::DISPENSER) ->build()); } ``` -------------------------------- ### Execute Post-Transaction Callbacks with then() Source: https://context7.com/muqsit/invmenu/llms.txt The then() method allows code execution after a transaction completes, which is necessary for operations like sending forms that cannot be opened while an inventory is active. ```php setName("Confirmation Menu"); $menu->getInventory()->setItem(13, VanillaItems::PAPER()->setCustomName("Click to confirm")); // Using standard listener $menu->setListener(function(InvMenuTransaction $transaction): InvMenuTransactionResult { $player = $transaction->getPlayer(); $player->removeCurrentWindow(); // Close the menu first return $transaction->discard()->then(function(Player $player): void { // This runs after the inventory is closed $player->sendMessage("Sending confirmation form..."); // $player->sendForm($confirmationForm); }); }); // Using readonly listener $readonlyMenu = InvMenu::create(InvMenu::TYPE_CHEST); $readonlyMenu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction): void { $player = $transaction->getPlayer(); $player->removeCurrentWindow(); $transaction->then(function(Player $player): void { $player->sendMessage("Menu closed, form would be sent here!"); // $player->sendForm($myForm); }); })); ``` -------------------------------- ### Registering Custom InvMenu Types Source: https://context7.com/muqsit/invmenu/llms.txt Use InvMenuTypeBuilders to define custom inventory types like dispensers or barrels. Ensure the handler is registered before defining types. ```php register( self::TYPE_DISPENSER, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED() ->setBlock(VanillaBlocks::DISPENSER()) // Requires custom block registration ->setSize(9) ->setBlockActorId("Dispenser") ->setNetworkWindowType(WindowTypes::DISPENSER) ->build() ); // Register a barrel menu (27 slots, same as chest) InvMenuHandler::getTypeRegistry()->register( self::TYPE_BARREL, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED() ->setBlock(VanillaBlocks::BARREL()) ->setSize(27) ->setBlockActorId("Barrel") ->build() ); } public function openDispenserMenu(Player $player): void { $menu = InvMenu::create(self::TYPE_DISPENSER); $menu->setName("Custom Dispenser Menu"); $menu->send($player); } public function openBarrelMenu(Player $player): void { $menu = InvMenu::create(self::TYPE_BARREL); $menu->setName("Storage Barrel"); $menu->send($player); } } ``` -------------------------------- ### Handle asynchronous send results Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Pass a callback to the send method to verify if the inventory was successfully sent to the player. ```php $menu->send($player, $name, function(bool $success) : void{ if($success){ // successfully sent to player }else{ // failed to send to player } }); ``` -------------------------------- ### Define an InvMenu handler signature Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation The handler must be a Closure that accepts an InvMenuTransaction and returns an InvMenuTransactionResult. ```php Closure(InvMenuTransaction $transaction) : InvMenuTransactionResult; ``` -------------------------------- ### Set an Inventory Close Listener Source: https://context7.com/muqsit/invmenu/llms.txt The close listener triggers when a player closes the menu, allowing for cleanup operations like clearing items from a trash can inventory. ```php setName("Trash Can - Place Items Here"); $trashCan->setInventoryCloseListener(function(Player $player, Inventory $inventory): void { $itemCount = 0; foreach ($inventory->getContents() as $item) { $itemCount += $item->getCount(); } $inventory->clearAll(); // Delete all items if ($itemCount > 0) { $player->sendMessage("Disposed {$itemCount} item(s)!"); } else { $player->sendMessage("No items were disposed."); } }); $trashCan->send($player); ``` -------------------------------- ### Register Custom InvMenu Type (Dispenser) Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Register a custom InvMenu type for a dispenser. This requires defining a unique identifier, block type, size, block actor ID, and network window type. ```php // class MyPluginMainClass extends PluginBase { public const TYPE_DISPENSER = "my_dispenser_menu"; protected function onEnable() : void{ if(!InvMenuHandler::isRegistered()){ InvMenuHandler::register($this); } InvMenuHandler::getTypeRegistry()->register(self::TYPE_DISPENSER /* identifier */, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED() ->setBlock(VanillaBlocks::DISPENSER()) // block type ->setSize(9) // number of slots ->setBlockActorId("Dispenser") // MCPE tile entity identifier ->setNetworkWindowType(WindowTypes::DISPENSER) // MCPE window type id ->build()); } // } ``` -------------------------------- ### Dispose InvMenu Instance Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Clear listeners to prevent circular references and memory leaks when the menu is no longer needed. ```php // dispose an InvMenu $menu->setListener(InvMenu::readonly() /* or null */); $menu->setInventoryCloseListener(null); ``` -------------------------------- ### Close Inventory on Click Source: https://github.com/muqsit/invmenu/wiki/Examples---InvMenu-v4 Closes the menu immediately when a player interacts with an item. ```php $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setName("Don't steal!"); $menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{ if(!$transaction->getOut()->isNull()){ $transaction->getPlayer()->removeCurrentWindow(); } })); $menu->getInventory()->addItem(VanillaItems::APPLE()); /** @var Player $player */ $menu->send($player); ``` -------------------------------- ### Send an InvMenu with a custom title Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Provide a custom title string to the send method to override the default inventory name for a specific player. ```php $menu->send($player, "Hello " . $player->getName()); ``` -------------------------------- ### Identify send request conflicts Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Sending a new InvMenu to a player will cancel any previously queued send request for that same player. ```php $menu1->send($player); $menu2->send($player); // $menu1 will fail to be sent to player ``` -------------------------------- ### Register InvMenuHandler Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Register InvMenuHandler during plugin enable to allow InvMenu creation. Ensure it's only registered once. ```php final class MyPlugin extends PluginBase{ protected function onEnable() : void{ + if(!InvMenuHandler::isRegistered()){ + InvMenuHandler::register($this); + } } } ``` -------------------------------- ### Define Inventory Close Listener Signature Source: https://github.com/muqsit/invmenu/blob/pm5/README.md The required closure signature for handling inventory close events. ```php /** * @param Player $player the player that closed the menu * @param Inventory $inventory the inventory of the menu */ Closure(Player $player, Inventory $inventory) : void; ``` -------------------------------- ### Migrate InvMenu::readonly() usage from v3 to v4 (with listener) Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-Changelog-and-Migration-Notes In v4, InvMenu::readonly() can accept a listener closure. This combines the readonly behavior with custom transaction handling. ```php // InvMenu v3.0 $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->readonly(); $menu->setListener(function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action, InventoryTransaction $invTransaction) : void{ }); // InvMenu v4.0 $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{ $player = $transaction->getPlayer(); $itemClicked = $transaction->getItemClicked(); $itemClickedWith = $transaction->getItemClickedWith(); $action = $transaction->getAction(); $invTransaction = $transaction->getInventoryTransaction(); })); ``` -------------------------------- ### Handle readonly transactions with then() Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-Changelog-and-Migration-Notes Directly trigger then() within a readonly listener for deterministic transaction handling. ```php $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{ if($transaction->getItemClicked()->getId() === ItemIds::APPLE){ $transaction->then(function(Player $player) : void{ $player->sendForm(new AppleForm()); }); return; } $transaction->then(function(Player $player) : void{ $player->sendForm(new FallbackForm()); }); })); ``` -------------------------------- ### Migrate InvMenu::createSessionized() from v3 to v4 Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-Changelog-and-Migration-Notes In v4, SessionizedInvMenu is removed. Use separate InvMenu instances for each player instead of a single sessionized menu. ```php // InvMenu v3.0 $menu = InvMenu::createSessionized(InvMenu::TYPE_CHEST); $menu->setName($name); $menu->setListener($listener); $menu->send($player1); $menu->send($player2); // InvMenu v4.0 $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setName($name); $menu->setListener($listener); $menu->send($player1); $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setName($name); $menu->setListener($listener); $menu->send($player2); ``` -------------------------------- ### Execute code after transaction completion Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Use the then method on a transaction result to perform actions like opening a form after the transaction is processed. ```php $menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ return $transaction->discard()->then(function(Player $player) : void{ $player->sendForm($someForm); }); }); ``` -------------------------------- ### Register InvMenuHandler Source: https://github.com/muqsit/invmenu/blob/pm5/README.md Register InvMenuHandler before using InvMenu. This should be done in your plugin's onEnable method. ```php protected function onEnable() : void{ if(!InvMenuHandler::isRegistered()){ InvMenuHandler::register($this); } } ``` -------------------------------- ### Conditionally allow inventory transactions Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Use discard or continue based on the transaction details to selectively restrict item movement. ```php $menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ if($transaction->getOut()->getId() === ItemIds::APPLE){ return $transaction->discard(); // revert the inventory transaction }else{ return $transaction->continue(); // allow the inventory transaction } }); ``` ```php $menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ if($transaction->getIn()->isNull()){ return $transaction->continue(); // allow the inventory transaction }else{ return $transaction->discard(); // revert the inventory transaction } }); ``` -------------------------------- ### Discard all inventory transactions Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Use discard to prevent players from modifying the inventory contents. ```php $menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ return $transaction->discard(); // revert the inventory transaction }); ``` -------------------------------- ### Migrate InvMenu::readonly() usage from v3 to v4 (without listener) Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-Changelog-and-Migration-Notes In v4, InvMenu::readonly() is a static method that returns a closure. It's now used with setListener() to achieve the same readonly behavior as v3. ```php // InvMenu v3.0 $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->readonly(); // InvMenu v4.0 $menu = InvMenu::create(InvMenu::TYPE_CHEST); $menu->setListener(InvMenu::readonly()); ``` -------------------------------- ### Set Custom InvMenu Name Source: https://github.com/muqsit/invmenu/wiki/InvMenu-v4.0-API-Documentation Set a custom title for an InvMenu instance using the setName() method. This overrides the default inventory title. ```php $menu->setName("Custom Title"); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.