Skip to content

Suggestion: Flow and execution control #4005

Open
@Moderocky

Description

Preface: these features are based on things available in similar "beginner" programming tools (like Scratch and action-workflow systems), they're designed to make it simple to do tasks that, while already possible, are either very complicated or currently dangerous if done wrongly.

The do section

The do section is (in simplest terms) a section of executable code, and the user is able to control how and when it is run.
This is designed to be similar to Java's CompletableFuture system, allowing control of how and when sections are executed.

This is designed to be simple and clear, easy to use and understand. It should look a bit like an if/else if/else block.

The main parts

Syntax Explanation
do [async]: Runs the code inside. If specified async, this is not run on the main thread.
and do [async]: Starts running at the same time as the do block before it if possible, requiring one to be a do async block. If neither are async, it runs one and then the other.
then do [async]: Starts running after the previous block completes, allowing for easy execution of code upon completion of a delayed task.
finally: This is run once all previous blocks have completed.

Examples

This allows you to make slow, otherwise-blocking requests in the background.
An addon developer doesn't have to worry about getting their expression or effect to work asynchronously because the Skript user can handle this for them.

on join:
  do async:
    set {_location} to # retrieve player location from database
    set {_name} to # retrieve nickname from web URL
    # other slow tasks
  then do: # run normally on the main thread once the previous block has completed
    teleport player to {_location}
    set player's display name to {_name}

This allows you to compute and execute things efficiently.
In this example, doing the two async requests sequentially would take longer than doing them both at the same time, and the finally block allows you to continue your code as soon as both are done.

on join:
  do async:
    set {_a} to # async web request syntax
  and do async: # done at same time as previous
    set {_b} to # async web request syntax
  finally: # done once both are completed
    if {_a} is true:
      if {_b} is true:
        kick player

This example shows how the user can do extensive or repeated calculations or slow loops without risking lag spikes or TPS drops.

on join:
  do async:
    loop 10000 times:
      # imagine a slow maths expression here :)
  finally:
    # do something with the result

This is a full example of all the possible sections. Their usage should be fairly obvious, but just to make it explicit:

do: # starts first, on main thread
do async: # starts first, on another thread

then do: # starts after previous, on main thread

and do: # starts at same time as previous, as normal. If neither are async, this would be done after

then do async: # starts after previous, on another thread

and do async: # starts at same time as previous, on another thread

finally: # starts after ALL blocks have completed (not just previous) on main thread

Caveats

Obviously, some things cannot be run safely on other threads. For example, a lot of world-altering syntaxes couldn't be run in an async block.

To cope with this, I have two solutions:

  1. Run these parts through the Bukkit scheduler on the main thread where possible - though this might cause extra problems
  2. Warn the user that these syntaxes cannot be used here, and that the block will run on the main thread

These would require you specify in syntaxes whether they are async-safe or not, which might require a lot of minor edits initially but would future-proof this (and possibly give some useful benefits for any other async stuff in future.)

There might also be some concern over syntax.
The term async is a programming term, and understandably might not fit with Skript's aesthetic. To beginner users it would just be a meaningless term, and could easily be misunderstood. Lots of people get the idea that 'async' means 'faster' or 'without lag' or something similar, and so might misuse this.
If this is a problem, then I can suggest in [the] background as an alternative - simpler for users to understand and pretty much explains what's going to happen. It doesn't imply the task will be done faster or better, just that it will be done in the background.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    enhancementFeature request, an issue about something that could be improved, or a PR improving something.priority: lowIssues that are not harmful to the experience but are related to useful changes or additions.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions