muqsit / invmenu
一个用于创建和管理虚拟库存的PocketMine-MP插件!
Requires
- pocketmine/pocketmine-mp: ^5.0.0
README
InvMenu 是一个简化创建和管理虚拟库存的PocketMine-MP插件!
安装
您可以在poggit上通过点击这里来获取编译后的.phar文件。
使用方法
InvMenu支持创建由任何类型的Inventory
组成的GUI。
注意:在开始创建InvMenu
实例之前,您必须在插件启用时注册InvMenuHandler
。
if(!InvMenuHandler::isRegistered()){ InvMenuHandler::register($this); }
创建InvMenu实例
InvMenu::create($identifier)
创建一个新的InvMenu实例。$identifier
必须是一个注册的InvMenuType
对象的标识符。InvMenu提供了3个预注册的InvMenuType
标识符:InvMenu::TYPE_CHEST
、InvMenu::TYPE_DOUBLE_CHEST
和InvMenu::TYPE_HOPPER
。
$menu = InvMenu::create(InvMenu::TYPE_CHEST);
要访问此菜单的库存,您可以
$inventory = $menu->getInventory();
$inventory
实现了pocketmine的Inventory
接口,因此您可以访问所有pocketmine库存方法。
$menu->getInventory()->setContents([ VanillaItems::DIAMOND_SWORD(), VanillaItems::DIAMOND_PICKAXE() ]); $menu->getInventory()->addItem(VanillaItems::DIAMOND_AXE()); $menu->getInventory()->setItem(3, VanillaItems::GOLD_INGOT());
要将菜单发送给玩家,请使用
/** @var Player $player */ $menu->send($player);
是的,就是这样。就这么简单。
为菜单指定自定义名称
要为菜单设置自定义名称,请使用
$menu->setName("Custom Name");
您还可以在InvMenu::send()
期间为每个玩家单独指定不同的菜单名称。
/** @var Player $player */ $menu->send($player, "Greetings, " . $player->getName());
验证菜单是否已发送给玩家
这不是一个常见的情况,但插件可能会阻止玩家打开库存。这也可能是在尝试丢弃垃圾InvMenu::send()
请求(如果您同时发送两个菜单而没有延迟,第一个菜单请求可能会被视为垃圾)。
/** @var string|null $name */ $menu->send($player, $name, function(bool $sent) : void{ if($sent){ // do something } });
处理菜单项目交易
要处理发生在菜单库存中的项目交易,您可以指定一个由InvMenu
在每次交易发生时触发的Closure
处理程序。您可以在处理程序中允许、取消并执行其他操作。要将交易处理程序注册到菜单,请使用
/** @var Closure $listener */ $menu->setListener($listener);
什么是$listener
?
/** * @param InvMenuTransaction $transaction * * Must return an InvMenuTransactionResult instance. * Return $transaction->continue() to continue the transaction. * Return $transaction->discard() to cancel the transaction. * @return InvMenuTransactionResult */ Closure(InvMenuTransaction $transaction) : InvMenuTransactionResult;
InvMenuTransaction
包含所有项目交易数据。
InvMenuTransaction::getPlayer()
返回触发交易的Player
。
InvMenuTransaction::getItemClicked()
返回玩家在菜单中点击的Item
。
InvMenuTransaction::getItemClickedWith()
返回玩家在点击项目时手中的Item
。
InvMenuTransaction::getAction()
返回一个SlotChangeAction
实例,以获取从菜单库存中点击的项目槽位索引。
InvMenuTransaction::getTransaction()
返回完整的InventoryTransaction
实例。
$menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ $player = $transaction->getPlayer(); $itemClicked = $transaction->getItemClicked(); $itemClickedWith = $transaction->getItemClickedWith(); $action = $transaction->getAction(); $invTransaction = $transaction->getTransaction(); return $transaction->continue(); });
不允许玩家从菜单库存中取出苹果的处理程序
$menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ if($transaction->getItemClicked()->getId() === ItemIds::APPLE){ $player->sendMessage("You cannot take apples out of that inventory."); return $transaction->discard(); } return $transaction->continue(); });
防止玩家更改库存
有两种方法可以防止玩家修改菜单的库存内容。
方法 #1:调用 InvMenuTransaction::discard()
$menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ // do something return $transaction->discard(); });
方法 #2:使用 InvMenu::readonly()
$menu->setListener(InvMenu::readonly());
$menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{ // do something }));
根据您的使用场景,您可能会发现其中一种方法比另一种更好。虽然方法 #1
让您对交易有完全的控制权(您可以根据玩家是否有权限、玩家是否在特定区域等条件有条件地取消交易),但方法 #2
减少了InvMenuTransactionResult
的导入和调用到InvMenutransaction::discard()
的冗余。
交易后执行任务
在玩家查看库存时,有些操作是无法进行的,例如发送表单——玩家在查看库存时无法查看表单。要完成此操作,您需要关闭菜单库存,并确保他们已经关闭,可以通过等待他们那边的响应来实现。您可以通过向 InvMenuTransactionResult::then()
提供回调来实现。
$menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{ $transaction->getPlayer()->removeCurrentWindow(); return $transaction->discard()->then(function(Player $player) : void{ // $player === $transaction->getPlayer() // assert($player->isOnline()); $player->sendForm(new Form()); }); });
$menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{ $transaction->getPlayer()->removeCurrentWindow(); $transaction->then(function(Player $player) : void{ $player->sendForm(new Form()); }); }));
监听玩家关闭或不再查看库存
要监听库存关闭触发器,请使用以下库存关闭 Closure
/** @var Closure $listener */ $menu->setInventoryCloseListener($listener);
什么是$listener
?
/** * @param Player $player the player who closed the inventory. * * @param Inventory $inventory the inventory instance closed by the player. */ Closure(Player $player, Inventory $inventory) : void;
强制关闭或从玩家处移除菜单
/** @var Player $player */ $player->removeCurrentWindow();
注册自定义 InvMenu 类型
假设您想向玩家发送一个分发器库存。虽然 InvMenu 没有内置 InvMenu::TYPE_DISPENSER
,但您仍然可以通过注册一个包含分发器库存外观信息的 InvMenuType
对象来创建一个分发器 InvMenu。
public const TYPE_DISPENSER = "myplugin:dispenser"; protected function onEnable() : void{ 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()); }
太好了!现在您可以使用以下方法创建分发器菜单
$menu = InvMenu::create(self::TYPE_DISPENSER);
InvMenu Wiki
使用 InvMenu 的应用程序、示例、教程和特色项目可以在 InvMenu Wiki 上找到。