Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ This repository owns the shared runtime platform:

`runtime-catalog/grounds-runtime-libraries.json` is the source of truth for shared runtime library versions. The BOM and runtime diagnostics are generated from that catalog.

`/grounds-runtime` player output uses the general system-message category at info level. The
diagnostic field and library rows use the same metadata as the localized headings, while console
output remains plain and copyable.

## Adding or updating a shared dependency

Use this flow when a library should be provided by `plugin-grounds-runtime` instead of bundled into each consumer plugin.
Expand Down
13 changes: 13 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,17 @@ val versionOverride = providers.gradleProperty("versionOverride").orNull
allprojects {
group = "gg.grounds"
version = versionOverride ?: "0.1.0"

repositories {
maven {
url = uri("https://maven.pkg.github.com/groundsgg/library-i18n")
credentials {
username =
providers.gradleProperty("github.user").orNull ?: System.getenv("GITHUB_ACTOR")
password =
providers.gradleProperty("github.token").orNull ?: System.getenv("GITHUB_TOKEN")
}
content { includeModule("gg.grounds", "library-i18n") }
}
}
}
10 changes: 9 additions & 1 deletion common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ plugins {
id("gg.grounds.kotlin-conventions")
}

dependencies { testImplementation(kotlin("test")) }
dependencies {
api("gg.grounds:library-i18n:0.4.0")
compileOnly("net.kyori:adventure-api:4.17.0")

testImplementation(kotlin("test"))
testImplementation("net.kyori:adventure-api:4.17.0")
testImplementation("net.kyori:adventure-text-minimessage:4.17.0")
testImplementation("net.kyori:adventure-text-serializer-plain:4.17.0")
}

val runtimeCatalogFile =
rootProject.layout.projectDirectory.file("runtime-catalog/grounds-runtime-libraries.json")
Expand Down
31 changes: 20 additions & 11 deletions common/src/main/kotlin/gg/grounds/runtime/RuntimeDiagnostics.kt
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package gg.grounds.runtime

