diff --git a/README.md b/README.md
index 00ecdfa..d3aac3f 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ Maven
gg.flyte
twilight
- 1.1.13
+ 1.1.14
```
@@ -33,14 +33,14 @@ maven {
url "https://repo.flyte.gg/releases"
}
-implementation "gg.flyte:twilight:1.1.13"
+implementation "gg.flyte:twilight:1.1.14"
```
Gradle (Kotlin DSL)
```kotlin
maven("https://repo.flyte.gg/releases")
-implementation("gg.flyte:twilight:1.1.13")
+implementation("gg.flyte:twilight:1.1.14")
```
Certain features of Twilight require configuration, which can be done via the Twilight class. To setup a Twilight class instance, you can use the `twilight` function as shown below:
@@ -266,6 +266,32 @@ repeat(5, 10, TimeUnit.SECONDS, true) {
> Twilight `repeat` conflicting with Kotlin's `repeat`? As an alternative, you can use `repeatingTask`.
+You can also chain runnables together using `onComplete` to nicely nest sync/async executions. Here's an example:
+```kotlin
+async {
+ println("I am an async BukkitRunnable called Atom")
+}.onComplete() {
+ println("I am an async BukkitRunnable called Brandon running immediately after Atom finishes executing")
+}.onCompleteSync(10) {
+ println("I am a sync BukkitRunnable called Charlie running 10 ticks after Brandon finishes executing")
+}.onComplete(5, TimeUnit.SECONDS) {
+ println("I am a sync BukkitRunnable called Dawson running 5 seconds after Charlie finishes executing")
+}.onCompleteAsync {
+ println("I am an async BukkitRunnable called Enid running immediately after Dawson finishes executing")
+}
+```
+As you can see, you can specify whether sync/async (if unspecified, it will not change) and you can pass in an optional delay.
+
This also works with a delay from the get-go:
+```kotlin
+delay(20, TimeUnit.SECONDS) {
+ println("I am a sync BukkitRunnable delayed by 20 seconds")
+}.onCompleteAsync(10, TimeUnit.SECONDS) {
+ println("I am an async BukkitRunnable delayed by a further 10 seconds")
+}
+```
+
+> Currently, onComplete is incompatible with repeating tasks.
+
### GUI Builder
Creating GUI's can be an incredibly long and tedious process, however, in Twilight we offer a clean and efficient way to build GUIs.
diff --git a/build.gradle.kts b/build.gradle.kts
index 99c34fc..fee4bf5 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,7 @@ plugins {
}
group = "gg.flyte"
-version = "1.1.13"
+version = "1.1.14"
repositories {
mavenLocal()
diff --git a/src/main/kotlin/gg/flyte/twilight/scheduler/Scheduler.kt b/src/main/kotlin/gg/flyte/twilight/scheduler/Scheduler.kt
index f393390..f2ef835 100644
--- a/src/main/kotlin/gg/flyte/twilight/scheduler/Scheduler.kt
+++ b/src/main/kotlin/gg/flyte/twilight/scheduler/Scheduler.kt
@@ -12,20 +12,20 @@ import org.bukkit.scheduler.BukkitTask
* Schedules a synchronous task to be executed by the Bukkit scheduler.
*
* @param runnable The function representing the task to be executed.
- * @return The BukkitTask representing the scheduled task.
+ * @return The TwilightRunnable representing the scheduled task.
*/
-fun sync(runnable: BukkitRunnable.() -> Unit): BukkitTask {
- return createBukkitRunnable(runnable).runTask(Twilight.plugin)
+fun sync(runnable: TwilightRunnable.() -> Unit): TwilightRunnable {
+ return TwilightRunnable(runnable, false).apply { schedule() }
}
/**
* Schedules an asynchronous task to be executed by the Bukkit scheduler.
*
* @param runnable The function representing the task to be executed.
- * @return The BukkitTask representing the scheduled task.
+ * @return The TwilightRunnable representing the scheduled task.
*/
-fun async(runnable: BukkitRunnable.() -> Unit): BukkitTask {
- return createBukkitRunnable(runnable).runTaskAsynchronously(Twilight.plugin)
+fun async(runnable: TwilightRunnable.() -> Unit): TwilightRunnable {
+ return TwilightRunnable(runnable, true).apply { schedule() }
}
/**
@@ -35,19 +35,15 @@ fun async(runnable: BukkitRunnable.() -> Unit): BukkitTask {
* @param unit The TimeUnit representing the time unit of the delay (default: MILLISECONDS).
* @param async Whether the task should be executed asynchronously (default: false).
* @param runnable The function representing the task to be executed.
- * @return The BukkitTask representing the scheduled task.
+ * @return The TwilightRunnable representing the scheduled task.
*/
fun delay(
value: Int,
unit: TimeUnit = TimeUnit.TICKS,
async: Boolean = false,
- runnable: BukkitRunnable.() -> Unit
-): BukkitTask {
- return if (async) {
- createBukkitRunnable(runnable).runTaskLaterAsynchronously(Twilight.plugin, unit.toTicks(value.toLong()))
- } else {
- createBukkitRunnable(runnable).runTaskLater(Twilight.plugin, unit.toTicks(value.toLong()))
- }
+ runnable: TwilightRunnable.() -> Unit
+): TwilightRunnable {
+ return TwilightRunnable(runnable, async, unit.toTicks(value.toLong())).apply { schedule() }
}
/**
@@ -56,10 +52,10 @@ fun delay(
*
* @param ticks The number of ticks for the delay (default: 1).
* @param runnable The function representing the task to be executed.
- * @return The BukkitTask representing the scheduled task.
+ * @return The TwilightRunnable representing the scheduled task.
* @see delay
*/
-fun delay(ticks: Int = 1, runnable: BukkitRunnable.() -> Unit): BukkitTask {
+fun delay(ticks: Int = 1, runnable: BukkitRunnable.() -> Unit): TwilightRunnable {
return delay(ticks, TimeUnit.TICKS, false, runnable)
}
@@ -71,10 +67,10 @@ fun delay(ticks: Int = 1, runnable: BukkitRunnable.() -> Unit): BukkitTask {
* @param ticks The number of ticks for the delay (default: 1).
* @param async Whether the task should be executed asynchronously.
* @param runnable The function representing the task to be executed.
- * @return The BukkitTask representing the scheduled task.
+ * @return The TwilightRunnable representing the scheduled task.
* @see delay
*/
-fun delay(ticks: Int = 1, async: Boolean, runnable: BukkitRunnable.() -> Unit): BukkitTask {
+fun delay(ticks: Int = 1, async: Boolean, runnable: BukkitRunnable.() -> Unit): TwilightRunnable {
return delay(ticks, TimeUnit.TICKS, async, runnable)
}
diff --git a/src/main/kotlin/gg/flyte/twilight/scheduler/TwilightRunnable.kt b/src/main/kotlin/gg/flyte/twilight/scheduler/TwilightRunnable.kt
new file mode 100644
index 0000000..bde9c3a
--- /dev/null
+++ b/src/main/kotlin/gg/flyte/twilight/scheduler/TwilightRunnable.kt
@@ -0,0 +1,117 @@
+package gg.flyte.twilight.scheduler
+
+import gg.flyte.twilight.Twilight
+import gg.flyte.twilight.time.TimeUnit
+import org.bukkit.scheduler.BukkitRunnable
+import org.bukkit.scheduler.BukkitTask
+
+/**
+ * A flexible runnable wrapper class for Bukkit/Spigot that supports chaining of tasks with
+ * optionally set delays and sync/async execution
+ *
+ * @param task The task context to be executed by this runnable
+ * @param async Whether this task should be run async
+ * @param delay The delay before this task should be executed in ticks
+ */
+class TwilightRunnable(
+ private val task: TwilightRunnable.() -> Unit,
+ val async: Boolean,
+ private val delay: Long = 0
+) : BukkitRunnable() {
+
+ private var nextRunnable: TwilightRunnable? = null
+
+ // Executes main task and schedules the next runnable if one exists
+ override fun run() {
+ try {
+ task()
+ } finally { nextRunnable?.schedule() }
+ }
+
+ /**
+ * Define a runnable to executed after the completion of this runnable,
+ * This runnable will run the same async state of the previous runnable
+ * @param delay delay before this task should be executed
+ * @param unit The unit of time the delay is in
+ * @param action The task to be executed
+ * @return The new TwilightRunnable
+ */
+ fun onComplete(
+ delay: Int = 0,
+ unit: TimeUnit = TimeUnit.TICKS,
+ action: TwilightRunnable.() -> Unit
+ ): TwilightRunnable {
+ return chainRunnable(action, async, unit.toTicks(delay.toLong()))
+ }
+
+ /**
+ * Define a runnable to executed synchronously after the completion of this runnable
+ * @param delay delay before this task should be executed
+ * @param unit The unit of time the delay is in
+ * @param action The task to be executed
+ * @return The new TwilightRunnable
+ */
+ fun onCompleteSync(
+ delay: Int = 0,
+ unit: TimeUnit = TimeUnit.TICKS,
+ action: TwilightRunnable.() -> Unit
+ ): TwilightRunnable {
+ return chainRunnable(action, false, unit.toTicks(delay.toLong()))
+ }
+
+ /**
+ * Define a runnable to executed asynchronously after the completion of this runnable
+ * @param delay delay before this task should be executed
+ * @param unit The unit of time the delay is in
+ * @param action The task to be executed
+ * @return The new TwilightRunnable
+ */
+ fun onCompleteAsync(
+ delay: Int = 0,
+ unit: TimeUnit = TimeUnit.TICKS,
+ action: TwilightRunnable.() -> Unit
+ ): TwilightRunnable {
+ return chainRunnable(action, true, unit.toTicks(delay.toLong()))
+ }
+
+ /**
+ * Chains a new task to be executed after the current one completes
+ * @param action The task to be executed
+ * @param async Whether the new task is async
+ * @param delay The delay before the new task should execute in ticks
+ * @return The new TwilightRunnable
+ */
+ private fun chainRunnable(action: TwilightRunnable.() -> Unit, async: Boolean, delay: Long = 0): TwilightRunnable {
+ val newRunnable = TwilightRunnable(action, async, delay)
+ if (nextRunnable == null) {
+ nextRunnable = newRunnable
+ } else {
+ var last = nextRunnable
+ while (last?.nextRunnable != null) {
+ last = last.nextRunnable
+ }
+ last?.nextRunnable = newRunnable
+ }
+ return newRunnable
+ }
+
+ /**
+ * Schedules this runnable to be executed
+ * TODO Repeating runnables cause issues with onComplete as it attempts to schedule identical tasks
+ * TODO Will fix at some point but for now just dont onComplete on repeat, it's pretty pointless to do so anyway
+ * TODO For now, I have not implemented this class for repeat in Scheduler.kt to prevent people using it
+ *
+ * @param delay Additional delay to be added in ticks
+ * @return The BukkitTask
+ */
+ fun schedule(delay: Int = 0): BukkitTask {
+ val totalDelay = this.delay + delay
+ return if (async) {
+ if (totalDelay > 0) this.runTaskLaterAsynchronously(Twilight.plugin, totalDelay)
+ else this.runTaskAsynchronously(Twilight.plugin)
+ } else {
+ if (totalDelay > 0) this.runTaskLater(Twilight.plugin, totalDelay)
+ else this.runTask(Twilight.plugin)
+ }
+ }
+}
\ No newline at end of file