Skip to content

Commit

Permalink
Merge pull request #74 from flytegg/pr/scheduler
Browse files Browse the repository at this point in the history
Pr/scheduler
  • Loading branch information
joshbker authored Oct 8, 2024
2 parents 8fa421d + 404bc82 commit 9d967f1
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 22 deletions.
32 changes: 29 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Maven
<dependency>
<groupId>gg.flyte</groupId>
<artifactId>twilight</artifactId>
<version>1.1.13</version>
<version>1.1.14</version>
</dependency>
```

Expand All @@ -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:
Expand Down Expand Up @@ -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.
<br>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.

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

group = "gg.flyte"
version = "1.1.13"
version = "1.1.14"

repositories {
mavenLocal()
Expand Down
32 changes: 14 additions & 18 deletions src/main/kotlin/gg/flyte/twilight/scheduler/Scheduler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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() }
}

/**
Expand All @@ -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() }
}

/**
Expand All @@ -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)
}

Expand All @@ -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)
}

Expand Down
117 changes: 117 additions & 0 deletions src/main/kotlin/gg/flyte/twilight/scheduler/TwilightRunnable.kt
Original file line number Diff line number Diff line change
@@ -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)
}
}
}

0 comments on commit 9d967f1

Please sign in to comment.