diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 407c469fb..be4542a9d 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -66,6 +66,8 @@ use pocketmine\event\player\PlayerToggleSneakEvent; use pocketmine\event\player\PlayerToggleSprintEvent; use pocketmine\event\player\PlayerTransferEvent; use pocketmine\event\server\DataPacketSendEvent; +use pocketmine\form\Form; +use pocketmine\form\FormValidationException; use pocketmine\inventory\CraftingGrid; use pocketmine\inventory\Inventory; use pocketmine\inventory\PlayerCursorInventory; @@ -116,6 +118,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\network\mcpe\protocol\LoginPacket; use pocketmine\network\mcpe\protocol\MobEffectPacket; use pocketmine\network\mcpe\protocol\MobEquipmentPacket; +use pocketmine\network\mcpe\protocol\ModalFormRequestPacket; use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\PlayerActionPacket; use pocketmine\network\mcpe\protocol\PlayStatusPacket; @@ -323,6 +326,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** @var int[] ID => ticks map */ protected $usedItemsCooldown = []; + /** @var int */ + protected $formIdCounter = 0; + /** @var Form[] */ + protected $forms = []; + /** * @return TranslationContainer|string */ @@ -3353,6 +3361,48 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->dataPacket($pk); } + /** + * Sends a Form to the player, or queue to send it if a form is already open. + * + * @param Form $form + */ + public function sendForm(Form $form) : void{ + $id = $this->formIdCounter++; + $pk = new ModalFormRequestPacket(); + $pk->formId = $id; + $pk->formData = json_encode($form); + if($this->dataPacket($pk)){ + $this->forms[$id] = $form; + } + } + + /** + * @param int $formId + * @param mixed $responseData + * + * @return bool + */ + public function onFormSubmit(int $formId, $responseData) : bool{ + if(!isset($this->forms[$formId])){ + $this->server->getLogger()->debug("Got unexpected response for form $formId"); + return false; + } + + try{ + $next = $this->forms[$formId]->handleResponse($this, $responseData); + if($next !== null){ + $this->sendForm($next); + } + }catch(FormValidationException $e){ + $this->server->getLogger()->critical("Failed to validate form " . get_class($this->forms[$formId]) . ": " . $e->getMessage()); + $this->server->getLogger()->logException($e); + }finally{ + unset($this->forms[$formId]); + } + + return true; + } + /** * Note for plugin developers: use kick() with the isAdmin * flag set to kick without the "Kicked by admin" part instead of this method. diff --git a/src/pocketmine/form/Form.php b/src/pocketmine/form/Form.php new file mode 100644 index 000000000..f822b1ceb --- /dev/null +++ b/src/pocketmine/form/Form.php @@ -0,0 +1,44 @@ +player->onFormSubmit($packet->formId, json_decode($packet->formData, true)); } public function handleServerSettingsRequest(ServerSettingsRequestPacket $packet) : bool{