From df8e10cad95c557595f2b03dae89be7f37d61a6d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 14 Aug 2018 16:06:55 +0100 Subject: [PATCH] Forms API, part 1: add Player->sendForm() and Form interface There's no implementation here yet, but that can come later. This lays the ground for allowing plugins to have an integrated method to send forms, as well as a solution to the ID conflict problem. A built in implementation should not be a concretion and it should be able to be swapped for third party implementations. This enables the possiblity to do so. --- src/pocketmine/Player.php | 50 +++++++++++++++++++ src/pocketmine/form/Form.php | 44 ++++++++++++++++ .../form/FormValidationException.php | 28 +++++++++++ .../mcpe/PlayerNetworkSessionAdapter.php | 2 +- 4 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 src/pocketmine/form/Form.php create mode 100644 src/pocketmine/form/FormValidationException.php 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{