muqsit/invmenu

一个用于创建和管理虚拟库存的PocketMine-MP插件!

4.6.5 2023-08-14 07:10 UTC

This package is auto-updated.

Last update: 2024-09-17 20:58:28 UTC


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_CHESTInvMenu::TYPE_DOUBLE_CHESTInvMenu::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 上找到。