-
Notifications
You must be signed in to change notification settings - Fork 80
Description
For those new to the topic, await-generator allows you to write asynchronous navigation flows sequentially in PHP. Think of yield from as a replacement for await keyword in Javascript, Python, and friends.
Menus are reusable (unlike forms), but switching between different menu navigation flows is laborious as you need to track state across different menu listeners which typically means sharing or explicitly persisting state variables across different contexts. InvMenu::send() can be readily wrapped in a Promise (as its callback is guaranteed to execute).
Menu transactions are complex - once you await a transaction, you have lost liberty over its outcome (continue/discard) as the response must be immediate. Awaiting a transaction is ideal when a menu is intended to be read-only.
// proposed solution
$menu = InvMenu::create(InvMenu::TYPE_CHEST);
while(true){
$players = array_values($player->getServer()->getOnlinePlayers());
$contents = array_map(fn($p) => VanillaItems::TOTEM(), $players);
$menu->setContents($contents);
try{
$transaction = yield from $menu->nextTransaction($player);
}catch(AwaitInvMenuException $e){
break;
}
$select = $players[$transaction->getAction()->getSlot()];
$player->sendToast($select->getName(), "You selected this player.");
}Reusable menu in which each totem represents an online player.
nextTransaction can take the task of sending the menu and capturing a transaction, but a separate sendAsync($player) and waitClose($player) are still helpful for more complex functions like terminating an animation early.
// helper function
function sleep($ticks) : Generator{
$scheduler = $plugin->getScheduler();
yield from Await::promise(fn($resolve) => $scheduler->scheduleDelayedTask(new ClosureTask($resolve), $ticks));
}
// simple countdown animation
$menu = InvMenu::create(InvMenu::TYPE_CHEST);
yield from $menu->sendAsync($player);
for($i = 10; $i > 0; $i--){
$menu->setItem(22, VanillaItems::ARROW()->setCount($i));
[$k, $v] = yield from Await::race([sleep(20), $menu->waitClose($player)]);
if($k === 1) break
}Simple countdown animation that reduces item count for 10 seconds. Loop terminates if player closes menu before countdown completes.