├── .poggit.yml ├── README.md ├── src └── muqsit │ └── invmenuutils │ └── InvMenuListenerUtils.php └── virion.yml /.poggit.yml: -------------------------------------------------------------------------------- 1 | --- # Poggit-CI Manifest. Open the CI at https://poggit.pmmp.io/ci/Muqsit/InvMenuUtils 2 | build-by-default: true 3 | branches: 4 | - master 5 | projects: 6 | InvMenuUtils: 7 | path: "" 8 | model: virion 9 | type: library 10 | ... 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InvMenuUtils 2 | A utility virion for the [InvMenu](https://github.com/Muqsit/InvMenu) virion implementing some commonly used procedures. 3 | 4 | ## Assigning multiple listeners to one `InvMenu` 5 | Multiple listeners have different behaviour for readonly and non-readonly InvMenu instances. 6 | For non-readonly InvMenu instances, listeners are prioritised in the order they were passed to the `InvMenuListenerUtils::multiple()` method. 7 | A listener will not be executed if the previous listener cancelled the transaction (i.e returned false). 8 | ```php 9 | $menu = InvMenu::create(InvMenu::TYPE_CHEST); 10 | $menu->setListener(InvMenuListenerUtils::multiple( 11 | $menu, 12 | function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : bool{ 13 | echo "This listener is called first" . PHP_EOL; 14 | return true; 15 | }, 16 | function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : bool{ 17 | echo "This listener is called second." . PHP_EOL; 18 | return false; 19 | }, 20 | function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : bool{ 21 | // This listener is not called as the previous listener cancelled the transaction 22 | // by returning false. 23 | return true; 24 | } 25 | )); 26 | ``` 27 | For readonly InvMenu instances, all listeners will be executed as the transaction is anyway forcefully cancelled. 28 | ```php 29 | 30 | $menu = InvMenu::create(InvMenu::TYPE_CHEST); 31 | $menu->readonly(); 32 | $menu->setListener(InvMenuListenerUtils::multiple( 33 | $menu, 34 | function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : void{ 35 | echo "This listener is called first" . PHP_EOL; 36 | }, 37 | function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : void{ 38 | echo "This listener is called second." . PHP_EOL; 39 | }, 40 | function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : void{ 41 | echo "This listener is called third." . PHP_EOL; 42 | } 43 | )); 44 | ``` 45 | 46 | ## Assigning slot-specific listeners to an `InvMenu` 47 | Listen or handle specific slots, or handle each slot separately.
48 | Index your listeners to the slot you'd like the listener to handle/listen.
49 | TIP: Use index `-1` to "catch-all" (fallback). 50 | ```php 51 | $menu->setListener(InvMenuListenerUtils::slotSpecific($menu, [ 52 | 8 => function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : bool{ 53 | $player->sendMessage("You clicked slot #8"); 54 | return true; 55 | }, 56 | 16 => function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : bool{ 57 | $player->sendMessage("You clicked slot #16"); 58 | return true; 59 | }, 60 | -1 => function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : bool{ 61 | $player->sendMessage("Fallback: You clicked slot #" . $action->getSlot()); 62 | return true; 63 | } 64 | ])); 65 | ``` 66 | 67 | ## Blacklisting specific slots 68 | **NOTE:** This method is applicable ONLY to non-readonly InvMenu instances.
69 | Blacklisting an array of slots disallows players from modify those slots. 70 | ```php 71 | $menu = InvMenu::create(InvMenu::TYPE_CHEST); 72 | $menu->setListener(InvMenuListenerUtils::blacklistSlots([0, 4, 8])); 73 | ``` 74 | You can even use this in combination with `InvMenuListenerUtils::multiple()`. 75 | ```php 76 | $menu = InvMenu::create(InvMenu::TYPE_CHEST); 77 | $menu->setListener(InvMenuListenerUtils::multiple( 78 | $menu, 79 | InvMenuListenerUtils::blacklistSlots([0, 1, 2]), 80 | function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : bool{ 81 | $player->sendMessage("You didn't click any of these slots: 0, 1, 2"); 82 | return true; 83 | } 84 | )); 85 | ``` 86 | 87 | ## Whitelisting specific slots 88 | **NOTE:** This method is applicable ONLY to non-readonly InvMenu instances.
89 | Whitelisting an array of slots allows players to modify ONLY those slots. 90 | ```php 91 | $menu = InvMenu::create(InvMenu::TYPE_CHEST); 92 | $menu->setListener(InvMenuListenerUtils::whitelistSlots([0, 4, 8])); 93 | ``` 94 | Similar to `InvMenuListenerUtils::blacklistSlots()`, you can use this in combination with `InvMenuListenerUtils::multiple()`. 95 | ```php 96 | $menu = InvMenu::create(InvMenu::TYPE_CHEST); 97 | $menu->setListener(InvMenuListenerUtils::multiple( 98 | $menu, 99 | InvMenuListenerUtils::whitelistSlots([0, 1, 2]), 100 | function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : bool{ 101 | $player->sendMessage("You click one of these slots: 0, 1, 2"); 102 | return true; 103 | } 104 | )); 105 | ``` 106 | 107 | ## Filtering items with specific NBT tags 108 | **NOTE:** This method is applicable ONLY to non-readonly InvMenu instances.
109 | Filter items only with a specific NBT tag on them to allow players to take those items out of the inventory. 110 | ```php 111 | $menu->setListener(InvMenuListenerUtils::onlyItemsWithTag("CustomItem", StringTag::class)); 112 | ``` 113 | Filter items only without a specific NBT tag on them to allow players to take those items out of the inventory. 114 | ```php 115 | $menu->setListener(InvMenuListenerUtils::onlyItemsWithoutTag("Button", ByteTag::class)); 116 | ``` 117 | Similar to `InvMenuListenerUtils::whitelistSlots()` and `InvMenuListenerUtils::blacklistSlots()`, this can be used in combination with `InvMenuListenerUtils::multiple()`. 118 | ```php 119 | $menu->setListener(InvMenuListenerUtils::multiple( 120 | $menu, 121 | InvMenuListenerUtils::onlyItemsWithTag("Button", ByteTag::class), 122 | function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) : bool{ 123 | $player->sendMessage("You clicked a button!"); 124 | return false; 125 | } 126 | )); 127 | ``` 128 | -------------------------------------------------------------------------------- /src/muqsit/invmenuutils/InvMenuListenerUtils.php: -------------------------------------------------------------------------------- 1 | isReadonly() ? self::multipleReadonly(...$listeners) : self::multipleReadWrite(...$listeners); 39 | } 40 | 41 | public static function multipleReadonly(Closure ...$listeners) : Closure{ 42 | return static function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) use($listeners) : void{ 43 | foreach($listeners as $listener){ 44 | $listener($player, $itemClicked, $itemClickedWith, $action); 45 | } 46 | }; 47 | } 48 | 49 | public static function multipleReadWrite(Closure ...$listeners) : Closure{ 50 | return static function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) use($listeners) : bool{ 51 | foreach($listeners as $listener){ 52 | if(!$listener($player, $itemClicked, $itemClickedWith, $action)){ 53 | return false; 54 | } 55 | } 56 | return true; 57 | }; 58 | } 59 | 60 | /** 61 | * An array of listeners indexed by the slot they should listen to. 62 | * Use index -1 for a "catch-all". 63 | * 64 | * @param InvMenu $menu 65 | * @param array $listeners 66 | * @return Closure 67 | */ 68 | public static function slotSpecific(InvMenu $menu, array $listeners) : Closure{ 69 | return $menu->isReadonly() ? self::slotSpecificReadonly($listeners) : self::slotSpecificReadWrite($listeners); 70 | } 71 | 72 | public static function slotSpecificReadonly(array $listeners) : Closure{ 73 | return static function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) use($listeners) : void{ 74 | $listener = $listeners[$action->getSlot()] ?? $listeners[-1] ?? null; 75 | if($listener !== null){ 76 | $listener($player, $itemClicked, $itemClickedWith, $action); 77 | } 78 | }; 79 | } 80 | 81 | public static function slotSpecificReadWrite(array $listeners) : Closure{ 82 | return static function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) use($listeners) : bool{ 83 | $listener = $listeners[$action->getSlot()] ?? $listeners[-1] ?? null; 84 | return $listener === null || $listener($player, $itemClicked, $itemClickedWith, $action); 85 | }; 86 | } 87 | 88 | /** 89 | * @param int[] $slots 90 | * @return Closure 91 | */ 92 | public static function blacklistSlots(array $slots) : Closure{ 93 | $blacklist = new Set($slots); 94 | return static function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) use($blacklist) : bool{ 95 | return !$blacklist->contains($action->getSlot()); 96 | }; 97 | } 98 | 99 | /** 100 | * @param int[] $slots 101 | * @return Closure 102 | */ 103 | public static function whitelistSlots(array $slots) : Closure{ 104 | $whitelist = new Set($slots); 105 | return static function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) use($whitelist) : bool{ 106 | return $whitelist->contains($action->getSlot()); 107 | }; 108 | } 109 | 110 | /** 111 | * @param string $name 112 | * @param string $expectedClass 113 | * @return Closure 114 | */ 115 | public static function onlyItemsWithTag(string $name, string $expectedClass = NamedTag::class) : Closure{ 116 | return static function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) use($name, $expectedClass) : bool{ 117 | return $itemClicked->getNamedTag()->hasTag($name, $expectedClass); 118 | }; 119 | } 120 | 121 | /** 122 | * @param string $name 123 | * @param string $expectedClass 124 | * @return Closure 125 | */ 126 | public static function onlyItemsWithoutTag(string $name, string $expectedClass = NamedTag::class) : Closure{ 127 | return static function(Player $player, Item $itemClicked, Item $itemClickedWith, SlotChangeAction $action) use($name, $expectedClass) : bool{ 128 | return !$itemClicked->getNamedTag()->hasTag($name, $expectedClass); 129 | }; 130 | } 131 | } -------------------------------------------------------------------------------- /virion.yml: -------------------------------------------------------------------------------- 1 | name: InvMenuUtils 2 | antigen: muqsit\invmenuutils 3 | api: 3.11.2 4 | version: 0.0.1 5 | author: Muqsit 6 | --------------------------------------------------------------------------------