1. The forums will be archived and moved to a read only mode in about 2 weeks (mid march).

RFC The Form UI Craze

Discussion in 'Development' started by SOFe, Nov 24, 2017.

  1. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,968
    GitHub:
    sof3
    I am starting this thread in light of the recent viral trend of rewriting existing plugins into supporting custom UI.

    As a matter of fact, most existing plugins just need a change in user interface. There is no need to drop the command interface (so that people can still powerful things like TapToDo with commands!), and the original controller and model layers (referring to the MVC approach) can actually be 100% preserved, probably even with more powerful features, because Form UI makes it easier to add configuration to user input.
    Take WorldEditArt-Lite for example. The command UI for block replacement can be very complicated: https://web.archive.org/web/20171124035315/https://legendofmcpe.github.io/WorldEditArt/wiki/Editing
    This is so complicated that not even the command syntax hint (as introduced in MCPE 0.17 or something) can show the correct predictions.

    However, with forms UI, this can be made much easier, e.g. with a wizard:
    1. User types //replace, or otherwise triggers the replacement wizard
    2. MenuForm
      • Title: "Replace wizard, 1/3: Choose replaced blocks"
      • Text: Click "Add" to add replaced block type, or click on a block type to remove. Click "Next" to continue.
      • Options: "Add", "Next", then a list of selected blocks.
      • "Add" will open a custom form for block selection, containing fields like block ID, search block name, wildcard/variable damage values etc.
      • "Import preset" will open a MenuForm to select a preset.
      • "Next" will open Step 3.
    3. MenuForm, same as Step 2 except for selecting blocks to replace with, and repeating patterns.
    4. CustomForm.
      • Dropdown for which selection to use.
      • Checkbox for whether a hollow selection should be used.
      • Sliders for the sizes of padding and margin.
    5. A confirmation ModalForm.
    From this example, we can see that form UI can be totally different from the command UI.

    What I would like to discuss in this thread is how we can make a smooth transition from commands to forms, without breaking the existing possibilities (e.g. plugins that execute commands).
    Particularly, I'd like to discuss if there is anything that the PocketMine API or potential libraries can do.
     
    Last edited: Nov 24, 2017
  2. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,968
    GitHub:
    sof3
    For example, is there any intelligent approach that could make it easy to implement both form UI and command UI for the same feature, without almost no code duplication?
     
  3. dktapps

    dktapps Administrator Staff Member PMMP Team

    Messages:
    774
    GitHub:
    dktapps
    given that the commands API is scheduled for a rewrite, anything you write now could end up broken tomorrow.

    ???
     
    jasonwynn10 and Sandertv like this.
  4. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,968
    GitHub:
    sof3
    Forms are your best friends ;)
    Yep, therefore this thread is about both commands and forms.
     
    HimbeersaftLP, Ant and jasonwynn10 like this.
  5. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,968
    GitHub:
    sof3
    I am mainly thinking of an aim-based API. Here I give a few examples:
    Economy plugin:
    HTML:
    <!-- I am using XML here, but of course, this is just an example, just because I prefer writing examples in XML -->
    <category id="economys" name="EconomyS" controller="onebone\economys\IntentController">
      <category id="transactions" cmdName="transactions" name="Transactions" permission="economys.transactions">
        <intent name="Pay" id="pay" cmdName="pay" descr="Pay money from your account to another player">
          <option id="target" type="PlayerMenu|allowOffline|noSelf" name="Target"/>
          <!-- Here, PlayerMenu is a registered OptionProvider, and allowOffline and noSelf are options passed to PlayerMenu -->
          <option id="amount" type="float" name="Amount"/>
          <option id="useBank" type="bool" name="Use bank account"/>
          <option id="message" type="rawtext" name="Message"/>
        </intent>
      </category>
    </category>
    
    When this XML is registered, a command called /pay is registered, with the command usage generated from the options required (e.g. "/pay <target : target> <amount : float> <useBank : bool> <message : rawtext>").
    If the user types /transactions, the category dialog (a MenuForm) will open up, showing the subcategories and intents under the category with cmdName "transactions".
    If the user types /pay, or clicks the pay option from the transactions MenuForm, the intent dialog for the pay intent will open up.

    How the intent dialog looks should be decided by a lot of factors based on its option types. For example, if the "target" option does not exist, it can be a simple CustomForm with one float input/slider (amount), one checkbox (useBank) and one input (message).

    But what about with "target"? This depends on the implementation of PlayerMenu. An example implementation would be like this?
    PHP:
    class PlayerMenu extends OptionProvider{
        public 
    $allowOffline false;
        public 
    $noSelf false;
        public function 
    getFormElement(Player $player) : CustomFormElement{
            if(!
    $this->allowOffline){
                
    $players Server::getInstance()->getOnlinePlayers();
                if(
    $noSelf) unset($players[array_search($player$players)]);
                return new 
    Dropdown($players); // too lazy to convert Player[] to name array
            
    }
            return new 
    OfflinePlayerMenuWizardButton();
            
    // this will show a button that opens the OfflinePlayerMenu wizard
        
    }

        public function 
    adaptFormResponse() : OptionProviderResult{
            
    // this might be complicated
        
    }

        public function 
    getCommandValueTypes() : array{
            return [
    "target"];
        }

        public function 
    adaptCommandResponse(string $input) : OptionProviderResult{
            return new 
    PlayerMenuResult($input);
        }
    }
    I've not thought about how OfflinePlayerMenuWizard can be implemented yet, but I'm thinking of something that looks like what I gave in the WorldEditArt example in my OP.
     
    Awzaw likes this.
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.