From f73c4307ad052491a553afccd9943040063549b4 Mon Sep 17 00:00:00 2001 From: itsTyrion Date: Tue, 22 Oct 2024 02:27:49 +0200 Subject: [PATCH] :recycle: Cleanup, bugfixes, new features, dependency bugs, added about 47 new bugs to fix later Took 2 hours 0 minutes --- build.gradle | 85 ++++++++----------- gradle.properties | 1 + src/main/kotlin-templates/BuildInfo.kt.peb | 3 - .../bungee/BungeeOnlineTimePlugin.kt | 54 ++++++------ .../bungee/OnlineTimeCommand.kt | 21 +++-- .../bungee/OnlineTimeListener.kt | 12 ++- .../common/OnlineTimeCommandBase.kt | 44 ++++------ .../common/OnlineTimePlugin.kt | 45 ++++++++++ .../bungeeonlinetime/common/config/Config.kt | 25 +++--- .../common/config/ConfigLoader.kt | 39 ++++++--- .../bungeeonlinetime/common/db/Database.kt | 6 ++ .../common/db/SQLiteDatabase.kt | 4 +- .../common/utils/Messaging.kt | 42 +++++++++ .../bungeeonlinetime/common/utils/Utils.kt | 20 ----- .../velocity/OnlineTimeCommand.kt | 33 ++++--- .../velocity/OnlineTimeListener.kt | 12 ++- .../velocity/VelocityOnlineTimePlugin.kt | 62 ++++++-------- 17 files changed, 290 insertions(+), 218 deletions(-) create mode 100644 gradle.properties delete mode 100644 src/main/kotlin-templates/BuildInfo.kt.peb create mode 100644 src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/OnlineTimePlugin.kt create mode 100644 src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/utils/Messaging.kt delete mode 100644 src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/utils/Utils.kt diff --git a/build.gradle b/build.gradle index 7435747..9e5041d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,9 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - id "org.jetbrains.kotlin.jvm" version "1.9.10" - id "org.jetbrains.kotlin.kapt" version "1.9.10" - id "com.github.johnrengelman.shadow" version "8.1.1" - id "net.kyori.blossom" version "2.1.0" -} - -configurations { - bungeecord + id "org.jetbrains.kotlin.jvm" version "2.0.21" + id "org.jetbrains.kotlin.kapt" version "2.0.21" + id "com.gradleup.shadow" version "8.3.3" } repositories { @@ -21,78 +16,66 @@ repositories { name "PaperMC" url uri("https://repo.papermc.io/repository/maven-public/") } + maven { url uri("https://jitpack.io") } } dependencies { - implementation "org.xerial:sqlite-jdbc:3.40.1.0" - implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.10" - implementation "org.yaml:snakeyaml:2.0" - bungeecord "org.slf4j:slf4j-api:2.0.5" - bungeecord "org.slf4j:slf4j-simple:2.0.5" - compileOnly "org.jetbrains.kotlin:kotlin-stdlib:1.9.10" - compileOnly "net.md-5:bungeecord-api:1.20-R0.1-SNAPSHOT" - compileOnly "com.velocitypowered:velocity-api:3.2.0-SNAPSHOT" - kapt "com.velocitypowered:velocity-api:3.2.0-SNAPSHOT" + implementation "org.xerial:sqlite-jdbc:3.46.1.3" + implementation "com.mysql:mysql-connector-j:9.1.0" + implementation "org.jetbrains.kotlin:kotlin-stdlib:2.0.21" + implementation "org.yaml:snakeyaml:2.2" + implementation "org.slf4j:slf4j-api:2.0.12" + implementation "org.slf4j:slf4j-simple:2.0.12" + compileOnly "net.md-5:bungeecord-api:1.21-R0.1-SNAPSHOT" + compileOnly "com.velocitypowered:velocity-api:3.3.0-SNAPSHOT" + compileOnly "de.itsTyrion:PluginAnnotationProcessor:1.4" + kapt "de.itsTyrion:PluginAnnotationProcessor:1.4" } group = "lu.r3flexi0n" -version = "8.4.2" +version = "8.5.0" description = "BungeeOnlineTime" -tasks.withType(JavaCompile).configureEach { - options.encoding = "UTF-8" - options.release = 17 - options.deprecation true +kotlin { + jvmToolchain 17 } -sourceSets { - main.blossom.kotlinSources { - property("version", version) - } +kapt.arguments { + arg "mcPluginVersion", version } shadowJar { - minimize() { exclude(dependency("org.xerial:sqlite-jdbc")) } archiveClassifier = "" + minimize() { + exclude(dependency("org.xerial:sqlite-jdbc")) + exclude(dependency("com.mysql:mysql-connector-j")) + } - relocate "kotlin", "de.itsTyrion.shaded.kotlin" - relocate "org.yaml", "de.itsTyrion.shaded.snakeyaml" - - def sqlite = "org/sqlite/native" - exclude "$sqlite/*/ppc64/**", "$sqlite/*/arm*/**", "$sqlite/*/x86/**" // uncommon architectures for MC servers - exclude "$sqlite/Linux-*/**", "$sqlite/Mac/**", "$sqlite/FreeBSD/**" // and uncommon OS' for MC servers -} - -tasks.register("bungeecord", ShadowJar) { - from sourceSets.main.output - configurations = [project.configurations.runtimeClasspath, project.configurations.bungeecord] - archiveClassifier = "bungeecord" - minimize() { exclude(dependency("org.xerial:sqlite-jdbc")) } + mergeServiceFiles() relocate "kotlin", "de.itsTyrion.shaded.kotlin" relocate "org.yaml", "de.itsTyrion.shaded.snakeyaml" - relocate "org.slf4j", "de.itsTyrion.shaded.slf4j" - def sqlite = "org/sqlite/native" - exclude "$sqlite/*/ppc64/**", "$sqlite/*/arm*/**", "$sqlite/*/x86/**" // uncommon architectures for MC servers - exclude "$sqlite/Linux-*/**", "$sqlite/Mac/**", "$sqlite/FreeBSD/**" // and uncommon OS' for MC servers + def base = "org/sqlite/native" + exclude "$base/*/ppc64/**", "$base/*/riscv64/**", "$base/*/arm*/**", "$base/*/x86/**" // uncommon architectures for MC servers + exclude "$base/Linux-*/**", "$base/Mac/**", "$base/FreeBSD/**" // and uncommon OS' for MC servers } tasks.register("fat", ShadowJar) { from sourceSets.main.output configurations = [project.configurations.runtimeClasspath] archiveClassifier = "fat" - minimize() { exclude(dependency("org.xerial:sqlite-jdbc")) } + minimize() { + exclude(dependency("org.xerial:sqlite-jdbc")) + exclude(dependency("com.mysql:mysql-connector-j")) + } + + mergeServiceFiles() relocate "kotlin", "de.itsTyrion.shaded.kotlin" relocate "org.yaml", "de.itsTyrion.shaded.snakeyaml" - relocate "org.slf4j", "de.itsTyrion.shaded.slf4j" -} - -gradle.beforeProject { - generateTemplates } build { - dependsOn([shadowJar, bungeecord, fat]) + dependsOn([shadowJar, fat]) } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..ee12aeb --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +kapt.include.compile.classpath=false \ No newline at end of file diff --git a/src/main/kotlin-templates/BuildInfo.kt.peb b/src/main/kotlin-templates/BuildInfo.kt.peb deleted file mode 100644 index dc97c3d..0000000 --- a/src/main/kotlin-templates/BuildInfo.kt.peb +++ /dev/null @@ -1,3 +0,0 @@ -object BuildInfo { - const val VERSION: String = "{# @pebvariable name="version" type="java.lang.String" #}{{ version }}" -} \ No newline at end of file diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/BungeeOnlineTimePlugin.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/BungeeOnlineTimePlugin.kt index 5f261f2..0da57d1 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/BungeeOnlineTimePlugin.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/BungeeOnlineTimePlugin.kt @@ -1,52 +1,41 @@ package lu.r3flexi0n.bungeeonlinetime.bungee +import de.itsTyrion.pluginAnnotation.bungee.BungeePlugin +import lu.r3flexi0n.bungeeonlinetime.common.OnlineTimePlugin import lu.r3flexi0n.bungeeonlinetime.common.config.Config import lu.r3flexi0n.bungeeonlinetime.common.config.ConfigLoader import lu.r3flexi0n.bungeeonlinetime.common.db.Database -import lu.r3flexi0n.bungeeonlinetime.common.db.MySQLDatabase -import lu.r3flexi0n.bungeeonlinetime.common.db.SQLiteDatabase import lu.r3flexi0n.bungeeonlinetime.common.objects.OnlineTimePlayer -import lu.r3flexi0n.bungeeonlinetime.common.utils.Utils +import lu.r3flexi0n.bungeeonlinetime.common.utils.Messaging import net.md_5.bungee.api.plugin.Plugin import org.slf4j.Logger import org.slf4j.LoggerFactory -import java.io.File import java.io.IOException +import java.nio.file.Path import java.util.UUID import java.util.concurrent.TimeUnit -class BungeeOnlineTimePlugin : Plugin() { +@BungeePlugin(name = "BungeeOnlineTime", author = "itsTyrion, R3fleXi0n") +class BungeeOnlineTimePlugin : Plugin(), OnlineTimePlugin { - lateinit var config: Config + override lateinit var config: Config + override lateinit var database: Database + override val dataPath: Path = dataFolder.toPath() - lateinit var database: Database + override val onlineTimePlayers = HashMap() - val onlineTimePlayers = HashMap() - - val pluginMessageChannel = "bungeeonlinetime:get" - - val logger: Logger = LoggerFactory.getLogger(super.getLogger().name) + override val logger: Logger = LoggerFactory.getLogger(super.getLogger().name) override fun onEnable() { try { config = ConfigLoader.load(dataFolder.toPath(), logger) } catch (ex: IOException) { - logger.error("Error while creating or loading. Disabling plugin...", ex) + logger.error("Error while creating or loading config. Disabling plugin...", ex) return } - database = if (config.mySQL.enabled) { - MySQLDatabase(config.mySQL) - } else { - SQLiteDatabase(File(dataFolder, "BungeeOnlineTime.db")) - } - try { - logger.info("Connecting to ${database.dbName}...") - database.openConnection() - database.createTable() - database.createIndex() - logger.info("Successfully connected to ${database.dbName}") + connectDB() } catch (ex: Exception) { logger.error("Error while connecting to ${database.dbName}. Disabling plugin...", ex) return @@ -59,17 +48,24 @@ class BungeeOnlineTimePlugin : Plugin() { proxy.pluginManager.registerListener(this, OnlineTimeListener(this)) if (config.plugin.usePlaceholderApi) { - proxy.registerChannel(pluginMessageChannel) - val timerInterval = config.plugin.placeholderRefreshTimer + proxy.registerChannel(Messaging.CHANNEL_MAIN) + proxy.registerChannel(Messaging.CHANNEL_TOP) + val timerInterval = config.plugin.placeholderRefreshSeconds if (timerInterval > 0) { proxy.scheduler.schedule(this, { for (player in proxy.players) { val onlineTimePlayer = onlineTimePlayers[player.uniqueId] ?: continue - val arr = Utils.createPluginMessageArr(onlineTimePlayer, player.uniqueId) + val arr = Messaging.createMainArr(onlineTimePlayer, player.uniqueId) if (arr != null) - player.server?.sendData(pluginMessageChannel, arr) + player.server?.sendData(Messaging.CHANNEL_MAIN, arr) } - }, 0L, timerInterval.toLong(), TimeUnit.MINUTES) + + val arr = Messaging.createTopArr(this) + for ((_, server) in proxy.servers) { + server.sendData(Messaging.CHANNEL_TOP, arr) + } + + }, 0L, timerInterval.toLong(), TimeUnit.SECONDS) } } } diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/OnlineTimeCommand.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/OnlineTimeCommand.kt index 992b5b4..d04e1fc 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/OnlineTimeCommand.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/OnlineTimeCommand.kt @@ -6,15 +6,15 @@ import net.md_5.bungee.api.CommandSender import net.md_5.bungee.api.chat.TextComponent import net.md_5.bungee.api.connection.ProxiedPlayer import net.md_5.bungee.api.plugin.Command +import kotlin.math.max class OnlineTimeCommand(private val plugin: BungeeOnlineTimePlugin, cmd: String, aliases: Array) : Command(cmd, null, *aliases) { - private val config = plugin.config - private val base = OnlineTimeCommandBase(plugin.logger, plugin.config, plugin.database) { plugin.onlineTimePlayers } + private val base = OnlineTimeCommandBase(plugin) private fun checkPermission(sender: CommandSender, permission: String): Boolean { if (!sender.hasPermission(permission)) { - send(sender, config.language.noPermission) + send(sender, plugin.config.language.noPermission) return false } return true @@ -22,7 +22,7 @@ class OnlineTimeCommand(private val plugin: BungeeOnlineTimePlugin, cmd: String, override fun execute(sender: CommandSender, args: Array) { if (sender !is ProxiedPlayer) { - send(sender, config.language.onlyPlayer) + send(sender, plugin.config.language.onlyPlayer) return } val arg0 = if (args.isNotEmpty()) args[0].lowercase() else "" @@ -43,7 +43,7 @@ class OnlineTimeCommand(private val plugin: BungeeOnlineTimePlugin, cmd: String, } else if ((size == 1 || size == 2) && arg0 == "top") { if (checkPermission(sender, "onlinetime.top")) { - val page = (args[1].toIntOrNull() ?: 1).coerceAtLeast(1) + val page = if (size == 1) 1 else max(1, args[1].toIntOrNull() ?: 1) base.sendTopOnlineTimes(page) { msg, placeholders -> send(sender, msg, placeholders) } } @@ -62,8 +62,15 @@ class OnlineTimeCommand(private val plugin: BungeeOnlineTimePlugin, cmd: String, if (checkPermission(sender, "onlinetime.resetall")) base.sendResetAll { msg, placeholders -> send(sender, msg, placeholders) } + } else if (args.size == 1 && arg0 == "reload") { + + if (checkPermission(sender, "onlinetime.reload")) { + plugin.reloadConfig() + send(sender, plugin.config.language.configReloaded) + } + } else { - send(sender, config.language.help) + send(sender, plugin.config.language.help) } } @@ -75,6 +82,6 @@ class OnlineTimeCommand(private val plugin: BungeeOnlineTimePlugin, cmd: String, message = message.replace(key, value.toString()) } } - sender.sendMessage(*TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&', message))) + sender.sendMessage(TextComponent.fromLegacy(ChatColor.translateAlternateColorCodes('&', message))) } } \ No newline at end of file diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/OnlineTimeListener.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/OnlineTimeListener.kt index 9349da8..d4f8ed9 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/OnlineTimeListener.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/bungee/OnlineTimeListener.kt @@ -1,7 +1,7 @@ package lu.r3flexi0n.bungeeonlinetime.bungee import lu.r3flexi0n.bungeeonlinetime.common.objects.OnlineTimePlayer -import lu.r3flexi0n.bungeeonlinetime.common.utils.Utils +import lu.r3flexi0n.bungeeonlinetime.common.utils.Messaging import lu.r3flexi0n.bungeeonlinetime.common.utils.asyncTask import net.md_5.bungee.api.event.PlayerDisconnectEvent import net.md_5.bungee.api.event.PostLoginEvent @@ -41,9 +41,13 @@ class OnlineTimeListener(private val plugin: BungeeOnlineTimePlugin) : Listener } else { onlineTimePlayer.leaveDisabledServer() } - if (usePlaceholderApi && onlineTimePlayer.savedOnlineTime != null) { - val arr = Utils.createPluginMessageArr(onlineTimePlayer, player.uniqueId) - server.sendData(plugin.pluginMessageChannel, arr) + if (usePlaceholderApi) { + if (onlineTimePlayer.savedOnlineTime != null) { + val arr = Messaging.createMainArr(onlineTimePlayer, player.uniqueId) + server.sendData(Messaging.CHANNEL_MAIN, arr) + } + val arr = Messaging.createTopArr(plugin) + server.sendData(Messaging.CHANNEL_TOP, arr) } } diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/OnlineTimeCommandBase.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/OnlineTimeCommandBase.kt index 3079dba..17b4708 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/OnlineTimeCommandBase.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/OnlineTimeCommandBase.kt @@ -1,25 +1,15 @@ package lu.r3flexi0n.bungeeonlinetime.common -import lu.r3flexi0n.bungeeonlinetime.common.config.Config -import lu.r3flexi0n.bungeeonlinetime.common.db.Database -import lu.r3flexi0n.bungeeonlinetime.common.objects.OnlineTimePlayer import lu.r3flexi0n.bungeeonlinetime.common.utils.asyncTask -import org.slf4j.Logger import java.time.Duration -import java.util.UUID import java.util.function.BiConsumer -import java.util.function.Supplier -class OnlineTimeCommandBase( - private val logger: Logger, - private val config: Config, - private val database: Database, - private val onlineTimePlayers: Supplier> -) { +class OnlineTimeCommandBase(private val plugin: OnlineTimePlugin) { + private val config get() = plugin.config fun sendOnlineTime(targetPlayerName: String, sendMessage: BiConsumer?>) { asyncTask(doTask = { - database.getOnlineTime(targetPlayerName) + plugin.database.getOnlineTime(targetPlayerName) }, onSuccess = { response -> if (response.isEmpty()) { @@ -27,28 +17,28 @@ class OnlineTimeCommandBase( sendMessage.accept(config.language.playerNotFound, placeholders) } else { for (onlineTime in response) { - val sessionTime = onlineTimePlayers.get()[onlineTime.uuid]?.getSessionOnlineTime() ?: 0 + val sessionTime = plugin.onlineTimePlayers[onlineTime.uuid]?.getSessionOnlineTime() ?: 0 val total = Duration.ofMillis(onlineTime.time + sessionTime) val placeholders = mapOf(//@formatter:off "%PLAYER%" to onlineTime.name, - "%HOURS%" to total.toHours() % 24, - "%MINUTES%" to total.toMinutes() % 60 + "%HOURS%" to total.toHours(), + "%MINUTES%" to total.toMinutesPart() )//@formatter:on sendMessage.accept(config.language.onlineTime, placeholders) } } }, onError = { e -> sendMessage.accept(config.language.error, emptyMap()) - logger.error("Error while loading online time for player $targetPlayerName.", e) + plugin.logger.error("Error while loading online time for player $targetPlayerName.", e) }) } fun sendTopOnlineTimes(page: Int, sendMessage: BiConsumer?>) { val topOnlineTimePageLimit = config.plugin.topOnlineTimePageLimit asyncTask(doTask = { - database.getTopOnlineTimes(page, topOnlineTimePageLimit) + plugin.database.getTopOnlineTimes(page, topOnlineTimePageLimit) }, onSuccess = { response -> var rank = (page - 1) * topOnlineTimePageLimit + 1 @@ -56,15 +46,15 @@ class OnlineTimeCommandBase( sendMessage.accept(config.language.topTimeAbove, headerPlaceholders) for (onlineTime in response) { - val sessionTime = onlineTimePlayers.get()[onlineTime.uuid]?.getSessionOnlineTime() ?: 0 + val sessionTime = plugin.onlineTimePlayers[onlineTime.uuid]?.getSessionOnlineTime() ?: 0 val total = Duration.ofMillis(onlineTime.time + sessionTime) val placeholders = mapOf(//@formatter:off "%RANK%" to rank, "%PLAYER%" to onlineTime.name, - "%HOURS%" to total.toHours() % 24, - "%MINUTES%" to total.toMinutes() % 60 + "%HOURS%" to total.toHours(), + "%MINUTES%" to total.toMinutesPart() )//@formatter:on sendMessage.accept(config.language.topTime, placeholders) rank++ @@ -72,30 +62,30 @@ class OnlineTimeCommandBase( sendMessage.accept(config.language.topTimeBelow, headerPlaceholders) }, onError = { e -> sendMessage.accept(config.language.error, null) - logger.error("Error while loading top online times.", e) + plugin.logger.error("Error while loading top online times.", e) }) } fun sendReset(targetPlayerName: String, sendMessage: BiConsumer?>) { asyncTask(doTask = { - database.resetOnlineTime(targetPlayerName) + plugin.database.resetOnlineTime(targetPlayerName) }, onSuccess = { sendMessage.accept(config.language.resetPlayer, mapOf("%PLAYER%" to targetPlayerName)) }, onError = { e -> sendMessage.accept(config.language.error, emptyMap()) - logger.error("Error while resetting online time for player $targetPlayerName.", e) + plugin.logger.error("Error while resetting online time for player $targetPlayerName.", e) }) } fun sendResetAll(sendMessage: BiConsumer?>) { asyncTask(doTask = { - database.resetAllOnlineTimes() - onlineTimePlayers.get().forEach { (_, value) -> value.setSavedOnlineTime(0L) } + plugin.database.resetAllOnlineTimes() + plugin.onlineTimePlayers.forEach { (_, value) -> value.setSavedOnlineTime(0L) } }, onSuccess = { sendMessage.accept(config.language.resetAll, emptyMap()) }, onError = { e -> sendMessage.accept(config.language.error, emptyMap()) - logger.error("Error while resetting online time database.", e) + plugin.logger.error("Error while resetting online time database.", e) }) } } \ No newline at end of file diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/OnlineTimePlugin.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/OnlineTimePlugin.kt new file mode 100644 index 0000000..639b83c --- /dev/null +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/OnlineTimePlugin.kt @@ -0,0 +1,45 @@ +package lu.r3flexi0n.bungeeonlinetime.common + +import lu.r3flexi0n.bungeeonlinetime.common.config.Config +import lu.r3flexi0n.bungeeonlinetime.common.config.ConfigLoader +import lu.r3flexi0n.bungeeonlinetime.common.db.Database +import lu.r3flexi0n.bungeeonlinetime.common.db.MySQLDatabase +import lu.r3flexi0n.bungeeonlinetime.common.db.SQLiteDatabase +import lu.r3flexi0n.bungeeonlinetime.common.objects.OnlineTimePlayer +import org.slf4j.Logger +import java.io.IOException +import java.nio.file.Path +import java.util.UUID + +interface OnlineTimePlugin { + var database: Database + val onlineTimePlayers: HashMap + val logger: Logger + var config: Config + val dataPath: Path + + fun reloadConfig() { + try { + config = ConfigLoader.load(dataPath, logger) + } catch (ex: IOException) { + logger.error("Error while loading config.", ex) + return + } + database.close() + + connectDB() + } + + fun connectDB() { + database = if (config.mySQL.enabled) { + MySQLDatabase(config.mySQL) + } else { + SQLiteDatabase(dataPath.resolve("BungeeOnlineTime.db")) + } + logger.info("Connecting to ${database.dbName}...") + database.openConnection() + database.createTable() + database.createIndex() + logger.info("Successfully connected to ${database.dbName}") + } +} diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/config/Config.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/config/Config.kt index 29a5810..9269821 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/config/Config.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/config/Config.kt @@ -7,10 +7,10 @@ class Config { @JvmField var mySQL = MySQL() - @Suppress("PropertyName", "SpellCheckingInspection") // mb lemme use quotes in a variable name real quick - var version_dont_touch = 1 + @Suppress("PropertyName") + var version_dont_touch = CURRENT_VERSION - class Language { + class Language { // @formatter:on var help = """ &7Usage: &7/onlinetime @@ -19,16 +19,17 @@ class Config { &7/onlinetime reset &7/onlinetime resetall """.trimIndent() // @formatter:off - var resetAll = "&7The database has been reset." - var playerNotFound = "&7Player '&6%PLAYER%&7' was not found." + var resetAll = "&bThe database has been reset." + var playerNotFound = "&cPlayer '&6%PLAYER%&c' was not found." var topTimeAbove = "&7====== &6Top 10 &7======" var onlineTime = "&6%PLAYER%&7's onlinetime: &6%HOURS%&7h &6%MINUTES%&7min" var topTimeBelow = "&7====== &6Page %PAGE% &7======" - var noPermission = "&7You do not have access to this command." + var noPermission = "&cYou do not have access to this command." var topTime = "&7#%RANK% &6%PLAYER%&7: &6%HOURS%&7h &6%MINUTES%&7min" - var error = "&7An error occurred." - var onlyPlayer = "&7This command can only be executed by players." - var resetPlayer = "&6%PLAYER%&7's onlinetime has been reset." + var error = "&cAn error occurred." + var onlyPlayer = "&cThis command can only be executed by players." + var resetPlayer = "&6%PLAYER%&b's onlinetime has been reset." + var configReloaded = "&bThe config has been reloaded. A restart is still recommended." } // @formatter:on class Plugin { @@ -36,7 +37,9 @@ class Config { var disabledServers = mutableListOf("lobby-1", "lobby-2") var usePlaceholderApi = false var topOnlineTimePageLimit = 10 - var placeholderRefreshTimer = 1 + @Deprecated("Replaced. Minutes -> Seconds", ReplaceWith("placeholderRefreshSeconds")) + var placeholderRefreshTimer = Int.MIN_VALUE + var placeholderRefreshSeconds = 60 } class MySQL { // @formatter:off @@ -49,6 +52,6 @@ class Config { } // @formatter:on companion object { - const val CURRENT_VERSION = 1 + const val CURRENT_VERSION = 2 } } \ No newline at end of file diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/config/ConfigLoader.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/config/ConfigLoader.kt index 3bf87f7..3521dc4 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/config/ConfigLoader.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/config/ConfigLoader.kt @@ -2,7 +2,10 @@ package lu.r3flexi0n.bungeeonlinetime.common.config import org.slf4j.Logger import org.yaml.snakeyaml.DumperOptions +import org.yaml.snakeyaml.DumperOptions.FlowStyle +import org.yaml.snakeyaml.TypeDescription import org.yaml.snakeyaml.Yaml +import org.yaml.snakeyaml.nodes.Tag import org.yaml.snakeyaml.representer.Representer import java.nio.file.Path import kotlin.io.path.* @@ -12,32 +15,44 @@ object ConfigLoader { fun load(dataFolderPath: Path, logger: Logger): Config { dataFolderPath.createDirectories() val settingsPath = dataFolderPath.resolve("settings.yml") - val yaml = Yaml(BlockRepresenter()) if (!settingsPath.exists()) { settingsPath.createFile() - save(Config(), yaml, settingsPath) + save(Config(), settingsPath) logger.warn("No config file was found, default config was created.") } settingsPath.inputStream().use { input -> - val config = yaml.loadAs(input, Config::class.java) + val config = Yaml().loadAs(input, Config::class.java) if (config.version_dont_touch < Config.CURRENT_VERSION) { - config.version_dont_touch = Config.CURRENT_VERSION - save(config, yaml, settingsPath) + migrateConfig(config) + save(config, settingsPath) logger.warn("New config version, please check new values and change if/as needed.") } return config } } - private fun save(config: Config, yaml: Yaml, settingsPath: Path) { - val dumped = yaml.dump(config) - settingsPath.bufferedWriter().use { it.write(dumped.substringAfter('\n')) } + @Suppress("DEPRECATION") + private fun migrateConfig(config: Config) { + if (config.version_dont_touch == 1) { + config.plugin.placeholderRefreshSeconds = config.plugin.placeholderRefreshTimer * 60 + } + config.version_dont_touch = Config.CURRENT_VERSION } - internal class BlockRepresenter : Representer(DumperOptions()) { - init { - setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK) - } + private fun save(config: Config, settingsPath: Path) { + val representer = Representer(DumperOptions()) + representer.defaultFlowStyle = FlowStyle.BLOCK + + val typeDescription = TypeDescription(Config.Plugin::class.java) + typeDescription.setExcludes("placeholderRefreshTimer") + representer.addTypeDescription(typeDescription) + // To disable the tag with class name + representer.addClassTag(Config.Plugin::class.java, Tag.MAP) + representer.addClassTag(Config::class.java, Tag.MAP) + + val yaml = Yaml(representer) + + settingsPath.bufferedWriter().use { it.write(yaml.dump(config)) } } } \ No newline at end of file diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/db/Database.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/db/Database.kt index 0035a95..0869389 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/db/Database.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/db/Database.kt @@ -4,6 +4,7 @@ import lu.r3flexi0n.bungeeonlinetime.common.objects.OnlineTime import java.sql.* import java.util.* +@Suppress("SqlNoDataSourceInspection") abstract class Database(val dbName: String, private val dbClass: Array, private val dbURL: String) { var dbProperties = Properties(3) @@ -35,6 +36,11 @@ abstract class Database(val dbName: String, private val dbClass: Array, con.createStatement().use { it.executeUpdate(sql) } } + fun close() { + if (::con.isInitialized) + con.close() + } + @Throws(SQLException::class) abstract fun createIndex() diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/db/SQLiteDatabase.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/db/SQLiteDatabase.kt index a28318f..9332271 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/db/SQLiteDatabase.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/db/SQLiteDatabase.kt @@ -1,8 +1,8 @@ package lu.r3flexi0n.bungeeonlinetime.common.db -import java.io.File +import java.nio.file.Path -class SQLiteDatabase(file: File) : Database("SQLite", arrayOf("org.sqlite.JDBC"), "jdbc:sqlite:" + file.path) { +class SQLiteDatabase(path: Path) : Database("SQLite", arrayOf("org.sqlite.JDBC"), "jdbc:sqlite:$path") { override fun createIndex() { con.createStatement().use { st -> diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/utils/Messaging.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/utils/Messaging.kt new file mode 100644 index 0000000..461f4ed --- /dev/null +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/utils/Messaging.kt @@ -0,0 +1,42 @@ +package lu.r3flexi0n.bungeeonlinetime.common.utils + +import lu.r3flexi0n.bungeeonlinetime.common.OnlineTimePlugin +import lu.r3flexi0n.bungeeonlinetime.common.objects.OnlineTimePlayer +import java.io.ByteArrayOutputStream +import java.io.DataOutputStream +import java.util.UUID + +object Messaging { + const val CHANNEL_MAIN = "bungeeonlinetime:get" + const val CHANNEL_TOP = "bungeeonlinetime:top" + + fun createMainArr(otp: OnlineTimePlayer, uuid: UUID): ByteArray? { + val savedOnlineTime = otp.savedOnlineTime ?: return null + val totalOnlineTime = savedOnlineTime + otp.getSessionOnlineTime() + + val baos = ByteArrayOutputStream() + val data = DataOutputStream(baos) + data.writeUTF(uuid.toString()) + data.writeLong(totalOnlineTime / 1000L) + return baos.toByteArray() + } + + fun createTopArr(plugin: OnlineTimePlugin): ByteArray { + val top = plugin.database.getTopOnlineTimes(1, 1).firstOrNull() + val baos = ByteArrayOutputStream() + val data = DataOutputStream(baos) + if (top == null) { + data.writeUTF("") + data.writeLong(0L) + } else { + val otp = plugin.onlineTimePlayers[top.uuid] + val totalOnlineTime = if (otp?.savedOnlineTime != null) { + otp.savedOnlineTime!! + otp.getSessionOnlineTime() + } else + top.time + data.writeUTF(top.name) + data.writeLong(totalOnlineTime / 1000L) + } + return baos.toByteArray() + } +} \ No newline at end of file diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/utils/Utils.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/utils/Utils.kt deleted file mode 100644 index 444230f..0000000 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/common/utils/Utils.kt +++ /dev/null @@ -1,20 +0,0 @@ -package lu.r3flexi0n.bungeeonlinetime.common.utils - -import lu.r3flexi0n.bungeeonlinetime.common.objects.OnlineTimePlayer -import java.io.ByteArrayOutputStream -import java.io.DataOutputStream -import java.util.UUID - -object Utils { - - fun createPluginMessageArr(otp: OnlineTimePlayer, uuid: UUID): ByteArray? { - val savedOnlineTime = otp.savedOnlineTime ?: return null - val totalOnlineTime = savedOnlineTime + otp.getSessionOnlineTime() - - val baos = ByteArrayOutputStream() - val data = DataOutputStream(baos) - data.writeUTF(uuid.toString()) - data.writeLong(totalOnlineTime / 1000) - return baos.toByteArray() - } -} \ No newline at end of file diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/OnlineTimeCommand.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/OnlineTimeCommand.kt index a8be7c9..3f4da09 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/OnlineTimeCommand.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/OnlineTimeCommand.kt @@ -9,12 +9,11 @@ import kotlin.math.max class OnlineTimeCommand(private val plugin: VelocityOnlineTimePlugin) : SimpleCommand { - private val config = plugin.config - private val base = OnlineTimeCommandBase(plugin.logger, plugin.config, plugin.database) { plugin.onlineTimePlayers } + private val base = OnlineTimeCommandBase(plugin) private fun checkPermission(sender: CommandSource, permission: String): Boolean { if (!sender.hasPermission(permission)) { - sendMessage(sender, config.language.noPermission) + send(sender, plugin.config.language.noPermission) return false } return true @@ -23,7 +22,7 @@ class OnlineTimeCommand(private val plugin: VelocityOnlineTimePlugin) : SimpleCo override fun execute(invocation: SimpleCommand.Invocation) { val sender = invocation.source() if (sender !is Player) { - sendMessage(sender, config.language.onlyPlayer) + send(sender, plugin.config.language.onlyPlayer) return } val args = invocation.arguments() @@ -32,29 +31,28 @@ class OnlineTimeCommand(private val plugin: VelocityOnlineTimePlugin) : SimpleCo if (size == 0) { if (checkPermission(sender, "onlinetime.own")) { - val name = sender.username - base.sendOnlineTime(name) { msg, placeholders -> sendMessage(sender, msg, placeholders) } + base.sendOnlineTime(sender.username) { msg, placeholders -> send(sender, msg, placeholders) } } } else if (size == 2 && arg0 == "get") { if (checkPermission(sender, "onlinetime.others")) { val name = args[1] - base.sendOnlineTime(name) { msg, placeholders -> sendMessage(sender, msg, placeholders) } + base.sendOnlineTime(name) { msg, placeholders -> send(sender, msg, placeholders) } } } else if ((size == 1 || size == 2) && arg0 == "top") { if (checkPermission(sender, "onlinetime.top")) { - val page = max(args[1].toIntOrNull() ?: 1, 1) - base.sendTopOnlineTimes(page) { msg, placeholders -> sendMessage(sender, msg, placeholders) } + val page = if (size == 1) 1 else max(1, args[1].toIntOrNull() ?: 1) + base.sendTopOnlineTimes(page) { msg, placeholders -> send(sender, msg, placeholders) } } } else if (args.size == 2 && arg0 == "reset") { if (checkPermission(sender, "onlinetime.reset")) { val name = args[1] - base.sendReset(name) { msg, placeholders -> sendMessage(sender, msg, placeholders) } + base.sendReset(name) { msg, placeholders -> send(sender, msg, placeholders) } plugin.proxy.getPlayer(name) .ifPresent { plugin.onlineTimePlayers[it.uniqueId]?.setSavedOnlineTime(0L) } } @@ -62,14 +60,21 @@ class OnlineTimeCommand(private val plugin: VelocityOnlineTimePlugin) : SimpleCo } else if (args.size == 1 && arg0 == "resetall") { if (checkPermission(sender, "onlinetime.resetall")) - base.sendResetAll { msg, placeholders -> sendMessage(sender, msg, placeholders) } + base.sendResetAll { msg, placeholders -> send(sender, msg, placeholders) } - } else { - sendMessage(sender, config.language.help) + } else if (args.size == 1 && arg0 == "reload") { + + if (checkPermission(sender, "onlinetime.reload")) { + plugin.reloadConfig() + send(sender, plugin.config.language.configReloaded) + } + + } else { + send(sender, plugin.config.language.help) } } - private fun sendMessage(sender: CommandSource, messageId: String, placeholders: Map? = null) { + private fun send(sender: CommandSource, messageId: String, placeholders: Map? = null) { var message = messageId if (placeholders != null) { for ((key, value) in placeholders) { diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/OnlineTimeListener.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/OnlineTimeListener.kt index 9d9ba6e..1869b52 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/OnlineTimeListener.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/OnlineTimeListener.kt @@ -5,7 +5,7 @@ import com.velocitypowered.api.event.connection.DisconnectEvent import com.velocitypowered.api.event.connection.PostLoginEvent import com.velocitypowered.api.event.player.ServerPostConnectEvent import lu.r3flexi0n.bungeeonlinetime.common.objects.OnlineTimePlayer -import lu.r3flexi0n.bungeeonlinetime.common.utils.Utils +import lu.r3flexi0n.bungeeonlinetime.common.utils.Messaging import lu.r3flexi0n.bungeeonlinetime.common.utils.asyncTask class OnlineTimeListener(private val plugin: VelocityOnlineTimePlugin) { @@ -45,9 +45,13 @@ class OnlineTimeListener(private val plugin: VelocityOnlineTimePlugin) { } else { onlineTimePlayer.leaveDisabledServer() } - if (usePlaceholderApi && onlineTimePlayer.savedOnlineTime != null) { - val arr = Utils.createPluginMessageArr(onlineTimePlayer, player.uniqueId) - server.sendPluginMessage(plugin.pluginMessageChannel, arr) + if (usePlaceholderApi) { + if (onlineTimePlayer.savedOnlineTime != null) { + val arr = Messaging.createMainArr(onlineTimePlayer, player.uniqueId)!! + server.sendPluginMessage(plugin.pluginMessageChannelMain, arr) + } + val arr = Messaging.createTopArr(plugin) + server.sendPluginMessage(plugin.pluginMessageChannelTop, arr) } } diff --git a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/VelocityOnlineTimePlugin.kt b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/VelocityOnlineTimePlugin.kt index 4b54c24..be37053 100644 --- a/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/VelocityOnlineTimePlugin.kt +++ b/src/main/kotlin/lu/r3flexi0n/bungeeonlinetime/velocity/VelocityOnlineTimePlugin.kt @@ -3,62 +3,49 @@ package lu.r3flexi0n.bungeeonlinetime.velocity import com.google.inject.Inject import com.velocitypowered.api.event.Subscribe import com.velocitypowered.api.event.proxy.ProxyInitializeEvent -import com.velocitypowered.api.plugin.Plugin import com.velocitypowered.api.plugin.annotation.DataDirectory import com.velocitypowered.api.proxy.ProxyServer -import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier +import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier +import de.itsTyrion.pluginAnnotation.velocity.VelocityPlugin +import lu.r3flexi0n.bungeeonlinetime.common.OnlineTimePlugin import lu.r3flexi0n.bungeeonlinetime.common.config.Config import lu.r3flexi0n.bungeeonlinetime.common.config.ConfigLoader import lu.r3flexi0n.bungeeonlinetime.common.db.Database -import lu.r3flexi0n.bungeeonlinetime.common.db.MySQLDatabase -import lu.r3flexi0n.bungeeonlinetime.common.db.SQLiteDatabase import lu.r3flexi0n.bungeeonlinetime.common.objects.OnlineTimePlayer -import lu.r3flexi0n.bungeeonlinetime.common.utils.Utils +import lu.r3flexi0n.bungeeonlinetime.common.utils.Messaging import org.slf4j.Logger -import java.io.File import java.io.IOException import java.nio.file.Path import java.util.UUID import java.util.concurrent.TimeUnit -@Plugin(id = "onlinetime", name = "OnlineTime", version = BuildInfo.VERSION, authors = ["itsTyrion", "r3flexi0n"]) +@VelocityPlugin(id = "onlinetime", name = "OnlineTime", authors = ["itsTyrion", "r3flexi0n"]) class VelocityOnlineTimePlugin @Inject constructor( val proxy: ProxyServer, - val logger: Logger, - @DataDirectory val dataFolder: Path -) { + override val logger: Logger, + @DataDirectory override val dataPath: Path +) : OnlineTimePlugin { - lateinit var config: Config + override lateinit var config: Config + override lateinit var database: Database - lateinit var database: Database + override val onlineTimePlayers = HashMap() - val onlineTimePlayers = HashMap() - - val pluginMessageChannel = MinecraftChannelIdentifier.from("bungeeonlinetime:get")!! + val pluginMessageChannelMain = LegacyChannelIdentifier(Messaging.CHANNEL_MAIN) + val pluginMessageChannelTop = LegacyChannelIdentifier(Messaging.CHANNEL_TOP) @Subscribe fun onEnable(@Suppress("unused_parameter") e: ProxyInitializeEvent) { try { - config = ConfigLoader.load(dataFolder, logger) + config = ConfigLoader.load(dataPath, logger) } catch (ex: IOException) { logger.error("Error while creating or loading. Disabling plugin...", ex) return } - database = if (config.mySQL.enabled) { - MySQLDatabase(config.mySQL) - } else { - val databaseFile = File(dataFolder.toFile(), "BungeeOnlineTime.db") - SQLiteDatabase(databaseFile) - } - try { - logger.info("Connecting to ${database.dbName}...") - database.openConnection() - database.createTable() - database.createIndex() - logger.info("Successfully connected to ${database.dbName}") + connectDB() } catch (ex: Exception) { logger.error("Error while connecting to ${database.dbName}. Disabling plugin...") ex.printStackTrace() @@ -68,21 +55,28 @@ class VelocityOnlineTimePlugin @Inject constructor( val commandAliases = config.plugin.commandAliases val command = OnlineTimeCommand(this) - proxy.commandManager.register(commandAliases[0], command, *commandAliases) + val cmdMgr = proxy.commandManager + cmdMgr.register(cmdMgr.metaBuilder(commandAliases[0]).aliases(*commandAliases).plugin(this).build(), command) proxy.eventManager.register(this, OnlineTimeListener(this)) if (config.plugin.usePlaceholderApi) { - proxy.channelRegistrar.register(pluginMessageChannel) - val timerInterval = config.plugin.placeholderRefreshTimer + proxy.channelRegistrar.register(pluginMessageChannelMain, pluginMessageChannelTop) + val timerInterval = config.plugin.placeholderRefreshSeconds if (timerInterval > 0) { proxy.scheduler.buildTask(this) { -> for (player in proxy.allPlayers) { val onlineTimePlayer = onlineTimePlayers[player.uniqueId] ?: continue - val arr = Utils.createPluginMessageArr(onlineTimePlayer, player.uniqueId) + val arr = Messaging.createMainArr(onlineTimePlayer, player.uniqueId) if (arr != null) - player.currentServer.ifPresent { it.sendPluginMessage(pluginMessageChannel, arr) } + player.currentServer.ifPresent { it.sendPluginMessage(pluginMessageChannelMain, arr) } } - }.repeat(timerInterval.toLong(), TimeUnit.MINUTES).schedule() + + val arr = Messaging.createTopArr(this) + for (server in proxy.allServers) { + server.sendPluginMessage(pluginMessageChannelTop, arr) + } + + }.repeat(timerInterval.toLong(), TimeUnit.SECONDS).schedule() } } }