From 1871475a225006578bb904ef2b62ac8220616246 Mon Sep 17 00:00:00 2001 From: Atrius Date: Mon, 1 Jun 2026 22:50:12 -0400 Subject: [PATCH] chore: Improve bStats tracking and move metrics to a dedicated module --- .../kotlin/xyz/atrius/waystones/Waystones.kt | 2 + .../atrius/waystones/config/DatabaseModule.kt | 9 - .../atrius/waystones/config/MetricsModule.kt | 158 ++++++++++++++++++ .../waystones/config/WaystonesModule.kt | 9 - 4 files changed, 160 insertions(+), 18 deletions(-) create mode 100644 src/main/kotlin/xyz/atrius/waystones/config/MetricsModule.kt diff --git a/src/main/kotlin/xyz/atrius/waystones/Waystones.kt b/src/main/kotlin/xyz/atrius/waystones/Waystones.kt index 993c0047..6f93d9d5 100644 --- a/src/main/kotlin/xyz/atrius/waystones/Waystones.kt +++ b/src/main/kotlin/xyz/atrius/waystones/Waystones.kt @@ -1,5 +1,6 @@ package xyz.atrius.waystones +import org.bstats.bukkit.Metrics import org.koin.core.annotation.KoinApplication import org.koin.dsl.module import org.koin.plugin.module.dsl.startKoin @@ -31,6 +32,7 @@ open class Waystones : KotlinPlugin() { modules(defaultModule()) } koin.koin.get().enable(this) + koin.koin.get() } override fun onDisable() { diff --git a/src/main/kotlin/xyz/atrius/waystones/config/DatabaseModule.kt b/src/main/kotlin/xyz/atrius/waystones/config/DatabaseModule.kt index ccf5920c..8f8dcad6 100644 --- a/src/main/kotlin/xyz/atrius/waystones/config/DatabaseModule.kt +++ b/src/main/kotlin/xyz/atrius/waystones/config/DatabaseModule.kt @@ -1,7 +1,5 @@ package xyz.atrius.waystones.config -import org.bstats.bukkit.Metrics -import org.bstats.charts.SimplePie import org.flywaydb.core.Flyway import org.koin.core.annotation.Module import org.koin.core.annotation.Provided @@ -16,7 +14,6 @@ object DatabaseModule { @Single fun getDatabaseConfiguration( @Provided plugin: KotlinPlugin, - @Provided metrics: Metrics, ): DatabaseProperties { logger.info("Attempting to load database configuration...") @@ -26,12 +23,6 @@ object DatabaseModule { val database = config .getString("type") .bindAsEnum() - // Track database type usage - metrics.addCustomChart( - SimplePie("database_type") { - database.description - } - ) return DatabaseProperties( type = database, diff --git a/src/main/kotlin/xyz/atrius/waystones/config/MetricsModule.kt b/src/main/kotlin/xyz/atrius/waystones/config/MetricsModule.kt new file mode 100644 index 00000000..bb36a819 --- /dev/null +++ b/src/main/kotlin/xyz/atrius/waystones/config/MetricsModule.kt @@ -0,0 +1,158 @@ +package xyz.atrius.waystones.config + +import org.bstats.bukkit.Metrics +import org.bstats.charts.AdvancedPie +import org.bstats.charts.DrilldownPie +import org.bstats.charts.SimpleBarChart +import org.bstats.charts.SimplePie +import org.bstats.charts.SingleLineChart +import org.bukkit.Material +import org.koin.core.annotation.Module +import org.koin.core.annotation.Provided +import org.koin.core.annotation.Single +import xyz.atrius.waystones.data.config.property.type.Power +import xyz.atrius.waystones.internal.KotlinPlugin +import xyz.atrius.waystones.manager.ConfigManager +import xyz.atrius.waystones.repository.WaystoneInfoRepository +import xyz.atrius.waystones.utility.bindAsEnum +import java.util.Locale +import java.util.concurrent.TimeUnit + +@Module +object MetricsModule { + + const val BSTATS_PLUGIN_ID: Int = 29245 + + private val playerCountSplits = splitsOf(5, 20, 50, 100, 200) + private val maxPlayersSplits = splitsOf(10, 25, 50, 100, 200, 500) + private val worldCountSplits = splitsOf(3, 6, 10, 20) + private val baseDistanceSplits = splitsOf(49, 99, 199, 499, 999) + private val maxBoostSplits = splitsOf(24, 49, 99, 149, 249) + private val maxWarpSizeSplits = splitsOf(24, 49, 99, 199) + private val waystoneCountSplits = splitsOf(25, 50, 100, 200, 500) + + @Single + fun metrics( + @Provided plugin: KotlinPlugin, + @Provided configManager: ConfigManager, + @Provided waystoneInfoRepository: WaystoneInfoRepository, + ): Metrics = Metrics(plugin, BSTATS_PLUGIN_ID).apply { + addCustomChart(SimplePie("database_type") { + plugin.config + .getString("type") + .bindAsEnum() + .description + }) + + addCustomChart(SimplePie("power_mode") { + configManager + .getPropertyOrNull("require-power") + ?.value() + ?.toString() + ?: "INTER_DIMENSION" + }) + + addCustomChart(SimplePie("fallback_locale") { + configManager + .getPropertyOrNull("fallback-locale") + ?.value() + ?.getDisplayLanguage(Locale.ENGLISH) + ?: "English" + }) + + addCustomChart(SimpleBarChart("feature_adoption") { + mapOf( + "Portal Sickness" to configManager.booleanFlag("enable-portal-sickness"), + "Single-Use Keys" to configManager.booleanFlag("single-use"), + "Uses Custom Recipe" to configManager.customRecipeFlag("key-recipe"), + ) + }) + + addCustomChart(DrilldownPie("player_count") { + drilldown(plugin.server.onlinePlayers.size, playerCountSplits) + }) + + addCustomChart(DrilldownPie("max_players") { + drilldown(plugin.server.maxPlayers, maxPlayersSplits) + }) + + addCustomChart(DrilldownPie("world_count") { + drilldown(plugin.server.worlds.size, worldCountSplits) + }) + + addCustomChart(DrilldownPie("base_distance") { + drilldown(configManager.intProperty("base-distance"), baseDistanceSplits) + }) + + addCustomChart(DrilldownPie("max_boost") { + drilldown(configManager.intProperty("max-boost"), maxBoostSplits) + }) + + addCustomChart(DrilldownPie("max_warp_size") { + drilldown(configManager.intProperty("max-warp-size"), maxWarpSizeSplits) + }) + + addCustomChart(AdvancedPie("world_environments") { + plugin.server.worlds + .groupBy { it.environment.name } + .mapValues { it.value.size } + }) + + addCustomChart(SingleLineChart("waystone_count") { + waystoneInfoRepository.entries().get(1, TimeUnit.SECONDS) + }) + + addCustomChart(DrilldownPie("waystone_count_bucketed") { + drilldown(waystoneInfoRepository.entries().get(1, TimeUnit.SECONDS), waystoneCountSplits) + }) + } + + private class Splits(private val points: IntArray) { + + fun resolve(value: Int): String { + for (i in points.indices) { + // Skip all buckets where the current end point is less than the input value + if (value > points[i]) { + continue + } + // Cap lower end at 0, otherwise get the value of the previous point in line and add 1 + val start = when { + i <= 0 -> 0 + else -> points[i - 1] + 1 + } + // Get the value of the current point and construct the range + return "$start-${points[i]}" + } + // Default case, anything over the max of all buckets + return "${points.last() + 1}+" + } + } + + private fun splitsOf(vararg points: Int) = Splits(intArrayOf(*points)) + + private fun drilldown(value: Int, splits: Splits): Map> = + mapOf(splits.resolve(value) to mapOf(value.toString() to 1)) + + private fun ConfigManager.booleanFlag(key: String): Int = when ( + getPropertyOrNull(key)?.value() + ) { + true -> 1 + else -> 0 + } + + private fun ConfigManager.intProperty(key: String): Int = + getPropertyOrNull(key) + ?.value() + ?: 0 + + private fun ConfigManager.customRecipeFlag(key: String): Int { + val prop = getListPropertyOrNull>(key) + ?: return 0 + // If the lists have equality, then its assumed the recipe has not changed + if (prop.value() == prop.default) { + return 0 + } + + return 1 + } +} diff --git a/src/main/kotlin/xyz/atrius/waystones/config/WaystonesModule.kt b/src/main/kotlin/xyz/atrius/waystones/config/WaystonesModule.kt index 0e76861d..652c32d6 100644 --- a/src/main/kotlin/xyz/atrius/waystones/config/WaystonesModule.kt +++ b/src/main/kotlin/xyz/atrius/waystones/config/WaystonesModule.kt @@ -3,19 +3,14 @@ package xyz.atrius.waystones.config import com.google.gson.FieldNamingPolicy import com.google.gson.Gson import com.google.gson.GsonBuilder -import org.bstats.bukkit.Metrics import org.bukkit.Material import org.koin.core.annotation.ComponentScan import org.koin.core.annotation.Module import org.koin.core.annotation.Named -import org.koin.core.annotation.Provided import org.koin.core.annotation.Single import xyz.atrius.waystones.data.json.serializer.MaterialTypeAdapter -import xyz.atrius.waystones.internal.KotlinPlugin import java.util.Locale -const val BSTATS_PLUGIN_ID: Int = 29245 - @Module @ComponentScan("xyz.atrius.waystones") object WaystonesModule { @@ -37,8 +32,4 @@ object WaystonesModule { @Single @Named("defaultPluginLocale") fun defaultPluginLocale(): Locale = Locale.ENGLISH - - @Single(createdAtStart = true) - fun metrics(@Provided plugin: KotlinPlugin): Metrics = - Metrics(plugin, BSTATS_PLUGIN_ID) }