From 28eae48670c2059d0a93b9edc7cba77480196bf0 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Wed, 24 Dec 2025 14:14:25 +0100 Subject: [PATCH 01/17] feat: add GitHub Actions workflow for publishing, enhance Redis event handling, and update dependencies --- .github/workflows/publish.yml | 102 ++++++++++++++++++ gradle.properties | 2 +- surf-tab-api/build.gradle.kts | 6 +- .../surf/tab/api/redis/TabHideRedisEvent.kt | 11 ++ .../surf/tab/api/redis/TabShowRedisEvent.kt | 11 ++ surf-tab-velocity/build.gradle.kts | 3 - .../slne/surf/tab/velocity/VelocityMain.kt | 2 +- .../velocity/redis/TabRedisEventListener.kt | 21 +++- .../redis/event/TabEntryAddRedisEvent.kt | 2 +- .../redis/event/TabEntryRemoveRedisEvent.kt | 2 +- .../tab/velocity/service/TablistService.kt | 1 - 11 files changed, 153 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/publish.yml create mode 100644 surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabHideRedisEvent.kt create mode 100644 surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabShowRedisEvent.kt diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..4f0cde9 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,102 @@ +name: Publish to Maven & Create GitHub Release + +on: + push: + branches: + - 'version/*' + workflow_dispatch: + +env: + SLNE_SNAPSHOTS_REPO_USERNAME: ${{ secrets.SLNE_SNAPSHOTS_REPO_USERNAME }} + SLNE_SNAPSHOTS_REPO_PASSWORD: ${{ secrets.SLNE_SNAPSHOTS_REPO_PASSWORD }} + SLNE_RELEASES_REPO_USERNAME: ${{ secrets.SLNE_RELEASES_REPO_USERNAME }} + SLNE_RELEASES_REPO_PASSWORD: ${{ secrets.SLNE_RELEASES_REPO_PASSWORD }} + MODULE_REGEX: "surf-tab-api.*-all\\.jar$|surf-tab-velocity.*-all\\.jar$" + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + +jobs: + build: + runs-on: ubuntu-latest + environment: production + steps: + - name: Collect Workflow Telemetry + uses: catchpoint/workflow-telemetry-action@v2 + + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Cache Gradle packages + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: gradle-${{ runner.os }}- + + - name: Setup JDK + uses: actions/setup-java@v4 + with: + distribution: 'graalvm' + java-version: '24' + + - name: Build all modules with Gradle + run: ./gradlew build shadowJar --parallel --no-scan + + - name: Publish all modules to Maven + run: ./gradlew publish --parallel --no-scan + + - name: Extract Project Version and Snapshot Flag from Gradle + id: get_version + run: | + VERSION=$(./gradlew properties --no-daemon \ + | grep '^version:' \ + | awk '{print $2}') + SNAPSHOT_FLAG=$(./gradlew properties --no-daemon \ + | grep '^snapshot:' \ + | awk '{print $2}') + if [ "$SNAPSHOT_FLAG" = "true" ]; then + VERSION="${VERSION}-SNAPSHOT" + fi + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "SNAPSHOT_FLAG=$SNAPSHOT_FLAG" >> $GITHUB_ENV + + - name: Determine release flags + run: | + CURRENT_BRANCH=${GITHUB_REF#refs/heads/} + # prerelease only for snapshots + if [ "${SNAPSHOT_FLAG}" = "true" ]; then + echo "PRERELEASE=true" >> $GITHUB_ENV + else + echo "PRERELEASE=false" >> $GITHUB_ENV + fi + # make_latest false for snapshots or non-default branches + if [ "${SNAPSHOT_FLAG}" = "true" ] || [ "${CURRENT_BRANCH}" != "${DEFAULT_BRANCH}" ]; then + echo "MAKE_LATEST=false" >> $GITHUB_ENV + else + echo "MAKE_LATEST=true" >> $GITHUB_ENV + fi + + - name: Find and filter JAR files + id: find_jars + run: | + echo "JAR_FILES<> $GITHUB_ENV + find . -path "**/build/libs/*.jar" \ + | grep -E "${{ env.MODULE_REGEX }}" \ + >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ env.VERSION }} + name: Release ${{ env.VERSION }} + draft: false + prerelease: ${{ env.PRERELEASE }} + make_latest: ${{ env.MAKE_LATEST }} + files: ${{ env.JAR_FILES }} + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 57f03c0..d224704 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official kotlin.stdlib.default.dependency=false org.gradle.parallel=true -version=1.21.11-1.0.0-SNAPSHOT \ No newline at end of file +version=1.21.11-1.0.1-SNAPSHOT \ No newline at end of file diff --git a/surf-tab-api/build.gradle.kts b/surf-tab-api/build.gradle.kts index 34ec0c2..aeb8404 100644 --- a/surf-tab-api/build.gradle.kts +++ b/surf-tab-api/build.gradle.kts @@ -1,3 +1,7 @@ plugins { - id("dev.slne.surf.surfapi.gradle.velocity") + id("dev.slne.surf.surfapi.gradle.core") +} + +dependencies { + api("dev.slne.surf:surf-redis:1.0.0-SNAPSHOT") } \ No newline at end of file diff --git a/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabHideRedisEvent.kt b/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabHideRedisEvent.kt new file mode 100644 index 0000000..9018e36 --- /dev/null +++ b/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabHideRedisEvent.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.tab.api.redis + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.util.* + +@Serializable +data class TabHideRedisEvent( + val player: @Contextual UUID, + val toHide: @Contextual UUID +) diff --git a/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabShowRedisEvent.kt b/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabShowRedisEvent.kt new file mode 100644 index 0000000..bd187cf --- /dev/null +++ b/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabShowRedisEvent.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.tab.api.redis + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.util.* + +@Serializable +data class TabShowRedisEvent( + val player: @Contextual UUID, + val toShow: @Contextual UUID +) diff --git a/surf-tab-velocity/build.gradle.kts b/surf-tab-velocity/build.gradle.kts index b847294..ef65227 100644 --- a/surf-tab-velocity/build.gradle.kts +++ b/surf-tab-velocity/build.gradle.kts @@ -20,8 +20,5 @@ dependencies { compileOnly(libs.mini.placeholders) compileOnly(libs.mini.placeholders.kotlin) compileOnly(libs.luckperms.api) - - implementation("dev.slne:surf-redis:1.0.0-20251223.105653-21") - api(project(":surf-tab-api")) } \ No newline at end of file diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/VelocityMain.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/VelocityMain.kt index d3d41ac..64863f6 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/VelocityMain.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/VelocityMain.kt @@ -8,7 +8,7 @@ import com.velocitypowered.api.event.proxy.ProxyShutdownEvent import com.velocitypowered.api.plugin.PluginContainer import com.velocitypowered.api.plugin.annotation.DataDirectory import com.velocitypowered.api.proxy.ProxyServer -import dev.slne.redis.RedisApi +import dev.slne.surf.redis.RedisApi import dev.slne.surf.tab.velocity.command.surfTabCommand import dev.slne.surf.tab.velocity.config.TablistConfigProvider import dev.slne.surf.tab.velocity.hook.LuckPermsHook diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt index 2f17a0b..1832146 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt @@ -1,9 +1,14 @@ package dev.slne.surf.tab.velocity.redis -import dev.slne.redis.event.OnRedisEvent +import dev.slne.surf.redis.event.OnRedisEvent +import dev.slne.surf.tab.api.redis.TabHideRedisEvent +import dev.slne.surf.tab.api.redis.TabShowRedisEvent +import dev.slne.surf.tab.velocity.plugin import dev.slne.surf.tab.velocity.redis.event.TabEntryAddRedisEvent import dev.slne.surf.tab.velocity.redis.event.TabEntryRemoveRedisEvent import dev.slne.surf.tab.velocity.service.tablistService +import dev.slne.surf.tab.velocity.util.toVelocity +import kotlin.jvm.optionals.getOrNull object TabRedisEventListener { @OnRedisEvent @@ -32,4 +37,18 @@ object TabRedisEventListener { tablistService.removePlayer(it, event.profileUuid) } } + + @OnRedisEvent + fun onTabHide(event: TabHideRedisEvent) { + val player = plugin.proxy.getPlayer(event.player).getOrNull() ?: return + player.tabList.removeEntry(event.toHide) + } + + @OnRedisEvent + fun onTabShow(event: TabShowRedisEvent) { + val player = plugin.proxy.getPlayer(event.player).getOrNull() ?: return + val entry = tablistService.entries.find { it.profile.uuid == event.toShow } ?: return + + player.tabList.addEntry(entry.toVelocity(player.tabList)) + } } \ No newline at end of file diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/event/TabEntryAddRedisEvent.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/event/TabEntryAddRedisEvent.kt index b7af14d..315b663 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/event/TabEntryAddRedisEvent.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/event/TabEntryAddRedisEvent.kt @@ -1,7 +1,7 @@ package dev.slne.surf.tab.velocity.redis.event import com.velocitypowered.api.proxy.server.RegisteredServer -import dev.slne.redis.event.RedisEvent +import dev.slne.surf.redis.event.RedisEvent import dev.slne.surf.tab.api.entry.TabEntry import dev.slne.surf.tab.velocity.serializer.RegisteredServerSerializer import kotlinx.serialization.Serializable diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/event/TabEntryRemoveRedisEvent.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/event/TabEntryRemoveRedisEvent.kt index 3212581..eed8cbc 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/event/TabEntryRemoveRedisEvent.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/event/TabEntryRemoveRedisEvent.kt @@ -1,7 +1,7 @@ package dev.slne.surf.tab.velocity.redis.event import com.velocitypowered.api.proxy.server.RegisteredServer -import dev.slne.redis.event.RedisEvent +import dev.slne.surf.redis.event.RedisEvent import dev.slne.surf.tab.velocity.serializer.RegisteredServerSerializer import kotlinx.serialization.Contextual import kotlinx.serialization.Serializable diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt index 6b8eb62..d3ca44b 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt @@ -34,7 +34,6 @@ class VelocityTablistService { } fun sendCurrentTablist(player: Player) { - println("Sending current tablist to player ${player.username}: ${entries.map { it.profile.name }}") entries.forEach { entry -> addPlayer(player, entry) } From 600fa082a7495c4f6bece119892ef83725a703e9 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Wed, 24 Dec 2025 14:14:39 +0100 Subject: [PATCH 02/17] chore: chmod --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From 8df91165eeeae6e77f5edea5e8daa12482f72916 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Wed, 24 Dec 2025 14:19:52 +0100 Subject: [PATCH 03/17] chore: configure slneReleases repository for publishing in all subprojects --- build.gradle.kts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 7bbfa4d..1ea2d2d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import dev.slne.surf.surfapi.gradle.util.slneReleases + buildscript { repositories { gradlePluginPortal() @@ -11,4 +13,16 @@ buildscript { allprojects { group = "dev.slne.surf.tab" version = findProperty("version") as String +} + +subprojects { + afterEvaluate { + plugins.withType { + configure { + repositories { + slneReleases() + } + } + } + } } \ No newline at end of file From 23553d8e99cb61d53ba8958738fccbd14fd9addf Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Wed, 24 Dec 2025 14:24:24 +0100 Subject: [PATCH 04/17] feat: extend TabShowRedisEvent and TabHideRedisEvent from RedisEvent, update project version to 1.21.11-1.0.2-SNAPSHOT --- gradle.properties | 2 +- .../kotlin/dev/slne/surf/tab/api/redis/TabHideRedisEvent.kt | 3 ++- .../kotlin/dev/slne/surf/tab/api/redis/TabShowRedisEvent.kt | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index d224704..2920250 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official kotlin.stdlib.default.dependency=false org.gradle.parallel=true -version=1.21.11-1.0.1-SNAPSHOT \ No newline at end of file +version=1.21.11-1.0.2-SNAPSHOT \ No newline at end of file diff --git a/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabHideRedisEvent.kt b/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabHideRedisEvent.kt index 9018e36..1b477a0 100644 --- a/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabHideRedisEvent.kt +++ b/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabHideRedisEvent.kt @@ -1,5 +1,6 @@ package dev.slne.surf.tab.api.redis +import dev.slne.surf.redis.event.RedisEvent import kotlinx.serialization.Contextual import kotlinx.serialization.Serializable import java.util.* @@ -8,4 +9,4 @@ import java.util.* data class TabHideRedisEvent( val player: @Contextual UUID, val toHide: @Contextual UUID -) +) : RedisEvent() diff --git a/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabShowRedisEvent.kt b/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabShowRedisEvent.kt index bd187cf..4061208 100644 --- a/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabShowRedisEvent.kt +++ b/surf-tab-api/src/main/kotlin/dev/slne/surf/tab/api/redis/TabShowRedisEvent.kt @@ -1,5 +1,6 @@ package dev.slne.surf.tab.api.redis +import dev.slne.surf.redis.event.RedisEvent import kotlinx.serialization.Contextual import kotlinx.serialization.Serializable import java.util.* @@ -8,4 +9,4 @@ import java.util.* data class TabShowRedisEvent( val player: @Contextual UUID, val toShow: @Contextual UUID -) +) : RedisEvent() From f4ad73c21ce5ea831363294c22435ed0c65f7bbf Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Fri, 26 Dec 2025 18:40:38 +0100 Subject: [PATCH 05/17] fix: use `playerCount` instead of `allPlayers.size` to determine online player count --- .../kotlin/dev/slne/surf/tab/velocity/util/formatting-util.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/util/formatting-util.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/util/formatting-util.kt index 37d3671..27c2504 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/util/formatting-util.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/util/formatting-util.kt @@ -38,7 +38,7 @@ private fun dynamicResolver(player: Player): TagResolver = }, TagResolver.resolver("players_online") { _, _ -> Tag.inserting { - buildText { info(plugin.proxy.allPlayers.size) } + buildText { info(plugin.proxy.playerCount) } } }, TagResolver.resolver("players_max") { _, _ -> From a36b951207615c8d210c455e6d820f21297247e2 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Sun, 28 Dec 2025 14:07:33 +0100 Subject: [PATCH 06/17] refactor: replace `mutableObjectSetOf` with `mutableObject2ObjectMapOf` for `entries`, clean up unused utilities, and optimize tablist management logic --- .../velocity/redis/TabRedisEventListener.kt | 19 ++++-- .../tab/velocity/service/TablistService.kt | 8 ++- .../surf/tab/velocity/util/formatting-util.kt | 67 +------------------ 3 files changed, 23 insertions(+), 71 deletions(-) diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt index 1832146..a3f137b 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt @@ -17,7 +17,10 @@ object TabRedisEventListener { val seenServers = tablistService.getSeenServers(server) val visiblePlayers = seenServers.flatMap { it.playersConnected } - tablistService.entries.add(event.tabEntry) + seenServers.forEach { + tablistService.entries[it] = + tablistService.entries.getOrDefault(it, mutableListOf()) + event.tabEntry + } visiblePlayers.forEach { tablistService.addPlayer(it, event.tabEntry) @@ -26,12 +29,18 @@ object TabRedisEventListener { @OnRedisEvent fun onTabEntryRemove(event: TabEntryRemoveRedisEvent) { - println("Removing tab entry for UUID ${event.profileUuid} from tablist via Redis event") val server = event.baseServer val seenServers = tablistService.getSeenServers(server) val visiblePlayers = seenServers.flatMap { it.playersConnected } - tablistService.entries.removeIf { it.profile.uuid == event.profileUuid } + seenServers.forEach { server -> + tablistService.entries[server]?.forEach { + if (it.profile.uuid == event.profileUuid) { + tablistService.entries[server] = + tablistService.entries[server]?.filter { entry -> entry.profile.uuid != event.profileUuid } + } + } + } visiblePlayers.forEach { tablistService.removePlayer(it, event.profileUuid) @@ -47,7 +56,9 @@ object TabRedisEventListener { @OnRedisEvent fun onTabShow(event: TabShowRedisEvent) { val player = plugin.proxy.getPlayer(event.player).getOrNull() ?: return - val entry = tablistService.entries.find { it.profile.uuid == event.toShow } ?: return + val server = player.currentServer.getOrNull()?.server ?: return + val entry = + tablistService.entries[server]?.find { it.profile.uuid == event.toShow } ?: return player.tabList.addEntry(entry.toVelocity(player.tabList)) } diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt index d3ca44b..f988536 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt @@ -2,7 +2,7 @@ package dev.slne.surf.tab.velocity.service import com.velocitypowered.api.proxy.Player import com.velocitypowered.api.proxy.server.RegisteredServer -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf +import dev.slne.surf.surfapi.core.api.util.mutableObject2ObjectMapOf import dev.slne.surf.tab.api.entry.TabEntry import dev.slne.surf.tab.api.entry.TabGameMode import dev.slne.surf.tab.velocity.hook.LuckPermsHook @@ -12,11 +12,12 @@ import dev.slne.surf.tab.velocity.util.getServers import dev.slne.surf.tab.velocity.util.toTabProfile import dev.slne.surf.tab.velocity.util.toVelocity import java.util.* +import kotlin.jvm.optionals.getOrNull val tablistService = VelocityTablistService() class VelocityTablistService { - val entries = mutableObjectSetOf() + val entries = mutableObject2ObjectMapOf>() fun addPlayer(viewer: Player, entry: TabEntry) { viewer.tabList.addEntry(entry.toVelocity(viewer.tabList)) @@ -34,7 +35,8 @@ class VelocityTablistService { } fun sendCurrentTablist(player: Player) { - entries.forEach { entry -> + val currentServer = player.currentServer.getOrNull()?.server ?: return + entries[currentServer]?.forEach { entry -> addPlayer(player, entry) } } diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/util/formatting-util.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/util/formatting-util.kt index 27c2504..d530c9e 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/util/formatting-util.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/util/formatting-util.kt @@ -5,12 +5,7 @@ import dev.slne.surf.surfapi.core.api.messages.adventure.buildText import dev.slne.surf.tab.api.entry.TabGroup import dev.slne.surf.tab.velocity.plugin import io.github.miniplaceholders.api.MiniPlaceholders -import io.github.miniplaceholders.api.types.RelationalAudience -import net.kyori.adventure.audience.Audience -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.TextColor import net.kyori.adventure.text.minimessage.MiniMessage -import net.kyori.adventure.text.minimessage.tag.Tag import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver import java.time.ZonedDateTime import java.time.format.DateTimeFormatter @@ -18,7 +13,6 @@ import kotlin.jvm.optionals.getOrNull private val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy") private val timeFormatter = DateTimeFormatter.ofPattern("HH:mm") -private val miniMessage = MiniMessage.miniMessage() private val globalResolver = TagResolver.resolver( MiniPlaceholders.globalPlaceholders(), MiniPlaceholders.audiencePlaceholders(), @@ -27,49 +21,8 @@ private val globalResolver = TagResolver.resolver( MiniPlaceholders.audienceGlobalPlaceholders() ) -private fun dynamicResolver(player: Player): TagResolver = - TagResolver.resolver( - TagResolver.resolver("server") { _, _ -> - val name = player.currentServer - .getOrNull()?.server?.serverInfo?.name ?: "N/A" - Tag.inserting { - buildText { info(name) } - } - }, - TagResolver.resolver("players_online") { _, _ -> - Tag.inserting { - buildText { info(plugin.proxy.playerCount) } - } - }, - TagResolver.resolver("players_max") { _, _ -> - Tag.inserting { - buildText { info(plugin.proxy.configuration.showMaxPlayers) } - } - }, - TagResolver.resolver("date") { _, _ -> - Tag.inserting { - buildText { info(nowDate()) } - } - }, - TagResolver.resolver("time") { _, _ -> - Tag.inserting { - buildText { info(nowTime()) } - } - } - ) - - -fun String.formatWithAdventure(player: Player, other: Audience? = null): Component { - if (other != null) { - return MiniMessage.miniMessage() - .deserialize( - this, - RelationalAudience(player, other), - TagResolver.resolver(globalResolver) - ) - } - - return MiniMessage.miniMessage().deserialize(this, player, TagResolver.resolver(globalResolver)) +fun String.formatWithAdventure(player: Player) = + MiniMessage.miniMessage().deserialize(this, player, TagResolver.resolver(globalResolver)) .replaceText { it.matchLiteral("") it.replacement(buildText { @@ -83,7 +36,7 @@ fun String.formatWithAdventure(player: Player, other: Audience? = null): Compone it.matchLiteral("") it.replacement(buildText { info( - plugin.proxy.allPlayers.size + plugin.proxy.playerCount ) }) } @@ -107,7 +60,6 @@ fun String.formatWithAdventure(player: Player, other: Audience? = null): Compone info(ZonedDateTime.now().format(timeFormatter)) }) } -} @Volatile private var cachedMinute = -1 @@ -128,17 +80,4 @@ private fun updateTimeCache() { } } -private fun nowDate(): String { - updateTimeCache() - return cachedDate -} - -private fun nowTime(): String { - updateTimeCache() - return cachedTime -} - - -fun TextColor.mm() = "<${this.asHexString()}>" - fun TabGroup.getServers() = clients.mapNotNull { plugin.proxy.getServer(it).getOrNull() } \ No newline at end of file From f808c82bcabfc7e08059c944e721275c83358d66 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Sun, 28 Dec 2025 15:11:56 +0100 Subject: [PATCH 07/17] refactor: split `updatePlayerInTablist` into `updateOthersFor` and `updateForOthers`, adjust usages across services, and clean up tablist handling logic --- .../tab/velocity/command/SurfTabCommand.kt | 2 +- .../surf/tab/velocity/hook/LuckPermsHook.kt | 4 +- .../tab/velocity/service/TablistService.kt | 38 ++++++++++++------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt index c1fe035..784a497 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt @@ -16,7 +16,7 @@ fun surfTabCommand() = commandTree("surftab") { tablistConfiguration.reload() plugin.proxy.allPlayers.forEach { - tablistService.updatePlayerInTablist(it) + tablistService.updateOthersFor(it) } executor.sendText { diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/hook/LuckPermsHook.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/hook/LuckPermsHook.kt index 165435a..5d8ed96 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/hook/LuckPermsHook.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/hook/LuckPermsHook.kt @@ -32,8 +32,6 @@ object LuckPermsHook { private fun updatePlayerInTablist(user: User) { val player = plugin.proxy.getPlayer(user.uniqueId).getOrNull() ?: return - tablistService.updatePlayerInTablist(player) + tablistService.updateForOthers(player) } - - } \ No newline at end of file diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt index f988536..0ba5866 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt @@ -58,20 +58,32 @@ class VelocityTablistService { weight = LuckPermsHook.getWeight(target.uniqueId) ) - fun updatePlayerInTablist(player: Player) { -// val server = player.currentServer.getOrNull()?.server ?: return -// -// val seenServers = tablistService.getSeenServers(server) -// val viewers = seenServers.flatMap { it.playersConnected }.distinct() -// -// viewers.forEach { viewer -> -// tablistService.removePlayer(viewer, player.uniqueId) -// tablistService.addPlayer(viewer, tablistService.createEntry(player, viewer)) -// } -// -// tablistService.removePlayer(player, player.uniqueId) -// tablistService.addPlayer(player, tablistService.createEntry(player, player)) + fun updateOthersFor(viewer: Player) { + val server = viewer.currentServer.getOrNull()?.server ?: return + + val seenServers = tablistService.getSeenServers(server) + val seenPlayers = seenServers.flatMap { it.playersConnected }.distinct() + .filterNot { it.uniqueId == viewer.uniqueId } + + seenPlayers.forEach { seen -> + tablistService.removePlayer(viewer, seen.uniqueId) + tablistService.addPlayer(viewer, tablistService.createEntry(seen)) + } + // As velocity has no chat session api, we cannot update the tablist entries properly yet. Currently, it will cause the chat validation to fail. // [00:21:47] [Render thread/ERROR]: Received chat message from 1c779cb1-3860-4e23-9cac-7f160b2acc61, but they have no chat session initialized and secure chat is enforced } + + fun updateForOthers(toUpdate: Player) { + val server = toUpdate.currentServer.getOrNull()?.server ?: return + + val seenServers = tablistService.getSeenServers(server) + val seenPlayers = seenServers.flatMap { it.playersConnected }.distinct() + .filterNot { it.uniqueId == toUpdate.uniqueId } + + seenPlayers.forEach { viewer -> + tablistService.removePlayer(viewer, toUpdate.uniqueId) + tablistService.addPlayer(viewer, tablistService.createEntry(toUpdate)) + } + } } \ No newline at end of file From 1a92bf8bedc1163c8751bb014e88ad425d81b7f9 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Mon, 29 Dec 2025 16:36:27 +0100 Subject: [PATCH 08/17] refactor: simplify `getSeenServers` by using `toMutableObjectList`, ensure base server is included in the result --- .../slne/surf/tab/velocity/service/TablistService.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt index 0ba5866..9e3e801 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt @@ -3,6 +3,7 @@ package dev.slne.surf.tab.velocity.service import com.velocitypowered.api.proxy.Player import com.velocitypowered.api.proxy.server.RegisteredServer import dev.slne.surf.surfapi.core.api.util.mutableObject2ObjectMapOf +import dev.slne.surf.surfapi.core.api.util.toMutableObjectList import dev.slne.surf.tab.api.entry.TabEntry import dev.slne.surf.tab.api.entry.TabGameMode import dev.slne.surf.tab.velocity.hook.LuckPermsHook @@ -43,11 +44,13 @@ class VelocityTablistService { fun getSeenServers(base: RegisteredServer): List { val groups = tablistConfig.groups.map { it.toTabGroup() } - - return groups + val servers = groups .filter { base in it.getServers() } - .flatMap { it.getServers() } - .distinct() + .flatMap { it.getServers() }.distinct().toMutableObjectList() + + servers.add(base) + + return servers } fun createEntry(target: Player) = TabEntry( From b6858f42043f322c3235e059d5902fd956378334 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Mon, 29 Dec 2025 19:12:41 +0100 Subject: [PATCH 09/17] Revert "refactor: simplify `getSeenServers` by using `toMutableObjectList`, ensure base server is included in the result" This reverts commit 1a92bf8bedc1163c8751bb014e88ad425d81b7f9. --- .../slne/surf/tab/velocity/service/TablistService.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt index 9e3e801..0ba5866 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt @@ -3,7 +3,6 @@ package dev.slne.surf.tab.velocity.service import com.velocitypowered.api.proxy.Player import com.velocitypowered.api.proxy.server.RegisteredServer import dev.slne.surf.surfapi.core.api.util.mutableObject2ObjectMapOf -import dev.slne.surf.surfapi.core.api.util.toMutableObjectList import dev.slne.surf.tab.api.entry.TabEntry import dev.slne.surf.tab.api.entry.TabGameMode import dev.slne.surf.tab.velocity.hook.LuckPermsHook @@ -44,13 +43,11 @@ class VelocityTablistService { fun getSeenServers(base: RegisteredServer): List { val groups = tablistConfig.groups.map { it.toTabGroup() } - val servers = groups - .filter { base in it.getServers() } - .flatMap { it.getServers() }.distinct().toMutableObjectList() - - servers.add(base) - return servers + return groups + .filter { base in it.getServers() } + .flatMap { it.getServers() } + .distinct() } fun createEntry(target: Player) = TabEntry( From 4be0ab860766186cead81497c3fd107589e6a329 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Mon, 29 Dec 2025 19:12:41 +0100 Subject: [PATCH 10/17] Revert "refactor: split `updatePlayerInTablist` into `updateOthersFor` and `updateForOthers`, adjust usages across services, and clean up tablist handling logic" This reverts commit f808c82bcabfc7e08059c944e721275c83358d66. --- .../tab/velocity/command/SurfTabCommand.kt | 2 +- .../surf/tab/velocity/hook/LuckPermsHook.kt | 4 +- .../tab/velocity/service/TablistService.kt | 38 +++++++------------ 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt index 784a497..c1fe035 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt @@ -16,7 +16,7 @@ fun surfTabCommand() = commandTree("surftab") { tablistConfiguration.reload() plugin.proxy.allPlayers.forEach { - tablistService.updateOthersFor(it) + tablistService.updatePlayerInTablist(it) } executor.sendText { diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/hook/LuckPermsHook.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/hook/LuckPermsHook.kt index 5d8ed96..165435a 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/hook/LuckPermsHook.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/hook/LuckPermsHook.kt @@ -32,6 +32,8 @@ object LuckPermsHook { private fun updatePlayerInTablist(user: User) { val player = plugin.proxy.getPlayer(user.uniqueId).getOrNull() ?: return - tablistService.updateForOthers(player) + tablistService.updatePlayerInTablist(player) } + + } \ No newline at end of file diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt index 0ba5866..f988536 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt @@ -58,32 +58,20 @@ class VelocityTablistService { weight = LuckPermsHook.getWeight(target.uniqueId) ) - fun updateOthersFor(viewer: Player) { - val server = viewer.currentServer.getOrNull()?.server ?: return - - val seenServers = tablistService.getSeenServers(server) - val seenPlayers = seenServers.flatMap { it.playersConnected }.distinct() - .filterNot { it.uniqueId == viewer.uniqueId } - - seenPlayers.forEach { seen -> - tablistService.removePlayer(viewer, seen.uniqueId) - tablistService.addPlayer(viewer, tablistService.createEntry(seen)) - } - + fun updatePlayerInTablist(player: Player) { +// val server = player.currentServer.getOrNull()?.server ?: return +// +// val seenServers = tablistService.getSeenServers(server) +// val viewers = seenServers.flatMap { it.playersConnected }.distinct() +// +// viewers.forEach { viewer -> +// tablistService.removePlayer(viewer, player.uniqueId) +// tablistService.addPlayer(viewer, tablistService.createEntry(player, viewer)) +// } +// +// tablistService.removePlayer(player, player.uniqueId) +// tablistService.addPlayer(player, tablistService.createEntry(player, player)) // As velocity has no chat session api, we cannot update the tablist entries properly yet. Currently, it will cause the chat validation to fail. // [00:21:47] [Render thread/ERROR]: Received chat message from 1c779cb1-3860-4e23-9cac-7f160b2acc61, but they have no chat session initialized and secure chat is enforced } - - fun updateForOthers(toUpdate: Player) { - val server = toUpdate.currentServer.getOrNull()?.server ?: return - - val seenServers = tablistService.getSeenServers(server) - val seenPlayers = seenServers.flatMap { it.playersConnected }.distinct() - .filterNot { it.uniqueId == toUpdate.uniqueId } - - seenPlayers.forEach { viewer -> - tablistService.removePlayer(viewer, toUpdate.uniqueId) - tablistService.addPlayer(viewer, tablistService.createEntry(toUpdate)) - } - } } \ No newline at end of file From 22eb17a8615c2756e98468d1c8891ab2b20ecadb Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Mon, 29 Dec 2025 19:17:56 +0100 Subject: [PATCH 11/17] refactor: enhance `getSeenServers` by adding base server explicitly, add `toMutableObjectList` for distinct server handling --- .../surf/tab/velocity/redis/TabRedisEventListener.kt | 2 +- .../slne/surf/tab/velocity/service/TablistService.kt | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt index a3f137b..4df5ef0 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/TabRedisEventListener.kt @@ -60,6 +60,6 @@ object TabRedisEventListener { val entry = tablistService.entries[server]?.find { it.profile.uuid == event.toShow } ?: return - player.tabList.addEntry(entry.toVelocity(player.tabList)) + player.tabList.addEntry(entry.toVelocity(player.tabList))// TODO: Not working with multiproxy support } } \ No newline at end of file diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt index f988536..1b16975 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/service/TablistService.kt @@ -3,6 +3,7 @@ package dev.slne.surf.tab.velocity.service import com.velocitypowered.api.proxy.Player import com.velocitypowered.api.proxy.server.RegisteredServer import dev.slne.surf.surfapi.core.api.util.mutableObject2ObjectMapOf +import dev.slne.surf.surfapi.core.api.util.toMutableObjectList import dev.slne.surf.tab.api.entry.TabEntry import dev.slne.surf.tab.api.entry.TabGameMode import dev.slne.surf.tab.velocity.hook.LuckPermsHook @@ -43,11 +44,13 @@ class VelocityTablistService { fun getSeenServers(base: RegisteredServer): List { val groups = tablistConfig.groups.map { it.toTabGroup() } - - return groups + val servers = groups .filter { base in it.getServers() } - .flatMap { it.getServers() } - .distinct() + .flatMap { it.getServers() }.distinct().toMutableObjectList() + + servers.add(base) + + return servers } fun createEntry(target: Player) = TabEntry( From 62f6d587631134c3816b52e42b4bc84a37afcfc6 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Wed, 31 Dec 2025 12:11:10 +0100 Subject: [PATCH 12/17] refactor: streamline tablist management, replace direct server references with UUID handling, and enhance Redis event processing --- surf-tab-velocity/build.gradle.kts | 4 + .../tab/velocity/command/SurfTabCommand.kt | 6 -- .../surf/tab/velocity/config/TablistConfig.kt | 6 -- .../surf/tab/velocity/hook/LuckPermsHook.kt | 32 +++++-- .../velocity/listener/ConnectionListener.kt | 19 ++-- .../velocity/redis/TabRedisEventListener.kt | 61 +++++------- .../redis/event/TabEntryAddRedisEvent.kt | 9 +- .../redis/event/TabEntryRemoveRedisEvent.kt | 6 +- .../redis/event/TabEntryUpdateRedisEvent.kt | 11 +++ .../tab/velocity/service/TablistService.kt | 93 ++++++++++--------- 10 files changed, 123 insertions(+), 124 deletions(-) create mode 100644 surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/redis/event/TabEntryUpdateRedisEvent.kt diff --git a/surf-tab-velocity/build.gradle.kts b/surf-tab-velocity/build.gradle.kts index ef65227..c782624 100644 --- a/surf-tab-velocity/build.gradle.kts +++ b/surf-tab-velocity/build.gradle.kts @@ -13,6 +13,9 @@ velocityPluginFile { pluginDependencies { register("miniplaceholders") register("luckperms") + register("surf-clan-velocity") { + optional = true + } } } @@ -21,4 +24,5 @@ dependencies { compileOnly(libs.mini.placeholders.kotlin) compileOnly(libs.luckperms.api) api(project(":surf-tab-api")) + compileOnly("dev.slne.surf.clan:surf-clan-api:1.21.11-1.3.0-SNAPSHOT") } \ No newline at end of file diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt index c1fe035..68ad146 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/command/SurfTabCommand.kt @@ -4,8 +4,6 @@ import dev.jorel.commandapi.kotlindsl.anyExecutor import dev.jorel.commandapi.kotlindsl.commandTree import dev.jorel.commandapi.kotlindsl.literalArgument import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import dev.slne.surf.tab.velocity.plugin -import dev.slne.surf.tab.velocity.service.tablistService import dev.slne.surf.tab.velocity.tablistConfiguration fun surfTabCommand() = commandTree("surftab") { @@ -15,10 +13,6 @@ fun surfTabCommand() = commandTree("surftab") { anyExecutor { executor, _ -> tablistConfiguration.reload() - plugin.proxy.allPlayers.forEach { - tablistService.updatePlayerInTablist(it) - } - executor.sendText { appendPrefix() success("Die Tablist wurde neu geladen.") diff --git a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/config/TablistConfig.kt b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/config/TablistConfig.kt index 8f6d3c2..bbcdff3 100644 --- a/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/config/TablistConfig.kt +++ b/surf-tab-velocity/src/main/kotlin/dev/slne/surf/tab/velocity/config/TablistConfig.kt @@ -7,10 +7,4 @@ data class TablistConfig( val header: String = "
<#6EA6D9> CASTCRAFTER
<#6EA6D9>COMMUNITY SERVER

<#59CCF2> - <#59CCF2>