diff --git a/README.md b/README.md
index b1a8559..267d7d3 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ Maven
gg.flyte
twilight
- 1.0.25
+ 1.0.26
```
@@ -29,14 +29,14 @@ maven {
url "https://repo.flyte.gg/releases"
}
-implementation "gg.flyte:twilight:1.0.25"
+implementation "gg.flyte:twilight:1.0.26"
```
Gradle (Kotlin DSL)
```kotlin
maven("https://repo.flyte.gg/releases")
-implementation("gg.flyte:twilight:1.0.25")
+implementation("gg.flyte:twilight:1.0.26")
```
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` method as shown below:
diff --git a/build.gradle.kts b/build.gradle.kts
index 51b46cd..f4d895e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -5,7 +5,7 @@ plugins {
}
group = "gg.flyte"
-version = "1.0.25"
+version = "1.0.26"
repositories {
mavenCentral()
diff --git a/src/main/kotlin/gg/flyte/twilight/event/Event.kt b/src/main/kotlin/gg/flyte/twilight/event/Event.kt
index 317aa3b..051fa46 100644
--- a/src/main/kotlin/gg/flyte/twilight/event/Event.kt
+++ b/src/main/kotlin/gg/flyte/twilight/event/Event.kt
@@ -1,10 +1,12 @@
package gg.flyte.twilight.event
import gg.flyte.twilight.Twilight
+import gg.flyte.twilight.event.custom.admin.listener.OpEventListener
import gg.flyte.twilight.event.custom.interact.listener.InteractEventListener
import gg.flyte.twilight.extension.applyForEach
import gg.flyte.twilight.inventory.GUIListener
import org.bukkit.event.*
+import org.bukkit.scheduler.BukkitTask
import java.time.Instant
/**
@@ -47,8 +49,12 @@ open class CustomTwilightListener {
* The list of events registered to this custom Twilight Event
*/
val events = mutableListOf()
+ val runnables = mutableListOf()
- fun unregister() = events.applyForEach { unregister() }
+ fun unregister() {
+ events.applyForEach { unregister() }
+ runnables.applyForEach { cancel() }
+ }
}
/**
@@ -113,6 +119,7 @@ open class TwilightEvent(async: Boolean = false) : Event(async), Cancellable {
*/
val customEvents = listOf(
GUIListener,
- InteractEventListener
+ InteractEventListener,
+ OpEventListener
)
diff --git a/src/main/kotlin/gg/flyte/twilight/event/custom/admin/PlayerDeopEvent.kt b/src/main/kotlin/gg/flyte/twilight/event/custom/admin/PlayerDeopEvent.kt
new file mode 100644
index 0000000..1f5eb2d
--- /dev/null
+++ b/src/main/kotlin/gg/flyte/twilight/event/custom/admin/PlayerDeopEvent.kt
@@ -0,0 +1,32 @@
+package gg.flyte.twilight.event.custom.admin
+
+import gg.flyte.twilight.event.TwilightEvent
+import org.bukkit.Bukkit
+import org.bukkit.OfflinePlayer
+import org.bukkit.block.Block
+import org.bukkit.block.BlockFace
+import org.bukkit.entity.Player
+import org.bukkit.event.block.Action
+import org.bukkit.inventory.ItemStack
+import org.bukkit.util.Vector
+import java.util.*
+
+/**
+ * Represents an event that occurs when a player is de-op'd (de-promoted from operator status).
+ * This event contains information about the affected player's UUID and name.
+ */
+class PlayerDeopEvent(
+ val uuid: UUID, // The UUID of the player being de-op'd.
+ val name: String // The name of the player being de-op'd.
+) : TwilightEvent() {
+ /**
+ * Represents the offline player associated with this event.
+ */
+ val offlinePlayer: OfflinePlayer = Bukkit.getOfflinePlayer(uuid)
+
+ /**
+ * Represents the online player associated with this event, if available.
+ * This property will be null if the player is not currently online.
+ */
+ val player: Player? = if (offlinePlayer.isOnline) offlinePlayer.player else null
+}
\ No newline at end of file
diff --git a/src/main/kotlin/gg/flyte/twilight/event/custom/admin/PlayerOpChangeEvent.kt b/src/main/kotlin/gg/flyte/twilight/event/custom/admin/PlayerOpChangeEvent.kt
new file mode 100644
index 0000000..3cb4b7c
--- /dev/null
+++ b/src/main/kotlin/gg/flyte/twilight/event/custom/admin/PlayerOpChangeEvent.kt
@@ -0,0 +1,32 @@
+package gg.flyte.twilight.event.custom.admin
+
+import gg.flyte.twilight.event.TwilightEvent
+import org.bukkit.Bukkit
+import org.bukkit.OfflinePlayer
+import org.bukkit.block.Block
+import org.bukkit.block.BlockFace
+import org.bukkit.entity.Player
+import org.bukkit.event.block.Action
+import org.bukkit.inventory.ItemStack
+import org.bukkit.util.Vector
+import java.util.*
+
+/**
+ * Represents an event that occurs when a player's operator status changes.
+ * This event contains information about the affected player's UUID and name.
+ */
+class PlayerOpChangeEvent(
+ val uuid: UUID, // The UUID of the player whose operator status changed.
+ val name: String // The name of the player whose operator status changed.
+) : TwilightEvent() {
+ /**
+ * Represents the offline player associated with this event.
+ */
+ val offlinePlayer: OfflinePlayer = Bukkit.getOfflinePlayer(uuid)
+
+ /**
+ * Represents the online player associated with this event, if available.
+ * This property will be null if the player is not currently online.
+ */
+ val player: Player? = if (offlinePlayer.isOnline) offlinePlayer.player else null
+}
diff --git a/src/main/kotlin/gg/flyte/twilight/event/custom/admin/PlayerOpEvent.kt b/src/main/kotlin/gg/flyte/twilight/event/custom/admin/PlayerOpEvent.kt
new file mode 100644
index 0000000..3354a17
--- /dev/null
+++ b/src/main/kotlin/gg/flyte/twilight/event/custom/admin/PlayerOpEvent.kt
@@ -0,0 +1,32 @@
+package gg.flyte.twilight.event.custom.admin
+
+import gg.flyte.twilight.event.TwilightEvent
+import org.bukkit.Bukkit
+import org.bukkit.OfflinePlayer
+import org.bukkit.block.Block
+import org.bukkit.block.BlockFace
+import org.bukkit.entity.Player
+import org.bukkit.event.block.Action
+import org.bukkit.inventory.ItemStack
+import org.bukkit.util.Vector
+import java.util.*
+
+/**
+ * Represents an event that occurs when a player is op'd (promoted to operator status).
+ * This event contains information about the affected player's UUID and name.
+ */
+class PlayerOpEvent(
+ val uuid: UUID, // The UUID of the player being op'd.
+ val name: String // The name of the player being op'd.
+) : TwilightEvent() {
+ /**
+ * Represents the offline player associated with this event.
+ */
+ val offlinePlayer: OfflinePlayer = Bukkit.getOfflinePlayer(uuid)
+
+ /**
+ * Represents the online player associated with this event, if available.
+ * This property will be null if the player is not currently online.
+ */
+ val player: Player? = if (offlinePlayer.isOnline) offlinePlayer.player else null
+}
diff --git a/src/main/kotlin/gg/flyte/twilight/event/custom/admin/listener/OpEventListener.kt b/src/main/kotlin/gg/flyte/twilight/event/custom/admin/listener/OpEventListener.kt
new file mode 100644
index 0000000..57f621d
--- /dev/null
+++ b/src/main/kotlin/gg/flyte/twilight/event/custom/admin/listener/OpEventListener.kt
@@ -0,0 +1,58 @@
+package gg.flyte.twilight.event.custom.admin.listener
+
+import gg.flyte.twilight.Twilight
+import gg.flyte.twilight.event.CustomTwilightListener
+import gg.flyte.twilight.event.custom.admin.PlayerDeopEvent
+import gg.flyte.twilight.event.custom.admin.PlayerOpChangeEvent
+import gg.flyte.twilight.event.custom.admin.PlayerOpEvent
+import gg.flyte.twilight.extension.applyForEach
+import gg.flyte.twilight.gson.GSON
+import gg.flyte.twilight.scheduler.repeat
+import java.io.File
+import java.util.*
+
+object OpEventListener : CustomTwilightListener() {
+ private val opsFile = File("${Twilight.plugin.dataFolder}/../../ops.json")
+ private var opsData = mutableSetOf()
+ private var opsLastChanged: Long? = null
+
+ init {
+ if (opsFile.exists()) {
+ opsLastChanged = opsFile.lastModified()
+ opsData += getOpsData()
+ }
+
+ runnables += repeat(async = true) {
+ if (!opsFile.exists()) return@repeat cancel()
+ if (!hasOpsChanged()) return@repeat
+
+ val newOpsData = getOpsData()
+
+ // Removed ops
+ opsData.subtract(newOpsData).toSet().applyForEach {
+ opsData -= this
+ Twilight.plugin.server.pluginManager.callEvent(PlayerDeopEvent(uuid, name))
+ Twilight.plugin.server.pluginManager.callEvent(PlayerOpChangeEvent(uuid, name))
+ }
+
+ // Added ops
+ newOpsData.subtract(opsData).toSet().applyForEach {
+ opsData += this
+ Twilight.plugin.server.pluginManager.callEvent(PlayerOpEvent(uuid, name))
+ Twilight.plugin.server.pluginManager.callEvent(PlayerOpChangeEvent(uuid, name))
+ }
+ }
+ }
+
+ data class OpData(
+ val uuid: UUID,
+ val name: String,
+ val level: Int,
+ val bypassPlayerLimit: Boolean
+ )
+
+ private fun getOpsData(): Set = GSON.fromJson(opsFile.reader(), Array::class.java).toSet()
+
+ private fun hasOpsChanged(): Boolean = (opsLastChanged ?: 0) < opsFile.lastModified()
+
+}