Paste #123095: gui engine

Date: 2024/05/26 06:27:53 UTC-07:00
Type: Denizen Script

View Raw Paste Download This Paste
Copy Link


ui_gui_events_handler_world:
  type: world
  debug: true
  subtasks:
    injecter:
      - stop if:!<context.inventory.script.exists>

      - define SCRIPT <context.inventory.script>
      - define SCRIPT_NAME <[SCRIPT].name>

      - stop if:!<server.has_flag[CACHE.UI.GUI.EVENTS.<[SCRIPT_NAME]>.<[EVENT]>]>

      - define HANDLERS_MAP <server.flag[CACHE.UI.GUI.EVENTS.<[SCRIPT_NAME]>.<[EVENT]>]>

      - define HANDLERS <[HANDLERS_MAP.ON].if_null[<list>]>
      - foreach <[HANDLERS]> as:HANDLER:
        - inject <script> path:subtasks.handlers.<[EVENT]>

      - wait 1t

      - define HANDLERS <[HANDLERS_MAP.AFTER].if_null[<list>]>
      - foreach <[HANDLERS]> as:HANDLER:
        - inject <script> path:subtasks.handlers.<[EVENT]>

    handlers:
      open:
        - inject <[SCRIPT]> path:subtasks.events.<[HANDLER.LINE]>

      close:
        - inject <[SCRIPT]> path:subtasks.events.<[HANDLER.LINE]>

      click:
        - if <[HANDLER.CLICK_TYPE].exists> && <context.click> != <[HANDLER.CLICK_TYPE]>:
          - foreach next
        - if <[HANDLER.ITEM_MATCHER].exists> && !<context.item.advanced_matches[<[HANDLER.ITEM_MATCHER]>]>:
          - foreach next
        - inject <[SCRIPT]> path:subtasks.events.<[HANDLER.LINE]>

      drag:
        - if <[HANDLER.ITEM_MATCHER].exists> && !<context.item.advanced_matches[<[HANDLER.ITEM_MATCHER]>]>:
          - foreach next
        - inject <[SCRIPT]> path:subtasks.events.<[HANDLER.LINE]>

  events:
    after script reload:
      - run ui_gui_refresh_events_cache

    on player clicks in inventory:
      - define EVENT click
      - inject <script> path:subtasks.injecter

    on player drags in inventory:
      - define EVENT drag
      - inject <script> path:subtasks.injecter

    on player opens inventory:
      - define EVENT open
      - inject <script> path:subtasks.injecter

    on player closes inventory:
      - define EVENT close
      - inject <script> path:subtasks.injecter

ui_gui_refresh_events_cache:
  type: task
  debug: false
  subtasks:
    handle_script:
      - define EVENT_LINES <[SCRIPT].data_key[subtasks.events].keys>
      - define SCRIPT_NAME <[SCRIPT].name>

      - foreach <[EVENT_LINES]> as:LINE:
        - define HANDLER <[LINE].proc[parse_gui_event_line]>
        - if <[HANDLER]> == null:
          - debug error "Event line '<[LINE]>' for script '<[SCRIPT_NAME]>' has been skipped."
          - foreach next

        # The flag format is:
        # EVENTS.my_script_name.click.on:<list[<map>]>
        # EVENTS.my_script_name.drag.after:<list[<map>]>
        # etc. to facilitate lookup during event handling.
        - flag server CACHE.UI.GUI.EVENTS.<[SCRIPT_NAME]>.<[HANDLER.EVENT]>.<[HANDLER.TIMING]>:->:<[HANDLER]>

  script:
    - flag server CACHE.UI.GUI:!

    - foreach <util.scripts> as:SCRIPT:
      - if <[SCRIPT].container_type> != inventory:
        - foreach next
      - if !<[SCRIPT].data_key[gui].is_truthy>:
        - foreach next
      - if !<[SCRIPT].data_key[subtasks.events].exists>:
        - foreach next

      - inject <script> path:subtasks.handle_script

parse_gui_event_line:
  type: procedure
  debug: false
  definitions: LINE
  description: Parses an event handler line into a map of its components.
  data:
    click_types:
      # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/inventory/ClickType.html
      - CONTROL_DROP
      - CREATIVE
      - DOUBLE_CLICK
      - DROP
      - LEFT
      - MIDDLE
      - NUMBER_KEY
      - RIGHT
      - SHIFT_LEFT
      - SHIFT_RIGHT
      - SWAP_OFFHAND
      - UNKNOWN
      - WINDOW_BORDER_LEFT
      - WINDOW_BORDER_RIGHT

    aliases:
      open: open
      close: close
      click: click
      clicked: click
      drag: drag
      dragged: drag

  subtasks:
    open:
      - debug error "'<[LINE]>' provides arguments, but 'open' does not accept any."
      - determine null

    close:
      - debug error "'<[LINE]>' provides arguments, but 'close' does not accept any."
      - determine null

    click:
      - define CLICK_TYPES <script.data_key[data.click_types]>
      - if <[PARTS].size> == 1:
        - define PART <[PARTS].first>
        - if <[PART]> in <[CLICK_TYPES]>:
          - define HANDLER.CLICK_TYPE <[PART]>
        - else:
          - define HANDLER.ITEM_MATCHER <[PART]>
      - else if <[PARTS].size> == 2:
        - if <[PARTS].first> in <[CLICK_TYPES]>:
          - define HANDLER.CLICK_TYPE <[PARTS].first>
          - define HANDLER.ITEM_MATCHER <[PARTS].get[2]>
        - else if <[PARTS].get[2]> in <[CLICK_TYPES]>:
          - define HANDLER.CLICK_TYPE <[PARTS].get[2]>
          - define HANDLER.ITEM_MATCHER <[PARTS].first>
        - else:
          - debug error "'<[LINE]>' event handler does not contain a valid click type."
          - determine null
      - else:
        - debug error "'<[LINE]>' event handler contains too many arguments."
        - determine null

    drag:
      - if <[PARTS].size> == 1:
        - define HANDLER.ITEM_MATCHER <[PARTS].first>
      - else:
        - debug error "'<[LINE]>' event handler contains too many arguments."
        - determine null

  script:
    - define PARTS <[LINE].split>

    # The first part must always be `on` or `after`
    - if <[PARTS].first> == on:
      - define TIMING on
    - else if <[PARTS].first> == after:
      - define TIMING after
    - else:
      - debug error "'<[LINE]>': all event handlers must start with 'on' or 'after'."
      - determine null

    # All events end with the event type, but might be conjugated differently
    # I.e. `on click` or `on item clicked`
    - define ALIAS <[PARTS].last>
    - define EVENT <script.data_key[data.aliases.<[ALIAS]>].if_null[null]>
    - if <[ALIAS]> == null:
      - debug error "'<[LINE]>' did not match any known event name."
      - determine null

    - definemap HANDLER:
        LINE: <[LINE]>
        TIMING: <[TIMING]>
        EVENT: <[EVENT]>

    # The remaining parts are the handler details
    - define PARTS <[PARTS].get[2].to[-2]>
    - if <[PARTS].is_truthy>:
      - inject <script> path:subtasks.<[EVENT]>

    - determine <[HANDLER]>