flytegg / twilight

A Kotlin API for Spigot/Paper Minecraft servers providing essential utilities to streamline development.
https://docs.flyte.gg/twilight.html
MIT License
55 stars 8 forks source link

Runnable onComplete Unit #72

Closed slohth closed 1 month ago

slohth commented 1 month ago

Not sure how this is possible but there should be an onComplete unit for runnables that is called when the code in the runnable block has finished executing. This will be very useful if you wish to run sync code and async code nested together.

onComplete { } - Run the next runnable the same way (async/sync) the previous runnable was ran onCompleteSync { } - Run the next runnable sync, even if the previous runnable was async onCompleteAsync { } - Run the next runnable async, even if the previous runnable was sync

For example, if I want to:

  1. (Async) Copy a world folder
  2. (Sync) Load the new copied world
  3. (Async) Load the schematic

And also send players a message when step 2 and 3 are finished it would look like:

Without onComplete:

val name = "map-${arena.key}-$id"
async { // Asynchronously copy world

  val template = File(Bukkit.getWorldContainer(), "void-template")
  val world = File(Bukkit.getWorldContainer(), name)
  FileUtils.copyDirectory(template, world)

  val uid = File(world, "uid.dat")
  if (uid.exists()) uid.delete()

  sync { // Then synchronously load world

    broadcast(Component.text("Attempting world load...", NamedTextColor.GRAY))
    Bukkit.createWorld(WorldCreator(name))
    broadcast(Component.text("Loaded world $name", NamedTextColor.GREEN))

    async { // Then asynchronously paste schematic

      broadcast(Component.text("Attempting schematic paste...", NamedTextColor.GRAY))
      // Paste schematic
      broadcast(Component.text("Loaded schematic!", NamedTextColor.GRAY))

    }
  }
}

With onComplete:

val name = "map-${arena.key}-$id"

async {

  val template = File(Bukkit.getWorldContainer(), "void-template")
  val world = File(Bukkit.getWorldContainer(), name)
  FileUtils.copyDirectory(template, world)

  val uid = File(world, "uid.dat")
  if (uid.exists()) uid.delete()

}.onCompleteSync {

  broadcast(Component.text("Attempting world load...", NamedTextColor.GRAY))
  Bukkit.createWorld(WorldCreator(name))
  broadcast(Component.text("Loaded world $name", NamedTextColor.GREEN))

}.onCompleteAsync {

  broadcast(Component.text("Attempting schematic paste...", NamedTextColor.GRAY))
  // Paste schematic
  broadcast(Component.text("Loaded schematic!", NamedTextColor.GRAY))

}

I'm sure there are many possibilities where this will be a really useful stylistic feature. I would look into implementing this myself but to be honest I haven't got the first idea about concurrency, lol.

slohth commented 1 month ago

Implemented as of version 1.1.14