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
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package gg.grounds.permissions.velocity

import gg.grounds.i18n.Translations
import java.util.Locale
import net.kyori.adventure.audience.Audience
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.event.ClickEvent
import net.kyori.adventure.text.event.HoverEvent

/** Renders command guidance as localized actions without exposing raw syntax as the label. */
object PermissionCommandInteraction {
fun supports(message: PermissionsMessage): Boolean = message in interactions

fun render(messages: Translations, message: PermissionsMessage, locale: Locale): Component {
return attach(messages.render(message, locale), message)
}

fun render(messages: Translations, message: PermissionsMessage, audience: Audience): Component {
return attach(messages.render(message, audience), message)
}

private fun attach(component: Component, message: PermissionsMessage): Component {
val interaction =
requireNotNull(interactions[message]) { "No command interaction for ${message.id}" }
return component
.clickEvent(interaction.click)
.hoverEvent(HoverEvent.showText(Component.text(interaction.syntax)))
}

private data class Interaction(val click: ClickEvent, val syntax: String)

private val interactions =
mapOf(
PermissionsMessage.HELP_STATUS to
Interaction(ClickEvent.runCommand("/perm status"), "/perm status"),
PermissionsMessage.USAGE_STATUS to
Interaction(ClickEvent.runCommand("/perm status"), "/perm status"),
PermissionsMessage.HELP_USER_INFO to
Interaction(ClickEvent.suggestCommand("/perm user "), "/perm user <player> info"),
PermissionsMessage.USAGE_INFO to
Interaction(ClickEvent.suggestCommand("/perm user "), "/perm user <player> info"),
PermissionsMessage.HELP_PERMISSION_CHECK to
Interaction(
ClickEvent.suggestCommand("/perm user "),
"/perm user <player> permission check <node> [scope]",
),
PermissionsMessage.USAGE_PERMISSION_CHECK to
Interaction(
ClickEvent.suggestCommand("/perm user "),
"/perm user <player> permission check <node> [scope]",
),
PermissionsMessage.HELP_USER_REFRESH to
Interaction(
ClickEvent.suggestCommand("/perm user "),
"/perm user <player> refresh",
),
PermissionsMessage.USAGE_USER to
Interaction(
ClickEvent.suggestCommand("/perm user "),
"/perm user <player> <info|refresh|permission>",
),
PermissionsMessage.HELP_REFRESH to
Interaction(
ClickEvent.suggestCommand("/perm refresh "),
"/perm refresh <player|all>",
),
PermissionsMessage.USAGE_REFRESH to
Interaction(
ClickEvent.suggestCommand("/perm refresh "),
"/perm refresh <player|all>",
),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,19 @@ class VelocityPermissionsCommand(
}

private fun sendLocalized(source: CommandSource, message: LocalizedPermissionMessage) {
messages.send(source, message.key, *message.args.map { it.key to it.value }.toTypedArray())
if (message.args.isEmpty() && PermissionCommandInteraction.supports(message.key)) {
messages.sendRendered(
source,
message.key,
PermissionCommandInteraction.render(messages, message.key, source),
)
} else {
messages.send(
source,
message.key,
*message.args.map { it.key to it.value }.toTypedArray(),
)
}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
command.output=<text><message>
command.failure=<danger><message>
help.status=<text>/perm status
help.user-info=<text>/perm user \\<player\\> info
help.permission-check=<text>/perm user \\<player\\> permission check \\<node\\> [scope]
help.user-refresh=<text>/perm user \\<player\\> refresh
help.refresh=<text>/perm refresh \\<player|all\\>
usage.status=<warning>Usage: /perm status
usage.user=<warning>Usage: /perm user \\<player\\> \\<info|refresh|permission\\>
usage.info=<warning>Usage: /perm user \\<player\\> info
usage.refresh=<warning>Usage: /perm refresh \\<player|all\\>
usage.permission-check=<warning>Usage: /perm user \\<player\\> permission check \\<node\\> [scope]
help.status=<accent>Show permission status</accent>
help.user-info=<accent>Show player permissions</accent>
help.permission-check=<accent>Check player permission</accent>
help.user-refresh=<accent>Refresh player permissions</accent>
help.refresh=<accent>Refresh permissions</accent>
usage.status=<accent>Show permission status</accent>
usage.user=<accent>Complete player command</accent>
usage.info=<accent>Show player permissions</accent>
usage.refresh=<accent>Refresh permissions</accent>
usage.permission-check=<accent>Check player permission</accent>
error.invalid-scope=<danger>Invalid permission scope: <scope>
error.player-offline=<danger>Player is not online: <player>
error.no-snapshot=<danger>No permission snapshot is loaded for this player.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
command.output=<text><message>
command.failure=<danger><message>
help.status=<text>/perm status
help.user-info=<text>/perm user \\<player\\> info
help.permission-check=<text>/perm user \\<player\\> permission check \\<node\\> [scope]
help.user-refresh=<text>/perm user \\<player\\> refresh
help.refresh=<text>/perm refresh \\<player|all\\>
usage.status=<warning>Benutzung: /perm status
usage.user=<warning>Benutzung: /perm user \\<player\\> \\<info|refresh|permission\\>
usage.info=<warning>Benutzung: /perm user \\<player\\> info
usage.refresh=<warning>Benutzung: /perm refresh \\<player|all\\>
usage.permission-check=<warning>Benutzung: /perm user \\<player\\> permission check \\<node\\> [scope]
help.status=<accent>Berechtigungsstatus anzeigen</accent>
help.user-info=<accent>Spielerberechtigungen anzeigen</accent>
help.permission-check=<accent>Spielerberechtigung prüfen</accent>
help.user-refresh=<accent>Spielerberechtigungen aktualisieren</accent>
help.refresh=<accent>Berechtigungen aktualisieren</accent>
usage.status=<accent>Berechtigungsstatus anzeigen</accent>
usage.user=<accent>Spielerbefehl vervollständigen</accent>
usage.info=<accent>Spielerberechtigungen anzeigen</accent>
usage.refresh=<accent>Berechtigungen aktualisieren</accent>
usage.permission-check=<accent>Spielerberechtigung prüfen</accent>
error.invalid-scope=<danger>Ungültiger Berechtigungsbereich: <scope>
error.player-offline=<danger>Spieler ist nicht online: <player>
error.no-snapshot=<danger>Für diesen Spieler ist kein Berechtigungs-Snapshot geladen.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import gg.grounds.i18n.SystemCategory
import gg.grounds.i18n.SystemLevel
import gg.grounds.i18n.Translations
import java.util.Locale
import net.kyori.adventure.text.event.ClickEvent
import net.kyori.adventure.text.event.HoverEvent
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -52,4 +54,37 @@ class PermissionsMessagesTest {
),
)
}

@Test
fun `localized permission help actions preserve commands and distinguish execution from entry`() {
val status =
PermissionCommandInteraction.render(
messages,
PermissionsMessage.HELP_STATUS,
Locale.GERMAN,
)
val check =
PermissionCommandInteraction.render(
messages,
PermissionsMessage.USAGE_PERMISSION_CHECK,
Locale.GERMAN,
)

assertEquals("Berechtigungsstatus anzeigen", plain.serialize(status))
assertEquals(ClickEvent.runCommand("/perm status"), status.clickEvent())
assertEquals(
HoverEvent.showText(net.kyori.adventure.text.Component.text("/perm status")),
status.hoverEvent(),
)
assertEquals("Spielerberechtigung prüfen", plain.serialize(check))
assertEquals(ClickEvent.suggestCommand("/perm user "), check.clickEvent())
assertEquals(
HoverEvent.showText(
net.kyori.adventure.text.Component.text(
"/perm user <player> permission check <node> [scope]"
)
),
check.hoverEvent(),
)
}
}
Loading