Skip to content
Open
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
Expand Up @@ -6,13 +6,19 @@ import net.kyori.adventure.text.format.NamedTextColor
import net.kyori.adventure.text.format.TextColor

object TabBadge {
fun chip(label: String, fill: TextColor): Component {
fun width(label: String): Int {
val textWidth = VanillaAdvances.width(label)
val pad = 4
val inner =
max(textWidth + pad, TabGlyphs.LEFT_PX + TabGlyphs.RIGHT_PX + TabGlyphs.MIDDLE_PX)
val middles = inner - TabGlyphs.LEFT_PX - TabGlyphs.RIGHT_PX
val badgeWidth = TabGlyphs.LEFT_PX + middles * TabGlyphs.MIDDLE_PX + TabGlyphs.RIGHT_PX
return TabGlyphs.LEFT_PX + middles * TabGlyphs.MIDDLE_PX + TabGlyphs.RIGHT_PX
}

fun chip(label: String, fill: TextColor): Component {
val textWidth = VanillaAdvances.width(label)
val badgeWidth = width(label)
val middles = badgeWidth - TabGlyphs.LEFT_PX - TabGlyphs.RIGHT_PX
val padLeft = (badgeWidth - textWidth) / 2
val padRight = badgeWidth - textWidth - padLeft
val gap = TabSpaces.of(-1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,11 @@ object TabGlyphs {
const val LEFT_PX = 3
const val MIDDLE_PX = 1
const val RIGHT_PX = 3
/** Matches `TabFont` bitmap height and the committed `tab/logo.png`. */
const val LOGO_HEIGHT = 32
const val LOGO_TEXTURE_WIDTH = 256
const val LOGO_TEXTURE_HEIGHT = 52
const val LOGO_ADVANCE = LOGO_TEXTURE_WIDTH * LOGO_HEIGHT / LOGO_TEXTURE_HEIGHT

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the bitmap glyph's rounded advance

When a player row is shorter than the logo, this calculates 157 px by truncating 256 * 32 / 52, but Minecraft rounds the scaled bitmap width and adds the bitmap glyph's built-in 1 px advance (the same spacing TabBadge cancels), giving this full-width texture a 159 px advance. Consequently TabName pads rows two pixels narrower than the padded header, so the wordmark can still overhang the row-sized background this change is intended to widen; derive HEADER_WIDTH from the font's actual rounded glyph advance instead.

Useful? React with 👍 / 👎.

const val LOGO_PAD = 16
const val HEADER_WIDTH = LOGO_PAD + LOGO_ADVANCE + LOGO_PAD
}
23 changes: 21 additions & 2 deletions velocity/src/main/kotlin/gg/grounds/proxy/velocity/tab/TabName.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.TextColor

object TabName {
private const val GAP = 2

fun format(name: String, locale: Locale?, role: PlayerRole?): Component {
val colour = role?.colour?.let(TextColor::fromHexString) ?: Palette.TEXT
val row = Component.text()
Expand All @@ -15,16 +17,33 @@ object TabName {
?.takeIf { it.isNotBlank() }
?.let { language ->
row.append(TabBadge.chip(language.uppercase(Locale.ROOT), Palette.TEXT_FAINT))
row.append(Component.text(TabSpaces.of(2)).font(TabGlyphs.FONT))
row.append(Component.text(TabSpaces.of(GAP)).font(TabGlyphs.FONT))
}
role
?.name
?.takeIf { it.isNotBlank() }
?.let { rank ->
row.append(TabBadge.chip(rank.uppercase(Locale.ROOT), colour))
row.append(Component.text(TabSpaces.of(2)).font(TabGlyphs.FONT))
row.append(Component.text(TabSpaces.of(GAP)).font(TabGlyphs.FONT))
}
row.append(Component.text(name, colour))
val pad = TabGlyphs.HEADER_WIDTH - rowWidth(name, locale, role)
if (pad > 0) {
row.append(Component.text(TabSpaces.of(pad)).font(TabGlyphs.FONT))
}
return row.build()
}

private fun rowWidth(name: String, locale: Locale?, role: PlayerRole?): Int {
var width = VanillaAdvances.width(name)
locale
?.language
?.takeIf { it.isNotBlank() }
?.let { width += TabBadge.width(it.uppercase(Locale.ROOT)) + GAP }
role
?.name
?.takeIf { it.isNotBlank() }
?.let { width += TabBadge.width(it.uppercase(Locale.ROOT)) + GAP }
return width
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
tab.header=\n<font:grounds:tab><white>\uE000</white></font>\n
# Newlines pad the wordmark vertically; U+E018 is TabSpaces.of(16) on each side.
tab.header=\n\n\n\n<font:grounds:tab><white>\uE018\uE000\uE018</white></font>\n\n
tab.footer=\n<text><server></text> <muted>Ping</muted> <ping>\n<faint>grounds.gg <year>
tab.server.lobby=Lobby
tab.server.game=Game
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ class TabListTest {
assertFalse(header.contains("Grounds Network"), header)
}

@Test
fun `the header pads the wordmark on every side`() {
val header = plain(messages.render(ProxyMessage.TAB_HEADER, Locale.ENGLISH))
val side = TabSpaces.of(TabGlyphs.LOGO_PAD)
assertTrue(header.contains("$side${TabGlyphs.LOGO}$side"), header)
val lines = header.lines()
assertTrue(lines.size >= 6, header)
assertTrue(lines.first().isEmpty(), header)
assertTrue(lines.last().isEmpty(), header)
}

@Test
fun `the header is not prefixed - the wordmark already says whose network this is`() {
val header = plain(messages.render(ProxyMessage.TAB_HEADER, Locale.ENGLISH))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gg.grounds.proxy.velocity.tab
import gg.grounds.proxy.api.PlayerRole
import java.util.Locale
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -30,4 +31,22 @@ class TabNameTest {
assertFalse(text.contains("DE"), text)
assertTrue(text.contains("Steve"), text)
}

@Test
fun `a short name is padded to the wordmark width`() {
val name = "A"
val text =
PlainTextComponentSerializer.plainText().serialize(TabName.format(name, null, null))
val pad = TabGlyphs.HEADER_WIDTH - VanillaAdvances.width(name)
assertTrue(pad > 0)
assertTrue(text.contains(TabSpaces.of(pad)), text)
}

@Test
fun `a name that is already wider than the wordmark is not padded`() {
val name = "A".repeat(40)
val text =
PlainTextComponentSerializer.plainText().serialize(TabName.format(name, null, null))
assertEquals(name, text)
}
}