Skip to content

InvMenu v4.0 Changelog and Migration Notes

Muqsit Rayyan edited this page Apr 12, 2021 · 1 revision

InvMenu v4 Changelog

Removed Classes

  • SessionizedInvMenu
  • SharedInvMenu

Removed Methods

  • InvMenu::copyProperties()
  • InvMenu::createSessionized()
  • InvMenu::getInventoryForPlayer()

Added Methods

  • InvMenu::getInventory() (<- SharedInvMenu::getInventory())

Changed Methods

  • InvMenu::create() now returns InvMenu instead of SharedInvMenu (SharedInvMenu has been removed)
  • InvMenu::readonly() is now a static method and accepts a listener as it's first parameter. The listener has a signature function(DeterministicInvMenuTransaction $transaction) : void
  • InvMenu::setListener($listener)'s $listener signature has been changed to function(InvMenuTransaction $transaction) : InvMenuTransactionResult

Migrating from InvMenu v3.x.x to InvMenu v4.x.x

InvMenu::createSessionized()

This method has been removed. SessionizedInvMenu was simply an InvMenu wrapper that held multiple InvMenu instances, mapped to player UUIDs. IOW, it was basically the end result of what you'd get if you were to have a non-sessionized InvMenu for each player.

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

InvMenu::setListener()

The method signature was far too long and possibly resulted in unnecessary imports that either you, your IDE or your static analyzer didn't like. InvMenu::setListener() now accepts only one parameter that holds it all — InvMenuTransaction. The return type of the listener has been changed from bool to InvMenuTransactionResult.

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

InvMenu::readonly()

In InvMenu v3.0, menus had a boolean readonly property to forcefully cancel the transaction. InvMenu::readonly() (then - non-static), produced same results as a non-readonly menu returning false in it's listener.

InvMenu::create(...)->setListener(function(...) : bool{ return false; });

The fact that readonly always cancelled the transaction meant it wasn't necessary to return any boolean value in the listener, i.e listener can be type-hinted with void... and so it was.. causing a mix in return types. Listeners' return type was then changed to bool|void based on the state of the menu's readonly property - readonly (return void), non-readonly (return bool). InvMenu::readonly() in v4.0 is now a static property that returns a closure that can be passed to InvMenu::setListener() instance that always returns false.

/** 1. Setting readonly without listener */
// InvMenu v3.0
$menu = InvMenu::create(InvMenu::TYPE_CHEST);
$menu->readonly();

// InvMenu v4.0
$menu = InvMenu::create(InvMenu::TYPE_CHEST);
$menu->setListener(InvMenu::readonly());
/** 2. Setting readonly with listener */
// 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();
}));

What's new in InvMenu v4.0

The InvMenuTransactionResult::then() method

Allows you to specify a closure that gets triggered after escaping from the event call stack and the client's network stack. This is useful when you need to do something like sending a form to a player (it isn't possible to send a form before or right after closing their inventory).

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

BEWARE: the then() callback will not get triggered if the player quits while the server is waiting for a confirmation from their side. The fact that then() was triggered implies $player->isConnected(). For readonly() listeners, you can directly trigger DeterministicInvMenuTransaction::then().

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

PHPStan Integration

PHPStan is a static analysis tool for PHP. You can read more about it here: https://phpstan.org/blog/find-bugs-in-your-code-without-writing-tests Based on your level, phpstan will warn you about incorrect closure signatures.