redtv_muqsit/invmenu

A PocketMine-MP 病毒来创建和管理虚拟库存!

dev-main 2024-09-05 19:59 UTC

This package is not auto-updated.

Last update: 2024-09-20 18:39:34 UTC


README

InvMenu 是一个 PocketMine-MP 病毒,它简化了创建和管理虚拟库存的过程!

安装

您可以在 poggit 上通过点击 这里 获取编译好的 .phar 文件。

用法

InvMenu 支持从任何类型的 Inventory 创建 GUI。

注意: 您必须在启用插件之前注册 InvMenuHandler,然后才能开始创建 InvMenu 实例。

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
	}
});

处理菜单项交易

要处理发生到和从菜单库存中的项目交易,您可以指定一个 Closure 处理程序,该处理程序在每次交易发生时由 InvMenu 触发。您可以在处理程序中允许、取消并执行其他操作。要将事务处理程序注册到菜单中,请使用

/** @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());
	});
}));

监听玩家关闭或不再查看存货

要监听存货关闭触发器,请使用

/** @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 维基

使用 InvMenu 的应用程序、示例、教程和特色项目可以在 InvMenu 维基 上找到。