object RuntimeDiagnostics {
fun lines(runtimeId: String, version: String, platform: String): List<String> {
fun report(runtimeId: String, version: String, platform: String): RuntimeDiagnosticsReport {
val manifestStatus =
if (RuntimeManifestLoader.loadRaw() == null) {
"missing"
} else {
"found"
}

return buildList {
add("Grounds Runtime")
add("runtimeId=$runtimeId")
add("version=$version")
add("platform=$platform")
add("manifestPath=${RuntimeManifestLoader.defaultPath}")
add("manifestStatus=$manifestStatus")
add("libraries:")
RuntimeLibraries.provided.forEach { library -> add("- ${library.coordinate()}") }
}
return RuntimeDiagnosticsReport(
fields =
listOf(
"runtimeId=$runtimeId",
"version=$version",
"platform=$platform",
"manifestPath=${RuntimeManifestLoader.defaultPath}",
"manifestStatus=$manifestStatus",
),
libraries = RuntimeLibraries.provided.map { it.coordinate() },
)
}

fun lines(runtimeId: String, version: String, platform: String): List<String> =
report(runtimeId, version, platform).consoleLines()
}

data class RuntimeDiagnosticsReport(val fields: List<String>, val libraries: List<String>) {
fun consoleLines(): List<String> =
listOf("Grounds Runtime") + fields + "libraries:" + libraries.map { "- $it" }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package gg.grounds.runtime

import gg.grounds.i18n.SystemCategory
import gg.grounds.i18n.SystemLevel
import gg.grounds.i18n.SystemMessageKey
import gg.grounds.i18n.SystemMessages
import gg.grounds.i18n.Translations
import net.kyori.adventure.audience.Audience
import net.kyori.adventure.text.Component

enum class RuntimeDiagnosticMessage(override val id: String, override val level: SystemLevel) :
SystemMessageKey {
HEADING("diagnostics.heading", SystemLevel.INFO),
LIBRARIES("diagnostics.libraries", SystemLevel.INFO),
}

object RuntimeDiagnosticsPresenter {
private val messages =
Translations.forBundle("gg.grounds.runtime.messages", javaClass.classLoader)

fun sendPlayer(audience: Audience, report: RuntimeDiagnosticsReport) {
messages.send(audience, RuntimeDiagnosticMessage.HEADING)
report.fields.forEach { line ->
audience.sendMessage(
SystemMessages.format(
Component.text(line),
category = SystemCategory.GENERAL,
locale = messages.localeOf(audience),
level = SystemLevel.INFO,
)
)
}
messages.send(audience, RuntimeDiagnosticMessage.LIBRARIES)
report.libraries.forEach { coordinate ->
audience.sendMessage(
SystemMessages.format(
Component.text("- $coordinate"),
category = SystemCategory.GENERAL,
locale = messages.localeOf(audience),
level = SystemLevel.INFO,
)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
diagnostics.heading=<info>Grounds Runtime
diagnostics.libraries=<info>Libraries
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
diagnostics.heading=<info>Grounds-Laufzeit
diagnostics.libraries=<info>Bibliotheken
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
diagnostics.heading=<info>Entorno de ejecución de Grounds
diagnostics.libraries=<info>Bibliotecas
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
diagnostics.heading=<info>Environnement d’exécution Grounds
diagnostics.libraries=<info>Bibliothèques
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package gg.grounds.runtime

import gg.grounds.i18n.BundleCheck
import gg.grounds.i18n.SystemCategory
import gg.grounds.i18n.SystemLevel
import kotlin.test.Test
import kotlin.test.assertEquals

class RuntimeDiagnosticMessagesTest {
@Test
fun `message bundles are complete`() {
assertEquals(
emptyList(),
BundleCheck.problems(
"gg.grounds.runtime.messages",
javaClass.classLoader,
RuntimeDiagnosticMessage.entries,
),
)
}

@Test
fun `diagnostic messages use general context at info level`() {
RuntimeDiagnosticMessage.entries.forEach { message ->
assertEquals(SystemCategory.GENERAL, message.category)
assertEquals(SystemLevel.INFO, message.level)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package gg.grounds.runtime

import java.util.Locale
import kotlin.test.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals
import net.kyori.adventure.audience.Audience
import net.kyori.adventure.identity.Identity
import net.kyori.adventure.pointer.Pointers
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer

class RuntimeDiagnosticsPresenterTest {
@Test
fun `player output localizes headings and preserves exact diagnostics`() {
val audience = RecordingAudience(Locale.GERMAN)
val report =
RuntimeDiagnostics.report(
runtimeId = "plugin-grounds-runtime-velocity",
version = "0.1.1",
platform = "velocity",
)

RuntimeDiagnosticsPresenter.sendPlayer(audience, report)

val messages = audience.sent.map(PlainTextComponentSerializer.plainText()::serialize)
assertEquals("[Grounds] Allgemein › Grounds-Laufzeit", messages.first())
assertEquals("[Grounds] Allgemein › runtimeId=plugin-grounds-runtime-velocity", messages[1])
assertEquals("[Grounds] Allgemein › Bibliotheken", messages[6])
assertContains(messages, "[Grounds] Allgemein › - io.grpc:grpc-api:1.81.0")
}

@Test
fun `console output remains plain and copyable`() {
val report =
RuntimeDiagnostics.report(
runtimeId = "plugin-grounds-runtime-paper",
version = "0.1.1",
platform = "paper",
)

val lines = report.consoleLines()
assertEquals("Grounds Runtime", lines.first())
assertEquals("runtimeId=plugin-grounds-runtime-paper", lines[1])
assertEquals("version=0.1.1", lines[2])
assertEquals("platform=paper", lines[3])
assertEquals("libraries:", lines[6])
assertContains(lines, "- io.grpc:grpc-api:1.81.0")
}
}

private class RecordingAudience(locale: Locale) : Audience {
val sent = mutableListOf<Component>()
private val pointers = Pointers.builder().withStatic(Identity.LOCALE, locale).build()

override fun pointers(): Pointers = pointers

override fun sendMessage(message: Component) {
sent += message
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package gg.grounds.runtime.paper

import gg.grounds.runtime.RuntimeDiagnostics
import gg.grounds.runtime.RuntimeDiagnosticsPresenter
import gg.grounds.runtime.RuntimeManifestLoader
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin

class GroundsRuntimePaperPlugin : JavaPlugin() {
Expand All @@ -23,12 +25,14 @@ class GroundsRuntimePaperPlugin : JavaPlugin() {
return false
}

RuntimeDiagnostics.lines(
val report =
RuntimeDiagnostics.report(
runtimeId = "plugin-grounds-runtime-paper",
version = pluginMeta.version,
platform = "paper",
)
.forEach(sender::sendMessage)
if (sender is Player) RuntimeDiagnosticsPresenter.sendPlayer(sender, report)
else report.consoleLines().forEach(sender::sendMessage)
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import com.velocitypowered.api.event.Subscribe
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent
import com.velocitypowered.api.plugin.Plugin
import com.velocitypowered.api.proxy.ConsoleCommandSource
import com.velocitypowered.api.proxy.Player
import com.velocitypowered.api.proxy.ProxyServer
import gg.grounds.BuildInfo
import gg.grounds.runtime.RuntimeDiagnostics
import gg.grounds.runtime.RuntimeDiagnosticsPresenter
import gg.grounds.runtime.RuntimeManifestLoader
import net.kyori.adventure.text.Component
import org.slf4j.Logger

@Plugin(
Expand Down Expand Up @@ -40,12 +41,15 @@ constructor(private val proxyServer: ProxyServer, private val logger: Logger) {

private class RuntimeInfoCommand : SimpleCommand {
override fun execute(invocation: SimpleCommand.Invocation) {
RuntimeDiagnostics.lines(
val report =
RuntimeDiagnostics.report(
runtimeId = "plugin-grounds-runtime-velocity",
version = BuildInfo.VERSION,
platform = "velocity",
)
.forEach { line -> invocation.source().sendMessage(Component.text(line)) }
val source = invocation.source()
if (source is Player) RuntimeDiagnosticsPresenter.sendPlayer(source, report)
else report.consoleLines().forEach { line -> source.sendPlainMessage(line) }
}

override fun hasPermission(invocation: SimpleCommand.Invocation): Boolean {
Expand Down