From 66c12d277c2f191a3a4e2cc10e178a0e1c4c62ae Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 20 Oct 2026 15:53:42 +0200 Subject: [PATCH 1/3] feat: hide vanished players from synced tablist --- .../app/simplecloud/plugin/prefixes/api/PrefixesApi.kt | 4 ++++ .../prefixes/minestom/display/MinestomDisplayManager.kt | 1 + .../prefixes/minestom/platform/MinestomPlatformImpl.kt | 2 ++ .../plugin/prefixes/paper/display/PaperDisplayManager.kt | 1 + .../plugin/prefixes/paper/platform/PaperPlatformImpl.kt | 2 ++ .../plugin/prefixes/shared/api/PrefixesApiImpl.kt | 8 ++++++++ .../plugin/prefixes/shared/data/PrefixesDataRegistry.kt | 8 ++++++++ .../plugin/prefixes/shared/platform/PrefixesPlatform.kt | 2 ++ 8 files changed, 28 insertions(+) diff --git a/server/prefixes/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApi.kt b/server/prefixes/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApi.kt index 3afd146..fb4f58f 100644 --- a/server/prefixes/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApi.kt +++ b/server/prefixes/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApi.kt @@ -57,6 +57,10 @@ interface PrefixesApi { fun reset(targets: Audience, viewers: Audience) + fun setVanished(id: UUID, vanished: Boolean) + + fun isVanished(id: UUID): Boolean + fun addGroup(group: PrefixesGroup): CompletableFuture fun registerGroupProvider(provider: GroupProvider) diff --git a/server/prefixes/prefixes-minestom/src/main/kotlin/app/simplecloud/plugin/prefixes/minestom/display/MinestomDisplayManager.kt b/server/prefixes/prefixes-minestom/src/main/kotlin/app/simplecloud/plugin/prefixes/minestom/display/MinestomDisplayManager.kt index 1c7f9b1..da19bd3 100644 --- a/server/prefixes/prefixes-minestom/src/main/kotlin/app/simplecloud/plugin/prefixes/minestom/display/MinestomDisplayManager.kt +++ b/server/prefixes/prefixes-minestom/src/main/kotlin/app/simplecloud/plugin/prefixes/minestom/display/MinestomDisplayManager.kt @@ -111,6 +111,7 @@ class MinestomDisplayManager( } private fun publish(player: Player, force: Boolean = false) { + if (prefixes.api.isVanished(player.uuid)) return unpublish(player.uuid) if (!prefixes.config.get().isTablistSynced()) return val publisher = prefixes.sync?.publisher ?: return val data = registry.getData(player.uuid) ?: return diff --git a/server/prefixes/prefixes-minestom/src/main/kotlin/app/simplecloud/plugin/prefixes/minestom/platform/MinestomPlatformImpl.kt b/server/prefixes/prefixes-minestom/src/main/kotlin/app/simplecloud/plugin/prefixes/minestom/platform/MinestomPlatformImpl.kt index c3bca63..02288aa 100644 --- a/server/prefixes/prefixes-minestom/src/main/kotlin/app/simplecloud/plugin/prefixes/minestom/platform/MinestomPlatformImpl.kt +++ b/server/prefixes/prefixes-minestom/src/main/kotlin/app/simplecloud/plugin/prefixes/minestom/platform/MinestomPlatformImpl.kt @@ -28,4 +28,6 @@ class MinestomPlatformImpl( override fun getPlayerName(id: UUID): String = MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(id)?.username ?: id.toString() override fun isOnline(id: UUID): Boolean = MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(id) != null + + override fun isVanished(id: UUID): Boolean = false } diff --git a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt index 88b6193..c42fe9f 100644 --- a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt +++ b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt @@ -111,6 +111,7 @@ class PaperDisplayManager( } private fun publish(player: Player, force: Boolean = false) { + if (prefixes.api.isVanished(player.uniqueId)) return unpublish(player.uniqueId) if (!prefixes.config.get().isTablistSynced()) return val publisher = prefixes.sync?.publisher ?: return val data = registry.getData(player.uniqueId) ?: return diff --git a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/platform/PaperPlatformImpl.kt b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/platform/PaperPlatformImpl.kt index 265491c..3e0fd79 100644 --- a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/platform/PaperPlatformImpl.kt +++ b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/platform/PaperPlatformImpl.kt @@ -24,4 +24,6 @@ class PaperPlatformImpl(private val plugin: Plugin) : PrefixesPlatform { override fun getPlayerName(id: UUID): String = Bukkit.getOfflinePlayer(id).name ?: id.toString() override fun isOnline(id: UUID): Boolean = Bukkit.getPlayer(id) != null + + override fun isVanished(id: UUID): Boolean = Bukkit.getPlayer(id)?.getMetadata("vanished")?.any { it.asBoolean() } ?: false } diff --git a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/api/PrefixesApiImpl.kt b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/api/PrefixesApiImpl.kt index d2274c3..83308c1 100644 --- a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/api/PrefixesApiImpl.kt +++ b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/api/PrefixesApiImpl.kt @@ -115,6 +115,14 @@ class PrefixesApiImpl( } } + override fun setVanished(id: UUID, vanished: Boolean) { + if (!platform.isOnline(id)) return + dataRegistry.setVanished(id, vanished) + notifyDataChange(id) + } + + override fun isVanished(id: UUID): Boolean = dataRegistry.isVanished(id) || platform.isVanished(id) + override fun addGroup(group: PrefixesGroup): CompletableFuture = registry.getCurrentGroupProvider().addGroup(group) override fun registerGroupProvider(provider: GroupProvider) = registry.register(provider) diff --git a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/data/PrefixesDataRegistry.kt b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/data/PrefixesDataRegistry.kt index 8d332d8..19abd57 100644 --- a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/data/PrefixesDataRegistry.kt +++ b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/data/PrefixesDataRegistry.kt @@ -18,6 +18,7 @@ class PrefixesDataRegistry(private val platform: PrefixesPlatform) { private val groups = ConcurrentHashMap() private val overrides = ConcurrentHashMap() private val viewerOverrides = ConcurrentHashMap() + private val vanished = ConcurrentHashMap.newKeySet() fun getData(id: UUID): PrefixesPlayerData? { val group = groups[id] ?: return null @@ -60,9 +61,16 @@ class PrefixesDataRegistry(private val platform: PrefixesPlatform) { viewerOverrides.remove(ViewerKey(id, viewer)) } + fun setVanished(id: UUID, vanished: Boolean) { + if (vanished) this.vanished.add(id) else this.vanished.remove(id) + } + + fun isVanished(id: UUID): Boolean = id in vanished + fun remove(id: UUID) { groups.remove(id) overrides.remove(id) + vanished.remove(id) viewerOverrides.keys.removeIf { key -> key.target == id || key.viewer == id } } diff --git a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/platform/PrefixesPlatform.kt b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/platform/PrefixesPlatform.kt index 45e3ef2..def4ef1 100644 --- a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/platform/PrefixesPlatform.kt +++ b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/platform/PrefixesPlatform.kt @@ -16,4 +16,6 @@ interface PrefixesPlatform { fun getPlayerName(id: UUID): String fun isOnline(id: UUID): Boolean + + fun isVanished(id: UUID): Boolean } From f91b4afd31fedd23c720f8d8dd62304d078856f6 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 20 Oct 2026 16:04:51 +0200 Subject: [PATCH 2/3] feat: detect vanish changes every second on paper --- .../main/kotlin/simplecloud.base-conventions.gradle.kts | 4 ++++ gradle/libs.versions.toml | 2 ++ .../proxy-essentials-bungeecord/build.gradle.kts | 4 ---- .../proxy-essentials-shared/build.gradle.kts | 4 ---- .../proxy-essentials-velocity/build.gradle.kts | 4 ---- server/prefixes/prefixes-paper/build.gradle.kts | 1 + .../simplecloud/plugin/prefixes/paper/PrefixesPaper.kt | 2 ++ .../plugin/prefixes/paper/display/PaperDisplayManager.kt | 9 +++++++++ .../prefixes/shared/group/config/ConfigPrefixesGroup.kt | 2 +- .../prefixes/shared/group/luckperms/LuckPermsGroup.kt | 8 ++++---- 10 files changed, 23 insertions(+), 17 deletions(-) diff --git a/build-logic/src/main/kotlin/simplecloud.base-conventions.gradle.kts b/build-logic/src/main/kotlin/simplecloud.base-conventions.gradle.kts index c7cb35f..1ac3e6a 100644 --- a/build-logic/src/main/kotlin/simplecloud.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/simplecloud.base-conventions.gradle.kts @@ -57,7 +57,11 @@ tasks.test { } tasks.shadowJar { + duplicatesStrategy = DuplicatesStrategy.INCLUDE mergeServiceFiles() + filesNotMatching(listOf("META-INF/services/**", "META-INF/*.kotlin_module")) { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + } archiveFileName.set("${project.name}.jar") } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d944070..3eeb65b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,6 +19,7 @@ minestom = "26_3-SNAPSHOT" placeholderapi = "2.12.3" miniplaceholders = "3.2.0" luckperms = "5.5" +reflection-remapper = "0.1.3" adventure = "5.2.0" adventure-platform-bungeecord = "4.4.1" @@ -54,6 +55,7 @@ minestom = { module = "net.minestom:minestom", version.ref = "minestom" } placeholderapi = { module = "me.clip:placeholderapi", version.ref = "placeholderapi" } miniplaceholders-api = { module = "io.github.miniplaceholders:miniplaceholders-api", version.ref = "miniplaceholders" } luckperms-api = { module = "net.luckperms:api", version.ref = "luckperms" } +reflection-remapper = { module = "xyz.jpenilla:reflection-remapper", version.ref = "reflection-remapper" } adventure = { module = "net.kyori:adventure-api", version.ref = "adventure" } adventure-text-minimessage = { module = "net.kyori:adventure-text-minimessage", version.ref = "adventure" } diff --git a/proxy/proxy-essentials/proxy-essentials-bungeecord/build.gradle.kts b/proxy/proxy-essentials/proxy-essentials-bungeecord/build.gradle.kts index 6956905..04122b8 100644 --- a/proxy/proxy-essentials/proxy-essentials-bungeecord/build.gradle.kts +++ b/proxy/proxy-essentials/proxy-essentials-bungeecord/build.gradle.kts @@ -16,10 +16,6 @@ dependencies { compileOnly(libs.slf4j.api) } -tasks.shadowJar { - duplicatesStrategy = DuplicatesStrategy.INCLUDE -} - modrinth { token.set(project.findProperty("modrinthToken") as String? ?: System.getenv("MODRINTH_TOKEN")) projectId.set("WzfN2mLK") diff --git a/proxy/proxy-essentials/proxy-essentials-shared/build.gradle.kts b/proxy/proxy-essentials/proxy-essentials-shared/build.gradle.kts index 66b7db1..c0eece7 100644 --- a/proxy/proxy-essentials/proxy-essentials-shared/build.gradle.kts +++ b/proxy/proxy-essentials/proxy-essentials-shared/build.gradle.kts @@ -12,7 +12,3 @@ dependencies { compileOnly(libs.simplecloud.api) compileOnly(libs.slf4j.api) } - -tasks.shadowJar { - duplicatesStrategy = DuplicatesStrategy.INCLUDE -} diff --git a/proxy/proxy-essentials/proxy-essentials-velocity/build.gradle.kts b/proxy/proxy-essentials/proxy-essentials-velocity/build.gradle.kts index 6184f85..6b95b60 100644 --- a/proxy/proxy-essentials/proxy-essentials-velocity/build.gradle.kts +++ b/proxy/proxy-essentials/proxy-essentials-velocity/build.gradle.kts @@ -18,10 +18,6 @@ dependencies { kapt(libs.velocity.api) } -tasks.shadowJar { - duplicatesStrategy = DuplicatesStrategy.INCLUDE -} - modrinth { token.set(project.findProperty("modrinthToken") as String? ?: System.getenv("MODRINTH_TOKEN")) projectId.set("WzfN2mLK") diff --git a/server/prefixes/prefixes-paper/build.gradle.kts b/server/prefixes/prefixes-paper/build.gradle.kts index 4e70312..129c8f5 100644 --- a/server/prefixes/prefixes-paper/build.gradle.kts +++ b/server/prefixes/prefixes-paper/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { implementation(projects.server.prefixes.prefixesShared) implementation(projects.core.corePaper) implementation(libs.cloud.paper) + implementation(libs.reflection.remapper) compileOnly(libs.paper.api) compileOnly(libs.luckperms.api) paperweight.paperDevBundle(libs.versions.paper) diff --git a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPaper.kt b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPaper.kt index e5eb1ed..9ee056d 100644 --- a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPaper.kt +++ b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPaper.kt @@ -57,6 +57,8 @@ class PrefixesPaper : JavaPlugin() { manager.publishAll() tablist.expire() }, 30L, 30L, TimeUnit.SECONDS) + + Bukkit.getAsyncScheduler().runAtFixedRate(this, { manager.refreshVanished() }, 1L, 1L, TimeUnit.SECONDS) } private fun registerCommands(prefixes: Prefixes) { diff --git a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt index c42fe9f..8f364be 100644 --- a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt +++ b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt @@ -93,6 +93,15 @@ class PaperDisplayManager( } } + fun refreshVanished() { + if (!prefixes.config.get().isTablistSynced()) return + Bukkit.getOnlinePlayers().forEach { player -> + player.scheduler.run(plugin, { + if (prefixes.api.isVanished(player.uniqueId) == entries.containsKey(player.uniqueId)) publish(player) + }, null) + } + } + fun unpublishAll() { entries.keys.forEach(::unpublish) } diff --git a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/group/config/ConfigPrefixesGroup.kt b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/group/config/ConfigPrefixesGroup.kt index 0098581..8c1e13c 100644 --- a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/group/config/ConfigPrefixesGroup.kt +++ b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/group/config/ConfigPrefixesGroup.kt @@ -12,7 +12,7 @@ import java.util.UUID import java.util.concurrent.CompletableFuture class ConfigPrefixesGroup( - private val group: ConfigGroup, + group: ConfigGroup, private val permissionChecker: PermissionChecker, ) : PrefixesGroup { diff --git a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/group/luckperms/LuckPermsGroup.kt b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/group/luckperms/LuckPermsGroup.kt index 5bc1c04..209ef6a 100644 --- a/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/group/luckperms/LuckPermsGroup.kt +++ b/server/prefixes/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/group/luckperms/LuckPermsGroup.kt @@ -23,11 +23,11 @@ class LuckPermsGroup( override val name: String = group.name override val priority: Int = group.weight.orElse(0) override val permission: String = "group.${group.name}" - override val prefix: Component = miniMessage.deserialize(group.cachedData.metaData.prefix ?: "") - override val suffix: Component = miniMessage.deserialize(group.cachedData.metaData.suffix ?: "") + override val prefix: Component = miniMessage.deserialize(group.cachedData.metaData.prefix.orEmpty()) + override val suffix: Component = miniMessage.deserialize(group.cachedData.metaData.suffix.orEmpty()) override val color: TextColor = parseColor() - override val displayName: String = getMetaValue("display-name") ?: "" - override val chatFormat: String = getMetaValue("chat-format") ?: "" + override val displayName: String = getMetaValue("display-name").orEmpty() + override val chatFormat: String = getMetaValue("chat-format").orEmpty() override fun containsPlayer(id: UUID): CompletableFuture { val user = luckPerms.userManager.getUser(id) From dacd0a5ddd841fdd0b2a31cecd90d39fee05ac55 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 20 Oct 2026 16:18:03 +0200 Subject: [PATCH 3/3] feat: hide prefixes of vanished players from other players --- .../plugin/prefixes/paper/PrefixesPaper.kt | 3 +-- .../paper/display/PaperDisplayManager.kt | 20 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPaper.kt b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPaper.kt index 9ee056d..dfee3ee 100644 --- a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPaper.kt +++ b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPaper.kt @@ -35,6 +35,7 @@ class PrefixesPaper : JavaPlugin() { Bukkit.getPluginManager().registerEvents(PlayerListener(prefixes, manager, tablist), this) registerSync(prefixes, manager, tablist) + Bukkit.getAsyncScheduler().runAtFixedRate(this, { manager.refreshVanished() }, 1L, 1L, TimeUnit.SECONDS) prefixes.addListener(PaperPrefixesListener(this, prefixes, manager, tablist)) @@ -57,8 +58,6 @@ class PrefixesPaper : JavaPlugin() { manager.publishAll() tablist.expire() }, 30L, 30L, TimeUnit.SECONDS) - - Bukkit.getAsyncScheduler().runAtFixedRate(this, { manager.refreshVanished() }, 1L, 1L, TimeUnit.SECONDS) } private fun registerCommands(prefixes: Prefixes) { diff --git a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt index 8f364be..397eabf 100644 --- a/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt +++ b/server/prefixes/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/display/PaperDisplayManager.kt @@ -37,6 +37,7 @@ class PaperDisplayManager( private val teams = ConcurrentHashMap() private val entries = ConcurrentHashMap() + private val vanished = ConcurrentHashMap.newKeySet() fun updatePlayer(player: Player) { PrefixesConstants.SCOPE.launch(PrefixesCoroutineDetails("${player.name} (${player.uniqueId})", "update player")) { @@ -51,6 +52,7 @@ class PaperDisplayManager( fun removePlayer(player: Player) { val id = player.uniqueId registry.remove(id) + vanished.remove(id) teams.keys.filter { key -> key.target == id || key.viewer == id }.forEach { key -> if (key.viewer == id) teams.remove(key) else removeTeam(key) } @@ -94,11 +96,8 @@ class PaperDisplayManager( } fun refreshVanished() { - if (!prefixes.config.get().isTablistSynced()) return Bukkit.getOnlinePlayers().forEach { player -> - player.scheduler.run(plugin, { - if (prefixes.api.isVanished(player.uniqueId) == entries.containsKey(player.uniqueId)) publish(player) - }, null) + player.scheduler.run(plugin, { refreshVanished(player) }, null) } } @@ -106,7 +105,20 @@ class PaperDisplayManager( entries.keys.forEach(::unpublish) } + private fun refreshVanished(player: Player) { + val id = player.uniqueId + val isVanished = prefixes.api.isVanished(id) + val changed = if (isVanished) vanished.add(id) else vanished.remove(id) + + when { + changed -> show(player) + isVanished == entries.containsKey(id) -> publish(player) + } + } + private fun showTo(player: Player, viewer: Player, team: PaperPlayerTeam?) { + if (!viewer.canSee(player)) return updateTeam(player, viewer, null) + val viewerData = registry.getViewerData(player.uniqueId, viewer.uniqueId) if (viewerData == null) { updateTeam(player, viewer, team)