diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/LuckPermsGroup.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/LuckPermsGroup.kt index 50ca469..00967e8 100644 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/LuckPermsGroup.kt +++ b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/LuckPermsGroup.kt @@ -31,10 +31,10 @@ class LuckPermsGroup(private var group: Group, private var luckPerms: LuckPerms) } override fun containsPlayer(uniqueId: UUID): Boolean { - return containsPlayerFuture(uniqueId).join() + return containsPlayerAsync(uniqueId).join() } - override fun containsPlayerFuture(uniqueId: UUID): CompletableFuture { + override fun containsPlayerAsync(uniqueId: UUID): CompletableFuture { return luckPerms.userManager.loadUser(uniqueId).thenApplyAsync { user -> return@thenApplyAsync user.primaryGroup == getName() } diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesActor.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesActor.kt deleted file mode 100644 index 4b58d54..0000000 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesActor.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.simplecloud.plugin.prefixes.api - -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.TextColor -import java.util.* - -interface PrefixesActor { - fun registerViewer(target: UUID, api: PrefixesApi) - fun hasViewer(target: UUID): Boolean - fun removeViewer(target: UUID) - fun applyGroup(target: UUID, group: PrefixesGroup, vararg viewers: UUID) - fun setPrefix(target: UUID, prefix: Component, vararg viewers: UUID) - fun setSuffix(target: UUID, suffix: Component, vararg viewers: UUID) - fun setColor(target: UUID, color: TextColor, vararg viewers: UUID) - fun apply(target: UUID, prefix: Component, color: TextColor, suffix: Component, priority: Int, vararg viewers: UUID) - fun formatMessage(target: UUID, viewer: UUID?, format: String, message: Component): Component - fun remove(target: UUID) -} \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApi.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApi.kt index 75810bc..7b8a43a 100644 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApi.kt +++ b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApi.kt @@ -5,68 +5,65 @@ import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.TextColor import java.util.* -interface PrefixesApi { +interface PrefixesApi { - /** - * Registers a player to be able to see prefixes - * @param uniqueId UUID of the target player - */ - fun registerViewer(uniqueId: UUID) - - /** - * Returns if a viewer exists - * @param uniqueId UUID of the target player - */ - fun hasViewer(uniqueId: UUID): Boolean - - /** - * Removes a viewer - * @param uniqueId UUID of the target player - */ - fun removeViewer(uniqueId: UUID) + fun registerAudience(audience: Audience) + fun hasAudience(audience: Audience): Boolean + fun removeAudience(audience: Audience) /** * Sets the prefix and suffix of a player in both Tab and Chat - * @param uniqueId UUID of the target player + * @param player Target player * @param group - * @param viewers A list of all viewers of this change (if empty, everyone is affected) + * @param audience An audience to this change (if null, everyone is affected) */ - fun setWholeName(uniqueId: UUID, group: PrefixesGroup, vararg viewers: UUID) + fun setWholeName(player: Player, group: PrefixesGroup, audience: Audience? = null) /** * Sets the prefix and suffix of a player in both Tab and Chat - * @param uniqueId UUID of the target player + * @param player Target player * @param groupName - * @param viewers A list of all viewers of this change (if empty, everyone is affected) + * @param audience An audience to this change (if null, everyone is affected) */ - fun setWholeName(uniqueId: UUID, groupName: String, vararg viewers: UUID) + fun setWholeName(player: Player, groupName: String, audience: Audience? = null) /** * Sets the prefix and suffix of a player in both Tab and Chat - * @param uniqueId UUID of the target player - * @param prefix the targets prefix - * @param color the targets team color - * @param suffix the targets suffix + * @param player Target player + * @param prefix the target prefix + * @param color the target team color + * @param suffix the target suffix * @param priority the users Tablist priority - * @param viewers A list of all viewers of this change (if empty, everyone is affected) + * @param audience An audience to this change (if null, everyone is affected) */ - fun setWholeName(uniqueId: UUID, prefix: Component, color: TextColor, suffix: Component, priority: Int, vararg viewers: UUID) + fun setWholeName( + player: Player, + prefix: Component, + color: TextColor, + suffix: Component, + priority: Int, + audience: Audience? = null + ) + + fun setWholeName(player: Player, data: PrefixesPlayerData, audience: Audience? = null) + + fun editWholeName(player: Player, audience: Audience? = null, action: (PrefixesPlayerData) -> Unit) /** * Sets the prefix of a player in both Tab and Chat - * @param uniqueId UUID of the target player + * @param player Target player * @param prefix prefix to set - * @param viewers A list of all viewers of this change (if empty, everyone is affected) + * @param audience An audience to this change (if null, everyone is affected) */ - fun setPrefix(uniqueId: UUID, prefix: Component, vararg viewers: UUID) + fun setPrefix(player: Player, prefix: Component, audience: Audience? = null) /** * Sets the prefix of a player in both Tab and Chat - * @param uniqueId UUID of the target player + * @param player Target player * @param suffix suffix to set - * @param viewers A list of all viewers of this change (if empty, everyone is affected) + * @param audience An audience to this change (if null, everyone is affected) */ - fun setSuffix(uniqueId: UUID, suffix: Component, vararg viewers: UUID) + fun setSuffix(player: Player, suffix: Component, audience: Audience? = null) /** * Returns all registered [PrefixesGroup] ordered by priority @@ -75,9 +72,9 @@ interface PrefixesApi { /** * Returns the highest [PrefixesGroup] of a player - * @param uniqueId UUID of the target player + * @param player Target player */ - fun getHighestGroup(uniqueId: UUID): PrefixesGroup + fun getHighestGroup(player: Player): PrefixesGroup /** * Adds a [PrefixesGroup] @@ -85,19 +82,13 @@ interface PrefixesApi { */ fun addGroup(group: PrefixesGroup) - /** - * Changes the [PrefixesActor] of the server instance (e.g. to a bukkit actor) - * @param actor - */ - fun setActor(actor: PrefixesActor) - /** * Changes the Scoreboard Team color of the target player (Used in 1.12+ to make player names colorful) - * @param uniqueId UUID of the target player + * @param player Target player * @param color the [TextColor] of the target players team - * @param viewers A list of all viewers of this change (if empty, everyone is affected) + * @param audience An audience to this change (if null, everyone is affected) */ - fun setColor(uniqueId: UUID, color: TextColor, vararg viewers: UUID) + fun setColor(player: Player, color: TextColor, audience: Audience? = null) /** * Sets the used PrefixesConfig @@ -105,70 +96,14 @@ interface PrefixesApi { */ fun setConfig(config: PrefixesConfig) - /** - * Returns a formatted chat message of the target player that will be sent to the viewer - * @param target UUID of the target player - * @param viewer UUID of the viewing player (if null, only default prefix and suffix of the players group will be shown) - * @param format the chat format the message should follow - * @param message Message sent by the [target] - */ - fun formatChatMessage(target: UUID, viewer: UUID?, format: String, message: Component): Component - /** - * Sets the prefix and suffix of a player in both Tab and Chat - * @param uniqueId UUID of the target player - * @param group - * @param viewers A list of all viewers of this change (if empty, everyone is affected) - */ - fun setWholeName(uniqueId: UUID, group: PrefixesGroup, viewers: Audience) - - /** - * Sets the prefix and suffix of a player in both Tab and Chat - * @param uniqueId UUID of the target player - * @param groupName - * @param viewers An [Audience] of all viewers of this change (if empty, everyone is affected) - */ - fun setWholeName(uniqueId: UUID, groupName: String, viewers: Audience) - - /** - * Sets the prefix and suffix of a player in both Tab and Chat - * @param uniqueId UUID of the target player - * @param prefix the targets prefix - * @param color the targets team color - * @param suffix the targets suffix - * @param viewers An [Audience] of all viewers of this change (if empty, everyone is affected) - */ - fun setWholeName(uniqueId: UUID, prefix: Component, color: TextColor, suffix: Component, priority: Int, viewers: Audience) - /** - * Sets the prefix of a player in both Tab and Chat - * @param uniqueId UUID of the target player - * @param prefix prefix to set - * @param viewers A list of all viewers of this change (if empty, everyone is affected) - */ - fun setPrefix(uniqueId: UUID, prefix: Component, viewers: Audience) - - /** - * Sets the prefix of a player in both Tab and Chat - * @param uniqueId UUID of the target player - * @param suffix suffix to set - * @param viewers An [Audience] of all viewers of this change (if empty, everyone is affected) - */ - fun setSuffix(uniqueId: UUID, suffix: Component, viewers: Audience) - - /** - * Changes the Scoreboard Team color of the target player (Used in 1.12+ to make player names colorful) - * @param uniqueId UUID of the target player - * @param color [TextColor] the color of the target players team - * @param viewers An [Audience] of all viewers of this change (if empty, everyone is affected) - */ - fun setColor(uniqueId: UUID, color: TextColor, viewers: Audience) /** * Returns a formatted chat message of the target player that will be sent to the viewer - * @param target UUID of the target player - * @param viewer An [Audience] of the viewing player (if empty, only default prefix and suffix of the targets group will be shown) + * @param target Target player + * @param audience An audience to this change (if null, everyone is affected) * @param format the chat format the message should follow * @param message Message sent by the [target] */ - fun formatChatMessage(target: UUID, viewer: Audience, format: String, message: Component): Component + fun formatChatMessage(target: Player, format: String, message: Component, audience: Audience? = null): Component } \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApiLuckPermsImpl.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApiLuckPermsImpl.kt deleted file mode 100644 index c6b136b..0000000 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesApiLuckPermsImpl.kt +++ /dev/null @@ -1,15 +0,0 @@ -package app.simplecloud.plugin.prefixes.api - -import app.simplecloud.plugin.prefixes.api.impl.PrefixesApiImpl -import net.luckperms.api.LuckPerms - -class PrefixesApiLuckPermsImpl(private var luckPerms: LuckPerms) : PrefixesApiImpl() { - override fun indexGroups() { - getGroups().clear() - luckPerms.groupManager.loadAllGroups().newIncompleteFuture().completeAsync { - luckPerms.groupManager.loadedGroups.forEach { - addGroup(LuckPermsGroup(it, luckPerms)) - } - } - } -} \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesChatLoader.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesChatLoader.kt deleted file mode 100644 index 9814e08..0000000 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesChatLoader.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.simplecloud.plugin.prefixes.api - -import app.simplecloud.plugin.prefixes.api.impl.PrefixesApiImpl - -interface PrefixesChatLoader { - - /** - * Instantiates the chat provider of PrefixesApi (useful for sharding) - * @param api the [PrefixesApiImpl] object the ChatLoader belongs to - */ - fun load(api: PrefixesApiImpl) -} \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesConfig.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesConfig.kt index ed1f819..8d63d7d 100644 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesConfig.kt +++ b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesConfig.kt @@ -1,6 +1,9 @@ package app.simplecloud.plugin.prefixes.api -interface PrefixesConfig { - fun getChatFormat(): String +class PrefixesConfig { + private var chatFormat: String = ": " + fun getChatFormat(): String { + return chatFormat + } } \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesConfigParser.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesConfigParser.kt index 771e713..db1ee43 100644 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesConfigParser.kt +++ b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesConfigParser.kt @@ -5,8 +5,8 @@ import com.google.gson.stream.JsonReader import java.io.File import java.io.FileReader -class PrefixesConfigParser(private val configFile: File) { - fun parse(type: Class, default: C): C { +class PrefixesConfigParser(private val configFile: File) { + fun parse(type: Class, default: PrefixesConfig): PrefixesConfig { if (!configFile.exists()) return default val gson = Gson() val reader = JsonReader(FileReader(configFile)) diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesDisplay.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesDisplay.kt index 2e607aa..443f366 100644 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesDisplay.kt +++ b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesDisplay.kt @@ -1,32 +1,13 @@ package app.simplecloud.plugin.prefixes.api -import net.kyori.adventure.text.format.TextColor - -interface PrefixesDisplay { - fun createTeam(id: String, priority: Int = 0): T? - fun getTeam(id: String): T? - fun updatePrefix(id: String, prefix: C) - fun getPriority(team: T): Int? - fun updateSuffix(id: String, suffix: C) - - fun updatePriority(id: String, priority: Int): T? - fun updateColor(id: String, color: TextColor) - fun update(id: String, prefix: C, suffix: C, priority: Int) - - fun toPriorityString(priority: Int): String { - if (priority < 0) return "000" - if (priority > 999) return "999" - var result = priority.toString() - for (i in 0 until 3 - result.length) { - result = "0${result}" - } - return result - } - - fun setPlayer(id: String, player: P) - fun removePlayer(player: P) - fun setViewer(player: P): Boolean - fun addViewer(player: P): Boolean - fun removeViewer(player: P): Boolean - fun getViewers(): Set

+interface PrefixesDisplay

{ + /** + * This is called whenever we transition from another display (global display) + */ + fun transition(player: P, content: PrefixesPlayerData) + + fun apply(player: P, content: PrefixesPlayerData) + fun getCurrent(player: P): PrefixesPlayerData? + fun remove(player: P) + fun getAll(): Map } \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGlobalDisplay.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGlobalDisplay.kt index 8b43fc9..828f95e 100644 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGlobalDisplay.kt +++ b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGlobalDisplay.kt @@ -1,90 +1,74 @@ package app.simplecloud.plugin.prefixes.api -import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.audience.Audience import java.util.* -open class PrefixesGlobalDisplay { +open class PrefixesGlobalDisplay

() { - private val displays = mutableMapOf>() + private val displays = mutableMapOf>() - private var defaultDisplay: PrefixesDisplay? = null + private var defaultDisplay: PrefixesDisplay

? = null - private fun executeFor(players: List, action: (display: PrefixesDisplay) -> Unit) { - displays.filter { players.isEmpty() || players.contains(it.key) }.forEach { display -> + private fun executeFor(audience: Audience? = null, action: (display: PrefixesDisplay

) -> Unit) { + if (audience == null) { + defaultDisplay?.let { action(it) } + return + } + displays.filter { it.key == audience }.forEach { display -> action(display.value) } - if (players.isEmpty()) - defaultDisplay?.let { action(it) } } - fun getDisplay(player: UUID): Optional> { - return Optional.ofNullable(displays.getOrDefault(player, null)) + fun getDisplay(audience: Audience): Optional> { + return Optional.ofNullable(displays.getOrDefault(audience, null)) } - fun removeDisplay(player: UUID) { - displays.remove(player) + fun remove(audience: Audience) { + displays.remove(audience) } - fun getDefaultDisplay(): PrefixesDisplay? { + fun getDefaultDisplay(): PrefixesDisplay

? { return defaultDisplay } - fun setDefaultDisplay(display: PrefixesDisplay) { + fun setDefaultDisplay(display: PrefixesDisplay

) { this.defaultDisplay = display } - fun register(uuid: UUID, display: PrefixesDisplay) { - displays[uuid] = display - } - - fun createTeam(id: String) { - executeFor(displays.keys.toList()) { - it.createTeam(id) - } - } - - fun updatePrefix(id: String, prefix: C, vararg players: UUID) { - executeFor(players.toList()) { - it.updatePrefix(id, prefix) - } - } - - fun updateSuffix(id: String, suffix: C, vararg players: UUID) { - executeFor(players.toList()) { - it.updateSuffix(id, suffix) - } + fun register(audience: Audience, display: PrefixesDisplay

) { + displays[audience] = display + defaultDisplay?.getAll()?.forEach { display.apply(it.key, it.value) } } - fun updatePriority(id: String, priority: Int, vararg players: UUID) { - executeFor(players.toList()) { - it.updatePriority(id, priority) + fun apply(player: P, content: PrefixesPlayerData, audience: Audience?) { + // Remove the player from all other audiences as we change something globally + if (audience == null) { + displays.filter { it.key != defaultDisplay }.forEach { it.value.remove(player) } } - } - fun update(id: String, prefix: C, suffix: C, priority: Int, vararg players: UUID) { - executeFor(players.toList()) { - it.update(id, prefix, suffix, priority) + executeFor(audience) { + // Transition from the global display if we need to + if (it != defaultDisplay && it.getCurrent(player) == null) { + val present = defaultDisplay?.getCurrent(player) + if (present != null) { + it.transition(player, present) + } + } + it.apply(player, content) } } - open fun setPlayer(id: String, player: P, vararg players: UUID) { - executeFor(players.toList()) { - it.setPlayer(id, player) - } + fun remove(player: P) { + defaultDisplay?.remove(player) + displays.forEach { it.value.remove(player) } } - fun removePlayer(player: P, vararg players: UUID) { - executeFor(players.toList()) { - it.removePlayer(player) - } - } - - fun updateColor(id: String, color: TextColor, vararg players: UUID) { - executeFor(players.toList()) { - it.updateColor(id, color) - } + fun getCurrent(player: P, audience: Audience?): PrefixesPlayerData? { + var result: PrefixesPlayerData? = null + executeFor(audience) { result = it.getCurrent(player) } + return result } } \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGroup.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGroup.kt index 533ff5a..ccd95f4 100644 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGroup.kt +++ b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGroup.kt @@ -12,5 +12,5 @@ interface PrefixesGroup { fun getSuffix(): Component? fun getPriority(): Int fun containsPlayer(uniqueId: UUID): Boolean - fun containsPlayerFuture(uniqueId: UUID): CompletableFuture + fun containsPlayerAsync(uniqueId: UUID): CompletableFuture } \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGroupIndexer.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGroupIndexer.kt new file mode 100644 index 0000000..ea80f0c --- /dev/null +++ b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesGroupIndexer.kt @@ -0,0 +1,5 @@ +package app.simplecloud.plugin.prefixes.api + +interface PrefixesGroupIndexer { + fun indexGroups(api: PrefixesApi) +} \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesPlayerData.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesPlayerData.kt new file mode 100644 index 0000000..d2afa34 --- /dev/null +++ b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesPlayerData.kt @@ -0,0 +1,21 @@ +package app.simplecloud.plugin.prefixes.api + +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.TextColor +import org.jetbrains.annotations.ApiStatus + +data class PrefixesPlayerData( + var prefix: Component, + var suffix: Component, + var color: TextColor, + @ApiStatus.Internal + var priority: Int, +) { + fun toFormattedName(name: Component): Component { + val mutableComponent = Component.empty().append(prefix) + .append(name.color(color)).append( + suffix + ) + return mutableComponent + } +} diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesPluginLoader.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesPluginLoader.kt deleted file mode 100644 index d326c3c..0000000 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/PrefixesPluginLoader.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.simplecloud.plugin.prefixes.api - -import app.simplecloud.plugin.prefixes.api.impl.PrefixesApiImpl - -interface PrefixesPluginLoader { - - /** - * Instantiates a new PrefixesApi (useful for sharding) - * @return a [PrefixesApiImpl] (null if load failed) - */ - fun load(): PrefixesApiImpl? -} \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/impl/PrefixesActorBlankImpl.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/impl/PrefixesActorBlankImpl.kt deleted file mode 100644 index 875cbaa..0000000 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/impl/PrefixesActorBlankImpl.kt +++ /dev/null @@ -1,50 +0,0 @@ -package app.simplecloud.plugin.prefixes.api.impl - -import app.simplecloud.plugin.prefixes.api.PrefixesActor -import app.simplecloud.plugin.prefixes.api.PrefixesApi -import app.simplecloud.plugin.prefixes.api.PrefixesGroup -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.TextColor -import java.util.* - -class PrefixesActorBlankImpl : PrefixesActor { - override fun registerViewer(target: UUID, api: PrefixesApi) { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } - - override fun hasViewer(target: UUID): Boolean { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } - - override fun removeViewer(target: UUID) { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } - - override fun applyGroup(target: UUID, group: PrefixesGroup, vararg viewers: UUID) { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } - - override fun setPrefix(target: UUID, prefix: Component, vararg viewers: UUID) { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } - - override fun setSuffix(target: UUID, suffix: Component, vararg viewers: UUID) { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } - - override fun setColor(target: UUID, color: TextColor, vararg viewers: UUID) { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } - - override fun apply(target: UUID, prefix: Component, color: TextColor, suffix: Component, priority: Int, vararg viewers: UUID) { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } - - override fun formatMessage(target: UUID, viewer: UUID?, format: String, message: Component): Component { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } - - override fun remove(target: UUID) { - throw NotImplementedError("You need to define a PrefixesActor to use this") - } -} \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/impl/PrefixesApiImpl.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/impl/PrefixesApiImpl.kt deleted file mode 100644 index 8e5c5df..0000000 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/impl/PrefixesApiImpl.kt +++ /dev/null @@ -1,156 +0,0 @@ -package app.simplecloud.plugin.prefixes.api.impl - -import app.simplecloud.plugin.prefixes.api.PrefixesActor -import app.simplecloud.plugin.prefixes.api.PrefixesApi -import app.simplecloud.plugin.prefixes.api.PrefixesConfig -import app.simplecloud.plugin.prefixes.api.PrefixesGroup -import net.kyori.adventure.audience.Audience -import net.kyori.adventure.identity.Identity -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.TextColor -import java.util.* - -abstract class PrefixesApiImpl : PrefixesApi { - - private val groups: MutableList = mutableListOf() - private var actor: PrefixesActor = PrefixesActorBlankImpl() - private lateinit var config: PrefixesConfig - - override fun registerViewer(uniqueId: UUID) { - actor.registerViewer(uniqueId, this) - } - - override fun hasViewer(uniqueId: UUID): Boolean { - return actor.hasViewer(uniqueId) - } - - override fun removeViewer(uniqueId: UUID) { - actor.removeViewer(uniqueId) - } - - override fun getGroups(): MutableList { - return groups - } - - override fun getHighestGroup(uniqueId: UUID): PrefixesGroup { - return groups.stream().filter { group -> - group.containsPlayer(uniqueId) - }.findFirst().orElse(null) - } - - override fun addGroup(group: PrefixesGroup) { - groups.add(group) - } - - override fun setActor(actor: PrefixesActor) { - this.actor = actor - } - - override fun setWholeName(uniqueId: UUID, group: PrefixesGroup, viewers: Audience) { - val uuids = toUUIDList(viewers) - setWholeName(uniqueId, group, *uuids.toTypedArray()) - } - - override fun setWholeName(uniqueId: UUID, groupName: String, viewers: Audience) { - setWholeName( - uniqueId, - groups.stream().filter { group -> group.getName() == groupName }.findFirst().orElse(null), - viewers - ) - } - - override fun setWholeName( - uniqueId: UUID, - prefix: Component, - color: TextColor, - suffix: Component, - priority: Int, - viewers: Audience - ) { - val uuids = toUUIDList(viewers) - setWholeName(uniqueId, prefix, color, suffix, priority, *uuids.toTypedArray()) - } - - override fun formatChatMessage(target: UUID, viewer: Audience, format: String, message: Component): Component { - val uuid = toUUID(viewer) - return actor.formatMessage(target, uuid, format, message) - } - - override fun setPrefix(uniqueId: UUID, prefix: Component, viewers: Audience) { - val uuids = toUUIDList(viewers) - setPrefix(uniqueId, prefix, *uuids.toTypedArray()) - } - - override fun setSuffix(uniqueId: UUID, suffix: Component, viewers: Audience) { - val uuids = toUUIDList(viewers) - setSuffix(uniqueId, suffix, *uuids.toTypedArray()) - } - - override fun setColor(uniqueId: UUID, color: TextColor, viewers: Audience) { - val uuids = toUUIDList(viewers) - setColor(uniqueId, color, *uuids.toTypedArray()) - } - - override fun setWholeName(uniqueId: UUID, group: PrefixesGroup, vararg viewers: UUID) { - actor.applyGroup(uniqueId, group, *viewers) - } - - override fun setWholeName(uniqueId: UUID, groupName: String, vararg viewers: UUID) { - setWholeName( - uniqueId, - groups.stream().filter { group -> group.getName() == groupName }.findFirst().orElse(null), - *viewers - ) - } - - override fun setWholeName( - uniqueId: UUID, - prefix: Component, - color: TextColor, - suffix: Component, - priority: Int, - vararg viewers: UUID - ) { - actor.apply(uniqueId, prefix, color, suffix, priority, *viewers) - } - - override fun setPrefix(uniqueId: UUID, prefix: Component, vararg viewers: UUID) { - actor.setPrefix(uniqueId, prefix, *viewers) - } - - override fun setSuffix(uniqueId: UUID, suffix: Component, vararg viewers: UUID) { - actor.setSuffix(uniqueId, suffix, *viewers) - } - - override fun setColor(uniqueId: UUID, color: TextColor, vararg viewers: UUID) { - actor.setColor(uniqueId, color, *viewers) - } - - override fun setConfig(config: PrefixesConfig) { - this.config = config - } - - fun getConfig(): PrefixesConfig { - return config - } - - override fun formatChatMessage(target: UUID, viewer: UUID?, format: String, message: Component): Component { - return actor.formatMessage(target, viewer, format, message) - } - - private fun toUUIDList(audience: Audience): List { - val uuids = mutableListOf() - audience.forEachAudience forEachPlayer@ { - val uuid = it.get(Identity.UUID).orElse(null) ?: return@forEachPlayer - uuids.add(uuid) - } - return uuids - } - - private fun toUUID(audience: Audience): UUID? { - return audience.get(Identity.UUID).orElse(null) - } - - abstract fun indexGroups() - -} \ No newline at end of file diff --git a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/impl/PrefixesConfigImpl.kt b/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/impl/PrefixesConfigImpl.kt deleted file mode 100644 index 69a4609..0000000 --- a/prefixes-api/src/main/kotlin/app/simplecloud/plugin/prefixes/api/impl/PrefixesConfigImpl.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.simplecloud.plugin.prefixes.api.impl - -import app.simplecloud.plugin.prefixes.api.PrefixesConfig - -class PrefixesConfigImpl : PrefixesConfig { - - private var chatFormat: String = ": " - - override fun getChatFormat(): String { - return chatFormat - } -} \ No newline at end of file diff --git a/prefixes-minestom/build.gradle.kts b/prefixes-minestom/build.gradle.kts deleted file mode 100644 index 638ad69..0000000 --- a/prefixes-minestom/build.gradle.kts +++ /dev/null @@ -1,6 +0,0 @@ -dependencies { - compileOnly("dev.hollowcube:minestom-ce-snapshots:1_20_2-e7f833b499") - compileOnly("dev.hollowcube:minestom-ce-extensions:1.2.0") - api(project(":prefixes-api")) - compileOnly(files("libs/lp-minestom-5.4-SNAPSHOT-all.jar")) -} \ No newline at end of file diff --git a/prefixes-minestom/libs/lp-minestom-5.4-SNAPSHOT-all.jar b/prefixes-minestom/libs/lp-minestom-5.4-SNAPSHOT-all.jar deleted file mode 100644 index 5dac6de..0000000 Binary files a/prefixes-minestom/libs/lp-minestom-5.4-SNAPSHOT-all.jar and /dev/null differ diff --git a/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesActorMinestomImpl.kt b/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesActorMinestomImpl.kt deleted file mode 100644 index 1e508e1..0000000 --- a/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesActorMinestomImpl.kt +++ /dev/null @@ -1,106 +0,0 @@ -package app.simplecloud.plugin.prefixes.minestom - -import app.simplecloud.plugin.prefixes.api.PrefixesActor -import app.simplecloud.plugin.prefixes.api.PrefixesApi -import app.simplecloud.plugin.prefixes.api.PrefixesGroup -import app.simplecloud.plugin.prefixes.shared.MiniMessageImpl -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.NamedTextColor -import net.kyori.adventure.text.format.TextColor -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver -import net.minestom.server.MinecraftServer -import net.minestom.server.entity.Player -import java.util.* - -class PrefixesActorMinestomImpl(private var scoreboard: PrefixesGlobalDisplayMinestomImpl) : PrefixesActor { - override fun registerViewer(target: UUID, api: PrefixesApi) { - scoreboard.register(target, PrefixesTablist()) - } - - override fun hasViewer(target: UUID): Boolean { - return scoreboard.getDisplay(target).orElse(null) != null - } - - override fun removeViewer(target: UUID) { - val player = MinecraftServer.getConnectionManager().getPlayer(target) ?: return - val display = scoreboard.getDisplay(player.uuid).orElse(null) ?: return - display.removeViewer(player) - scoreboard.removeDisplay(player.uuid) - } - - override fun applyGroup( - target: UUID, - group: PrefixesGroup, - vararg viewers: UUID, - ) { - apply(target, group.getPrefix() ?: Component.text(""), group.getColor() ?: NamedTextColor.WHITE, group.getSuffix() ?: Component.text(""), group.getPriority(), *viewers) - } - - override fun remove(target: UUID) { - val player: Player = MinecraftServer.getConnectionManager().getPlayer(target) ?: return - scoreboard.removePlayer(player) - } - - override fun setPrefix(target: UUID, prefix: Component, vararg viewers: UUID) { - val player: Player = MinecraftServer.getConnectionManager().getPlayer(target) ?: return - scoreboard.updatePrefix(player.username, prefix) - } - - override fun setSuffix(target: UUID, suffix: Component, vararg viewers: UUID) { - val player: Player = MinecraftServer.getConnectionManager().getPlayer(target) ?: return - scoreboard.updateSuffix(player.username, suffix) - } - - override fun formatMessage(target: UUID, viewer: UUID?, format: String, message: Component): Component { - val targetPlayer = MinecraftServer.getConnectionManager().getPlayer(target) ?: return message - val display = if (viewer != null) scoreboard.getDisplay(viewer) - .orElse(scoreboard.getDefaultDisplay()) else scoreboard.getDefaultDisplay() ?: return message - val team = display.getTeam(targetPlayer.username) - val tags = mutableListOf() - if (team != null) { - tags.add(Placeholder.component("prefix", team.prefix)) - tags.add(Placeholder.component("suffix", team.suffix)) - tags.add( - Placeholder.component( - "name_colored", - Component.text(MinecraftServer.getConnectionManager().getPlayer(target)!!.username) - .color(team.teamColor) - ) - ) - tags.add( - Placeholder.component( - "name", - Component.text(MinecraftServer.getConnectionManager().getPlayer(target)!!.username) - ) - ) - } else { - tags.add(Placeholder.unparsed("name", "%s")) - } - tags.add(Placeholder.component("message", message)) - return MiniMessageImpl.parse(format, tags) - } - - override fun setColor(target: UUID, color: TextColor, vararg viewers: UUID) { - val player: Player = MinecraftServer.getConnectionManager().getPlayer(target) ?: return - scoreboard.updateColor(player.username, color, *viewers) - } - - override fun apply( - target: UUID, - prefix: Component, - color: TextColor, - suffix: Component, - priority: Int, - vararg viewers: UUID - ) { - val player: Player = MinecraftServer.getConnectionManager().getPlayer(target) ?: return - scoreboard.update( - player.username, - prefix, suffix, priority, - *viewers - ) - setColor(target, color, *viewers) - scoreboard.setPlayer(player.username, player, *viewers) - } -} \ No newline at end of file diff --git a/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesExtension.kt b/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesExtension.kt deleted file mode 100644 index 6efecd4..0000000 --- a/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesExtension.kt +++ /dev/null @@ -1,70 +0,0 @@ -package app.simplecloud.plugin.prefixes.minestom - -import app.simplecloud.plugin.prefixes.api.PrefixesApi -import app.simplecloud.plugin.prefixes.api.PrefixesGroup -import app.simplecloud.plugin.prefixes.api.impl.PrefixesApiImpl -import app.simplecloud.plugin.prefixes.api.impl.PrefixesConfigImpl -import app.simplecloud.plugin.prefixes.shared.MiniMessageImpl -import app.simplecloud.plugin.prefixes.api.PrefixesApiLuckPermsImpl -import app.simplecloud.plugin.prefixes.api.PrefixesConfigParser -import jdk.jfr.Experimental -import me.lucko.luckperms.minestom.LPMinestomPlugin -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.TextColor -import net.minestom.server.MinecraftServer -import net.minestom.server.event.player.AsyncPlayerConfigurationEvent -import net.minestom.server.event.player.PlayerChatEvent -import net.minestom.server.event.player.PlayerDisconnectEvent -import net.minestom.server.extensions.Extension -import java.io.File - -class PrefixesExtension : Extension() { - - companion object { - private lateinit var prefixesApi: PrefixesApiImpl - fun getApi(): PrefixesApi { - return prefixesApi - } - } - - override fun initialize() { - - @Experimental - prefixesApi = - PrefixesApiLuckPermsImpl(LPMinestomPlugin.getApi()) //! NO OFFICIAL LUCKPERMS SUPPORT RELEASED YET ! - prefixesApi.setActor(PrefixesActorMinestomImpl(PrefixesGlobalDisplayMinestomImpl())) - val config = PrefixesConfigParser(File(dataDirectory.toFile(), "config.json")).parse( - PrefixesConfigImpl::class.java, - PrefixesConfigImpl() - ) - savePackagedResource("config.json") - prefixesApi.setConfig(config) - prefixesApi.indexGroups() - MinecraftServer.getGlobalEventHandler().addListener(AsyncPlayerConfigurationEvent::class.java) { event -> - prefixesApi.registerViewer(event.player.uuid) - val prefixesGroup: PrefixesGroup = prefixesApi.getHighestGroup(event.player.uuid) - prefixesApi.setWholeName(event.player.uuid, prefixesGroup) - } - MinecraftServer.getGlobalEventHandler().addListener(PlayerChatEvent::class.java) { event -> - event.setChatFormat { - return@setChatFormat prefixesApi.formatChatMessage( - event.player.uuid, - event.player.uuid, - prefixesApi.getConfig().getChatFormat(), - MiniMessageImpl.parse(event.message) - ) - } - } - - MinecraftServer.getGlobalEventHandler().addListener(PlayerDisconnectEvent::class.java) { event -> - prefixesApi.removeViewer(event.player.uuid) - } - MinecraftServer.LOGGER.info(Component.text("PrefixesApi initialized.").color(TextColor.color(0x7cf7ab))) - } - - override fun terminate() { - - } - - -} \ No newline at end of file diff --git a/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesGlobalDisplayMinestomImpl.kt b/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesGlobalDisplayMinestomImpl.kt deleted file mode 100644 index cb55ba4..0000000 --- a/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesGlobalDisplayMinestomImpl.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.simplecloud.plugin.prefixes.minestom - -import app.simplecloud.plugin.prefixes.api.PrefixesGlobalDisplay -import net.kyori.adventure.text.Component -import net.minestom.server.entity.Player -import net.minestom.server.scoreboard.Team - -class PrefixesGlobalDisplayMinestomImpl : PrefixesGlobalDisplay() \ No newline at end of file diff --git a/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesTablist.kt b/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesTablist.kt deleted file mode 100644 index efdf9d5..0000000 --- a/prefixes-minestom/src/main/java/app/simplecloud/plugin/prefixes/minestom/PrefixesTablist.kt +++ /dev/null @@ -1,200 +0,0 @@ -package app.simplecloud.plugin.prefixes.minestom - -import app.simplecloud.plugin.prefixes.api.PrefixesDisplay -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.NamedTextColor -import net.kyori.adventure.text.format.TextColor -import net.minestom.server.MinecraftServer -import net.minestom.server.entity.Player -import net.minestom.server.network.packet.server.play.PlayerInfoUpdatePacket -import net.minestom.server.network.packet.server.play.TeamsPacket -import net.minestom.server.scoreboard.Team - -class PrefixesTablist : PrefixesDisplay { - - private val teams = mutableListOf() - private val priorities = mutableMapOf() - private val viewers = mutableSetOf() - private var color: TextColor = NamedTextColor.GRAY - override fun addViewer(player: Player): Boolean { - val result = viewers.add(player) - if (result) { - teams.forEach { team -> - player.sendPacket(getCreateTeamPacket(team)) - team.players.forEach { teamPlayer -> - getUpdatePacket(teamPlayer)?.let { player.sendPacket(it) } - } - } - } - - return result - } - - override fun removeViewer(player: Player): Boolean { - val result = viewers.remove(player) - if (result) { - teams.forEach { team -> - player.sendPacket(getRemoveTeamPacket(team)) - team.players.forEach { teamPlayer -> - player.sendPacket(getDefaultPlayerInfoPacket(teamPlayer)) - } - } - } - return result - } - - override fun getViewers(): Set { - return viewers - } - - override fun createTeam(id: String, priority: Int): Team? { - if (getTeam(id) != null) return null - val team = MinecraftServer.getTeamManager().createTeam("${toPriorityString(priority)}$id") - teams.add(team) - return team - } - - override fun getTeam(id: String): Team? { - return teams.firstOrNull { it.teamName.endsWith(id) } - } - - override fun getPriority(team: Team): Int? { - return priorities[team] - } - - fun copyTeam(team: Team, id: String, priority: Int): Team? { - val newTeam = createTeam(id, priority) ?: return null - newTeam.prefix = team.prefix - newTeam.suffix = team.suffix - newTeam.teamColor = team.teamColor - newTeam.players.addAll(team.players) - return newTeam - } - - override fun updatePriority(id: String, priority: Int): Team? { - val team = getTeam(id) ?: return null - val newTeam = copyTeam(team, id, priority) ?: return null - teams.remove(team) - priorities.remove(team) - teams.add(newTeam) - priorities[newTeam] = priority - return newTeam - } - - override fun updateColor(id: String, color: TextColor) { - val team = getTeam(id) ?: return - team.teamColor = NamedTextColor.nearestTo(color) - this.color = color - render(team) - } - - override fun setViewer(player: Player): Boolean { - viewers.forEach { removeViewer(it) } - return addViewer(player) - } - - override fun removePlayer(player: Player) { - teams.forEach { - if (it.players.contains(player)) { - it.removeMember(player.username) - } - } - } - - override fun setPlayer(id: String, player: Player) { - val team = getTeam(id) ?: createTeam(id) ?: return - team.addMember(player.username) - } - - override fun update(id: String, prefix: Component, suffix: Component, priority: Int) { - val team = updatePriority(id, priority) ?: createTeam(id, priority) ?: return - team.prefix = prefix - team.suffix = suffix - render(team) - } - - override fun updateSuffix(id: String, suffix: Component) { - val team = getTeam(id) ?: return - team.suffix = suffix - render(team) - } - - override fun updatePrefix(id: String, prefix: Component) { - val team = getTeam(id) ?: return - team.prefix = prefix - render(team) - } - - private fun getUpdatePacket(player: Player): PlayerInfoUpdatePacket? { - val team = teams.firstOrNull { it.players.contains(player) } ?: return null - return PlayerInfoUpdatePacket( - PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, PlayerInfoUpdatePacket.Entry( - player.uuid, - player.username, - listOf(), - true, - player.latency, - player.gameMode, - team.prefix.append(Component.text(player.username).color(color)).append(team.suffix), - null - ) - ) - } - - private fun getDefaultPlayerInfoPacket(player: Player): PlayerInfoUpdatePacket { - return PlayerInfoUpdatePacket( - PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, PlayerInfoUpdatePacket.Entry( - player.uuid, - player.username, - listOf(), - true, - player.latency, - player.gameMode, - player.displayName, - null - ) - ) - } - - private fun render(team: Team) { - viewers.forEach { viewer -> - team.players.forEach { player -> - getUpdatePacket(player)?.let { viewer.sendPacket(it) } - } - viewer.sendPacket(getUpdateTeamPacket(team)) - } - } - - private fun getUpdateTeamPacket(team: Team): TeamsPacket { - return TeamsPacket( - team.teamName, TeamsPacket.UpdateTeamAction( - team.teamDisplayName, - team.friendlyFlags, - team.nameTagVisibility, - team.collisionRule, - team.teamColor, - team.prefix, - team.suffix - ) - ) - } - - private fun getCreateTeamPacket(team: Team): TeamsPacket { - return TeamsPacket( - team.teamName, TeamsPacket.CreateTeamAction( - team.teamDisplayName, - team.friendlyFlags, - team.nameTagVisibility, - team.collisionRule, - team.teamColor, - team.prefix, - team.suffix, - team.members - ) - ) - } - - private fun getRemoveTeamPacket(team: Team): TeamsPacket { - return TeamsPacket(team.teamName, TeamsPacket.RemoveTeamAction()) - } -} \ No newline at end of file diff --git a/prefixes-minestom/src/main/resources/config.json b/prefixes-minestom/src/main/resources/config.json deleted file mode 100644 index efe10ef..0000000 --- a/prefixes-minestom/src/main/resources/config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "chatFormat": ": " -} \ No newline at end of file diff --git a/prefixes-minestom/src/main/resources/extension.json b/prefixes-minestom/src/main/resources/extension.json deleted file mode 100644 index 7d64099..0000000 --- a/prefixes-minestom/src/main/resources/extension.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entrypoint": "app.simplecloud.plugin.prefixes.minestom.PrefixesExtension", - "name": "Prefixes", - "version": "1.1", - "dependencies": [ - "LuckPerms" - ] -} \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPlayerTeam.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPlayerTeam.kt index 06ab565..a806c4c 100644 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPlayerTeam.kt +++ b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPlayerTeam.kt @@ -1,36 +1,25 @@ package app.simplecloud.plugin.prefixes.paper +import app.simplecloud.plugin.prefixes.api.PrefixesPlayerData import io.papermc.paper.adventure.PaperAdventure -import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor -import net.kyori.adventure.text.format.TextColor import net.minecraft.ChatFormatting import net.minecraft.world.scores.PlayerTeam import net.minecraft.world.scores.Scoreboard +import org.bukkit.entity.Player -class PaperPlayerTeam(id: String, val priority: Int = 0) : - PlayerTeam(Scoreboard(), "${toPriorityString(priority)}${id}") { +class PaperPlayerTeam(player: Player, content: PrefixesPlayerData) : + PlayerTeam(Scoreboard(), "${content.getPriorityString()}${player.name}") { init { nameTagVisibility = Visibility.NEVER - } - - var realColor: TextColor = NamedTextColor.WHITE - set(value) { - field = value - color = ChatFormatting.valueOf(NamedTextColor.nearestTo(value).toString().uppercase()) - } - - fun getFormattedName(formattedName: Component): Component { - val mutableComponent = Component.empty().append(PaperAdventure.asAdventure(this.playerPrefix)) - .append(formattedName.color(realColor)).append( - PaperAdventure.asAdventure(this.playerSuffix) - ) - return mutableComponent + color = ChatFormatting.valueOf(NamedTextColor.nearestTo(content.color).toString().uppercase()) + playerPrefix = PaperAdventure.asVanilla(content.prefix) + playerSuffix = PaperAdventure.asVanilla(content.suffix) } } -private fun toPriorityString(priority: Int): String { +private fun PrefixesPlayerData.getPriorityString(): String { if (priority < 0) return "000" if (priority > 999) return "999" var result = priority.toString() diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesActor.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesActor.kt deleted file mode 100644 index 50fc9a8..0000000 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesActor.kt +++ /dev/null @@ -1,146 +0,0 @@ -package app.simplecloud.plugin.prefixes.paper - -import app.simplecloud.plugin.prefixes.api.PrefixesActor -import app.simplecloud.plugin.prefixes.api.PrefixesApi -import app.simplecloud.plugin.prefixes.api.PrefixesGroup -import app.simplecloud.plugin.prefixes.shared.MiniMessageImpl -import io.papermc.paper.adventure.PaperAdventure -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.NamedTextColor -import net.kyori.adventure.text.format.TextColor -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver -import org.bukkit.Bukkit -import org.bukkit.entity.Player -import java.util.* - -class PaperPrefixesActor( - private var scoreboard: PaperPrefixesGlobalDisplay, -) : PrefixesActor { - - init { - scoreboard.setDefaultDisplay(PaperPrefixesDisplay()) - } - - override fun registerViewer(target: UUID, api: PrefixesApi) { - val targetPlayer = Bukkit.getPlayer(target) ?: return - val display = PaperPrefixesDisplay() - scoreboard.register(target, display) - display.setViewer(targetPlayer) - val defaultDisplay = scoreboard.getDefaultDisplay() ?: return - Bukkit.getOnlinePlayers().forEach { player -> - if (player.uniqueId != target) { - val team = defaultDisplay.getTeam(player.name) ?: return@forEach - apply( - player.uniqueId, - PaperAdventure.asAdventure(team.playerPrefix), - TextColor.color(team.realColor), - PaperAdventure.asAdventure(team.playerSuffix), - defaultDisplay.getPriority(team) ?: 0, - target - ) - } - } - } - - override fun hasViewer(target: UUID): Boolean { - return scoreboard.getDisplay(target).orElse(null) != null - } - - override fun removeViewer(target: UUID) { - val player = Bukkit.getPlayer(target) ?: return - val display = scoreboard.getDisplay(target).orElse(null) ?: return - display.removeViewer(player) - scoreboard.removeDisplay(target) - } - - override fun applyGroup( - target: UUID, - group: PrefixesGroup, - vararg viewers: UUID - ) { - val player: Player = Bukkit.getPlayer(target) ?: return - scoreboard.update( - player.name, - group.getPrefix() ?: Component.text(""), - group.getSuffix() ?: Component.text(""), - group.getPriority(), - *viewers - ) - if (group.getColor() != null) - setColor(target, group.getColor()!!, *viewers) - scoreboard.setPlayer(player.name, player, *viewers) - apply( - target, - group.getPrefix() ?: Component.text(""), - group.getColor() ?: NamedTextColor.WHITE, - group.getSuffix() ?: Component.text(""), - group.getPriority(), - *viewers - ) - } - - override fun remove(target: UUID) { - val player: Player = Bukkit.getPlayer(target) ?: return - scoreboard.removePlayer(player) - } - - override fun setPrefix(target: UUID, prefix: Component, vararg viewers: UUID) { - val player = Bukkit.getPlayer(target) ?: return - scoreboard.updatePrefix(player.name, prefix, *viewers) - } - - override fun setSuffix(target: UUID, suffix: Component, vararg viewers: UUID) { - val player = Bukkit.getPlayer(target) ?: return - scoreboard.updateSuffix(player.name, suffix, *viewers) - } - - override fun formatMessage(target: UUID, viewer: UUID?, format: String, message: Component): Component { - val display = if (viewer != null) scoreboard.getDisplay(viewer) - .orElseGet { scoreboard.getDefaultDisplay() } else scoreboard.getDefaultDisplay() ?: return message - val targetPlayer = Bukkit.getPlayer(target) ?: return message - val team: PaperPlayerTeam? = display.getTeam(targetPlayer.name) - val tags = mutableListOf() - if (team != null) { - tags.add(Placeholder.component("prefix", PaperAdventure.asAdventure(team.playerPrefix))) - tags.add(Placeholder.component("suffix", PaperAdventure.asAdventure(team.playerSuffix))) - tags.add( - Placeholder.component( - "name_colored", - Component.text(Bukkit.getPlayer(target)!!.name) - .color(team.realColor) - ) - ) - tags.add(Placeholder.unparsed("name", targetPlayer.name)) - } else { - tags.add(Placeholder.unparsed("name", targetPlayer.name)) - } - tags.add(Placeholder.component("message", message)) - return MiniMessageImpl.parse(format, tags) - } - - override fun setColor(target: UUID, color: TextColor, vararg viewers: UUID) { - val player = Bukkit.getPlayer(target) ?: return - scoreboard.updateColor(player.name, color, *viewers) - } - - override fun apply( - target: UUID, - prefix: Component, - color: TextColor, - suffix: Component, - priority: Int, - vararg viewers: UUID - ) { - val player: Player = Bukkit.getPlayer(target) ?: return - scoreboard.update( - player.name, - prefix, - suffix, - priority, - *viewers - ) - setColor(target, color, *viewers) - scoreboard.setPlayer(player.name, player, *viewers) - } -} \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesChatLoader.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesChatLoader.kt deleted file mode 100644 index efd2634..0000000 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesChatLoader.kt +++ /dev/null @@ -1,28 +0,0 @@ -package app.simplecloud.plugin.prefixes.paper - -import app.simplecloud.plugin.prefixes.api.PrefixesChatLoader -import app.simplecloud.plugin.prefixes.api.impl.PrefixesApiImpl -import io.papermc.paper.event.player.AsyncChatEvent -import net.kyori.adventure.identity.Identity -import org.bukkit.Bukkit -import org.bukkit.event.EventHandler -import org.bukkit.event.EventPriority -import org.bukkit.event.Listener -import org.bukkit.plugin.Plugin - -class PaperPrefixesChatLoader(private val plugin: Plugin) : PrefixesChatLoader, Listener { - - private lateinit var api: PrefixesApiImpl - override fun load(api: PrefixesApiImpl) { - this.api = api - Bukkit.getPluginManager().registerEvents(this, plugin) - } - - @EventHandler(priority = EventPriority.LOWEST) - fun onChat(event: AsyncChatEvent) { - event.renderer { player, _, message, audience -> - val viewer = audience.getOrDefault(Identity.UUID, null) - api.formatChatMessage(player.uniqueId, viewer, api.getConfig().getChatFormat(), message) - } - } -} \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesDisplay.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesDisplay.kt deleted file mode 100644 index 03ef68f..0000000 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesDisplay.kt +++ /dev/null @@ -1,242 +0,0 @@ -package app.simplecloud.plugin.prefixes.paper - -import app.simplecloud.plugin.prefixes.api.PrefixesDisplay -import io.papermc.paper.adventure.PaperAdventure -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.TextColor -import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket -import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket -import net.minecraft.world.level.GameType -import net.minecraft.world.scores.PlayerTeam -import org.bukkit.Bukkit -import org.bukkit.craftbukkit.entity.CraftPlayer -import org.bukkit.entity.Player -import java.util.* - -class PaperPrefixesDisplay : PrefixesDisplay { - - private val teams: MutableMap = mutableMapOf() - private val players: MutableMap = mutableMapOf() - private val viewers: MutableSet = mutableSetOf() - - override fun createTeam(id: String, priority: Int): PaperPlayerTeam? { - if (getTeam(id) != null) return null - val team = PaperPlayerTeam(id, priority) - teams[id] = team - return team - } - - override fun getTeam(id: String): PaperPlayerTeam? { - return teams.getOrDefault(id, null) - } - - override fun getPriority(team: PaperPlayerTeam): Int { - return team.priority - } - - override fun updatePriority(id: String, priority: Int): PaperPlayerTeam? { - val team = getTeam(id) ?: return null - val deletePacket = ClientboundSetPlayerTeamPacket.createRemovePacket(team) - viewers.forEach { viewer -> - (viewer as CraftPlayer).handle.connection.sendPacket(deletePacket) - } - val newTeam = changeTeamPriority(priority, team) ?: return null - val createPacket = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(newTeam, true) - val addPlayersPacket = ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket( - newTeam, - getPlayersForTeam(newTeam), - ClientboundSetPlayerTeamPacket.Action.ADD - ) - viewers.forEach { viewer -> - with(viewer as CraftPlayer) { - handle.connection.sendPacket(createPacket) - handle.connection.sendPacket(addPlayersPacket) - } - } - teams[id] = newTeam - return team - } - - override fun updateColor(id: String, color: TextColor) { - val team = getTeam(id) ?: return - team.realColor = color - val updatePacket = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, false) - viewers.forEach { viewer -> - (viewer as CraftPlayer).handle.connection.sendPacket(updatePacket) - } - sendUpdateDisplayNamePackets(team) - } - - override fun getViewers(): Set { - return viewers - } - - override fun removeViewer(player: Player): Boolean { - val result = viewers.remove(player) - if (result) { - teams.values.forEach { team -> - val deletePacket = ClientboundSetPlayerTeamPacket.createRemovePacket(team) - (player as CraftPlayer).handle.connection.sendPacket(deletePacket) - getPlayersForTeam(team).filter { Bukkit.getPlayer(it)?.isOnline ?: false } - .map { Bukkit.getPlayer(it)!! }.forEach { sendUpdateDisplayNamePacket(it) } - } - } - return result - } - - override fun addViewer(player: Player): Boolean { - val result = viewers.add(player) - if (result) { - teams.values.forEach { team -> - val createPacket = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, false) - val addPlayersPacket = ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket( - team, - getPlayersForTeam(team), - ClientboundSetPlayerTeamPacket.Action.ADD - ) - with(player as CraftPlayer) { - handle.connection.sendPacket(createPacket) - handle.connection.sendPacket(addPlayersPacket) - } - sendUpdateDisplayNamePackets(team) - } - } - return result - } - - override fun setViewer(player: Player): Boolean { - viewers.forEach { removeViewer(it) } - return addViewer(player) - } - - override fun removePlayer(player: Player) { - val playerTeam = players[player.name] ?: return - val team = teams.filter { it.key == playerTeam }.map { it.value }.firstOrNull() ?: return - players.remove(player.name) - val packet = ClientboundSetPlayerTeamPacket.createPlayerPacket( - team, - player.name, - ClientboundSetPlayerTeamPacket.Action.REMOVE - ) - viewers.forEach { viewer -> (viewer as CraftPlayer).handle.connection.sendPacket(packet) } - sendUpdateDisplayNamePackets(team) - } - - override fun setPlayer(id: String, player: Player) { - val team = teams[id] ?: return - if (players.contains(player.name)) { - teams[players[player.name]]?.let { existing -> - val delete = ClientboundSetPlayerTeamPacket.createPlayerPacket( - existing, - player.name, - ClientboundSetPlayerTeamPacket.Action.REMOVE - ) - viewers.forEach { viewer -> (viewer as CraftPlayer).handle.connection.sendPacket(delete) } - } - - } - players[player.name] = id - val packet = ClientboundSetPlayerTeamPacket.createPlayerPacket( - team, - player.name, - ClientboundSetPlayerTeamPacket.Action.ADD - ) - viewers.forEach { viewer -> (viewer as CraftPlayer).handle.connection.sendPacket(packet) } - sendUpdateDisplayNamePackets(team) - } - - override fun update(id: String, prefix: Component, suffix: Component, priority: Int) { - val exists = getTeam(id) != null - val team = updatePriority(id, priority) ?: createTeam(id, priority) ?: return - team.playerPrefix = PaperAdventure.asVanilla(prefix) - team.playerSuffix = PaperAdventure.asVanilla(suffix) - teams[id] = team - val packet = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, !exists) - - viewers.forEach { viewer -> - with(viewer as CraftPlayer) { - handle.connection.sendPacket(packet) - } - } - sendUpdateDisplayNamePackets(team) - } - - override fun updateSuffix(id: String, suffix: Component) { - val team = getTeam(id) ?: return - team.playerSuffix = PaperAdventure.asVanilla(suffix) - teams[id] = team - val packet = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, false) - viewers.forEach { viewer -> - with(viewer as CraftPlayer) { - handle.connection.sendPacket(packet) - } - } - sendUpdateDisplayNamePackets(team) - } - - override fun updatePrefix(id: String, prefix: Component) { - val team = getTeam(id) ?: return - team.playerPrefix = PaperAdventure.asVanilla(prefix) - teams[id] = team - val packet = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, false) - viewers.forEach { viewer -> - with(viewer as CraftPlayer) { - handle.connection.sendPacket(packet) - } - } - sendUpdateDisplayNamePackets(team) - } - - private fun sendUpdateDisplayNamePackets(team: PaperPlayerTeam) { - val id = teams.filter { it.value == team }.keys.firstOrNull() ?: return - val players = players.filter { it.value == id && Bukkit.getPlayer(it.key)?.isOnline ?: false }.keys.map { - Bukkit.getPlayer(it)!! - } - players.forEach { player -> sendUpdateDisplayNamePacket(player, team) } - } - - private fun sendUpdateDisplayNamePacket(player: Player, passed: PaperPlayerTeam? = null) { - val team = passed ?: teams[players[player.name]] - val update = ClientboundPlayerInfoUpdatePacket( - EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME), - ClientboundPlayerInfoUpdatePacket.Entry( - player.uniqueId, - null, - true, - -1, - GameType.ADVENTURE, - PaperAdventure.asVanilla(team?.getFormattedName(player.name()) ?: player.name()), - true, - -1, - null - ) - ) - viewers.forEach { viewer -> - with(viewer as CraftPlayer) { - handle.connection.sendPacket(update) - } - } - } - - private fun changeTeamPriority(priority: Int, team: PaperPlayerTeam): PaperPlayerTeam? { - val id = teams.filter { it.value == team }.keys.firstOrNull() ?: return null - val playersInTeam = getPlayersForTeam(team) - val newTeam = PaperPlayerTeam(id, priority) - playersInTeam.forEach { player -> players[player] = id } - newTeam.playerPrefix = team.playerPrefix - newTeam.displayName = team.displayName - newTeam.playerSuffix = team.playerSuffix - newTeam.nameTagVisibility = team.nameTagVisibility - newTeam.setSeeFriendlyInvisibles(team.canSeeFriendlyInvisibles()) - newTeam.deathMessageVisibility = team.deathMessageVisibility - newTeam.collisionRule = team.collisionRule - newTeam.realColor = team.realColor - return newTeam - } - - private fun getPlayersForTeam(team: PlayerTeam): List { - val id = teams.filter { it.value == team }.keys.firstOrNull() ?: return emptyList() - return players.filter { it.value == id } - .map { it.key } - } -} \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesGlobalDisplay.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesGlobalDisplay.kt deleted file mode 100644 index 55290b2..0000000 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesGlobalDisplay.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.simplecloud.plugin.prefixes.paper - -import app.simplecloud.plugin.prefixes.api.PrefixesGlobalDisplay -import net.kyori.adventure.text.Component -import org.bukkit.entity.Player -import space.chunks.customname.api.CustomNameManager -import java.util.* - -class PaperPrefixesGlobalDisplay( - private val name: CustomNameManager -) : PrefixesGlobalDisplay() { - - override fun setPlayer(id: String, player: Player, vararg players: UUID) { - super.setPlayer(id, player, *players) - name.forEntity(player).setName { viewer -> - val defaultDisplay = getDefaultDisplay() ?: return@setName Component.text(player.name) - val display = getDisplay(viewer.uniqueId).orElse(null) ?: defaultDisplay - val team = display.getTeam(player.name) ?: defaultDisplay.getTeam(player.name) - ?: return@setName Component.text(player.name) - return@setName team.getFormattedName( - Component.text( - player.name - ) - ) - } - } -} \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesLoader.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesLoader.kt index 8b1bc17..ea126f0 100644 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesLoader.kt +++ b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PaperPrefixesLoader.kt @@ -1,24 +1,12 @@ package app.simplecloud.plugin.prefixes.paper import app.simplecloud.plugin.prefixes.api.PrefixesApi -import app.simplecloud.plugin.prefixes.api.PrefixesChatLoader -import app.simplecloud.plugin.prefixes.api.PrefixesPluginLoader -import app.simplecloud.plugin.prefixes.api.impl.PrefixesApiImpl -import app.simplecloud.plugin.prefixes.api.impl.PrefixesConfigImpl -import app.simplecloud.plugin.prefixes.paper.event.PrefixesConfigureEvent -import app.simplecloud.plugin.prefixes.paper.event.PrefixesConfiguredEvent -import app.simplecloud.plugin.prefixes.paper.listener.LuckPermsListener -import app.simplecloud.plugin.prefixes.api.PrefixesApiLuckPermsImpl +import app.simplecloud.plugin.prefixes.api.PrefixesConfig import app.simplecloud.plugin.prefixes.api.PrefixesConfigParser -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.NamedTextColor +import app.simplecloud.plugin.prefixes.paper.impl.LuckPermsPrefixesApiImpl import net.luckperms.api.LuckPerms import org.bukkit.Bukkit import org.bukkit.entity.Player -import org.bukkit.event.EventHandler -import org.bukkit.event.Listener -import org.bukkit.event.player.PlayerJoinEvent -import org.bukkit.event.player.PlayerQuitEvent import org.bukkit.plugin.Plugin import org.bukkit.plugin.RegisteredServiceProvider import org.bukkit.plugin.ServicePriority @@ -27,72 +15,25 @@ import java.io.File class PaperPrefixesLoader( private val plugin: Plugin, - private val chatLoader: PrefixesChatLoader -) : PrefixesPluginLoader, Listener { +) { - private lateinit var api: PrefixesApiImpl - private lateinit var actor: PaperPrefixesActor - override fun load(): PrefixesApiImpl? { + private lateinit var api: LuckPermsPrefixesApiImpl + fun load(): PrefixesApi? { val customNameManager = Bukkit.getServicesManager().load(CustomNameManager::class.java) ?: return null val luckPermsProvider: RegisteredServiceProvider = Bukkit.getServicesManager().getRegistration(LuckPerms::class.java) ?: return null - actor = PaperPrefixesActor(PaperPrefixesGlobalDisplay(customNameManager)) val luckPerms: LuckPerms = luckPermsProvider.provider - api = PrefixesApiLuckPermsImpl(luckPerms) - api.setActor(actor) + api = LuckPermsPrefixesApiImpl(luckPerms, plugin, customNameManager) api.setConfig( - PrefixesConfigParser(File(plugin.dataFolder, "config.json")).parse( - PrefixesConfigImpl::class.java, - PrefixesConfigImpl() + PrefixesConfigParser(File(plugin.dataFolder, "config.json")).parse( + PrefixesConfig::class.java, + PrefixesConfig() ) ) plugin.saveResource("config.json", false) - api.indexGroups() - Bukkit.getPluginManager().registerEvents(this, plugin) + api.indexGroups(api) + Bukkit.getPluginManager().registerEvents(api, plugin) Bukkit.getServicesManager().register(PrefixesApi::class.java, api, plugin, ServicePriority.Normal) - - chatLoader.load(api) - LuckPermsListener(plugin, luckPerms, api).init() return api } - - @EventHandler - fun onJoin(event: PlayerJoinEvent) { - Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, Runnable { - if (!api.hasViewer(event.player.uniqueId)) { - api.registerViewer(event.player.uniqueId) - applyFirstName(api, plugin, event.player) - } - }, 10L) - } - - @EventHandler - fun onQuit(event: PlayerQuitEvent) { - api.removeViewer(event.player.uniqueId) - actor.remove(event.player.uniqueId) - } - - companion object { - fun applyFirstName(api: PrefixesApi, plugin: Plugin, player: Player) { - val group = api.getHighestGroup(player.uniqueId) - Bukkit.getScheduler().runTask(plugin, Runnable { - val prefixData = PrefixesConfigureEvent( - player, - group.getPrefix(), - group.getSuffix(), - group.getColor(), - group.getPriority() - ) - Bukkit.getPluginManager().callEvent(prefixData) - api.setWholeName( - player.uniqueId, - prefixData.prefix ?: Component.text(""), - prefixData.color ?: NamedTextColor.WHITE, - prefixData.suffix ?: Component.text(""), - prefixData.priority - ) - Bukkit.getPluginManager().callEvent(PrefixesConfiguredEvent(player)) - }) - } - } } \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPlugin.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPlugin.kt index be21b6a..88e2758 100644 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPlugin.kt +++ b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/PrefixesPlugin.kt @@ -5,7 +5,7 @@ import org.bukkit.plugin.java.JavaPlugin class PrefixesPlugin : JavaPlugin(), Listener { override fun onEnable() { - val loader = PaperPrefixesLoader(this, PaperPrefixesChatLoader(this)) + val loader = PaperPrefixesLoader(this) if (loader.load() == null) { throw NullPointerException("The Prefixes Plugin could not load correctly") } diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/event/PrefixesConfigureEvent.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/event/PrefixesConfigureEvent.kt index 1a3e481..47fe4f5 100644 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/event/PrefixesConfigureEvent.kt +++ b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/event/PrefixesConfigureEvent.kt @@ -1,7 +1,6 @@ package app.simplecloud.plugin.prefixes.paper.event -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.TextColor +import app.simplecloud.plugin.prefixes.api.PrefixesPlayerData import org.bukkit.entity.Player import org.bukkit.event.Event import org.bukkit.event.HandlerList @@ -12,18 +11,17 @@ import org.bukkit.event.HandlerList */ data class PrefixesConfigureEvent( val player: Player, - var prefix: Component?, - var suffix: Component?, - var color: TextColor?, - var priority: Int, -): Event() { + val data: PrefixesPlayerData, +) : Event() { companion object { private val handlers: HandlerList = HandlerList() + @JvmStatic fun getHandlerList(): HandlerList { return handlers } } + override fun getHandlers(): HandlerList { return Companion.handlers } diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/event/PrefixesConfiguredEvent.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/event/PrefixesConfiguredEvent.kt index 1bc5260..3c1633a 100644 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/event/PrefixesConfiguredEvent.kt +++ b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/event/PrefixesConfiguredEvent.kt @@ -5,22 +5,24 @@ import org.bukkit.event.Event import org.bukkit.event.HandlerList /** - * This event is called when a player was successfully registered in the [app.simplecloud.plugin.prefixes.api.PrefixesActor]. - * If you want to create custom logic (e.g. a custom suffix visible to the friends of this player) + * This event is called when a player was successfully registered in the API. + * If you want to create custom logic (e.g., a custom suffix visible to the friends of this player), * you have to do it when listening on this event to make sure it works correctly. */ data class PrefixesConfiguredEvent( val player: Player -): Event() { +) : Event() { companion object { private val handlers: HandlerList = HandlerList() + @JvmStatic fun getHandlerList(): HandlerList { return handlers } } + override fun getHandlers(): HandlerList { - return Companion.handlers + return Companion.handlers } } \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/LuckPermsPrefixesApiImpl.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/LuckPermsPrefixesApiImpl.kt new file mode 100644 index 0000000..388a90a --- /dev/null +++ b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/LuckPermsPrefixesApiImpl.kt @@ -0,0 +1,43 @@ +package app.simplecloud.plugin.prefixes.paper.impl + +import app.simplecloud.plugin.prefixes.api.LuckPermsGroup +import app.simplecloud.plugin.prefixes.api.PrefixesApi +import app.simplecloud.plugin.prefixes.api.PrefixesGroupIndexer +import net.luckperms.api.LuckPerms +import net.luckperms.api.event.node.NodeMutateEvent +import net.luckperms.api.event.user.track.UserPromoteEvent +import net.luckperms.api.model.group.Group +import org.bukkit.Bukkit +import org.bukkit.entity.Player +import org.bukkit.plugin.Plugin +import space.chunks.customname.api.CustomNameManager +import kotlin.jvm.optionals.getOrNull + +class LuckPermsPrefixesApiImpl( + private val luckPerms: LuckPerms, + private val plugin: Plugin, + name: CustomNameManager +) : PaperPrefixesApiImpl(plugin, name), PrefixesGroupIndexer { + + override fun indexGroups(api: PrefixesApi) { + luckPerms.groupManager.loadAllGroups().newIncompleteFuture().completeAsync { + luckPerms.groupManager.loadedGroups.forEach { + addGroup(LuckPermsGroup(it, luckPerms)) + } + } + luckPerms.eventBus.subscribe(plugin, UserPromoteEvent::class.java) { event -> + val newGroup = event.groupTo.getOrNull() ?: return@subscribe + val player = Bukkit.getPlayer(event.user.uniqueId) ?: return@subscribe + if (!player.isOnline) return@subscribe + setWholeName(player, newGroup) + } + luckPerms.eventBus.subscribe(plugin, NodeMutateEvent::class.java) { event -> + if (!event.isGroup) return@subscribe + val group = event.target as Group + storedGroups.removeIf { it.getName() == group.name } + val updated = LuckPermsGroup(group, luckPerms) + addGroup(updated) + Bukkit.getOnlinePlayers().forEach { if (getHighestGroup(it) == updated) setWholeName(it, updated) } + } + } +} \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/PaperPrefixesApiImpl.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/PaperPrefixesApiImpl.kt new file mode 100644 index 0000000..3cfc094 --- /dev/null +++ b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/PaperPrefixesApiImpl.kt @@ -0,0 +1,223 @@ +package app.simplecloud.plugin.prefixes.paper.impl + +import app.simplecloud.plugin.prefixes.api.PrefixesApi +import app.simplecloud.plugin.prefixes.api.PrefixesConfig +import app.simplecloud.plugin.prefixes.api.PrefixesGroup +import app.simplecloud.plugin.prefixes.api.PrefixesPlayerData +import app.simplecloud.plugin.prefixes.paper.event.PrefixesConfigureEvent +import app.simplecloud.plugin.prefixes.paper.event.PrefixesConfiguredEvent +import app.simplecloud.plugin.prefixes.shared.MiniMessageImpl +import io.papermc.paper.event.player.AsyncChatEvent +import io.papermc.paper.event.player.PlayerClientLoadedWorldEvent +import net.kyori.adventure.audience.Audience +import net.kyori.adventure.identity.Identity +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver +import org.bukkit.Bukkit +import org.bukkit.entity.Player +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.player.PlayerJoinEvent +import org.bukkit.event.player.PlayerQuitEvent +import org.bukkit.plugin.Plugin +import org.jetbrains.annotations.ApiStatus +import space.chunks.customname.api.CustomNameManager + +open class PaperPrefixesApiImpl(private val plugin: Plugin, private val name: CustomNameManager) : PrefixesApi, + Listener { + + protected val storedGroups = mutableListOf() + private val display = PaperPrefixesGlobalDisplayImpl() + private lateinit var config: PrefixesConfig + + @ApiStatus.Internal + override fun registerAudience(audience: Audience) { + audience.toSingleAudiences().forEach { + display.register(it, PaperPrefixesDisplayImpl(it)) + } + } + + @ApiStatus.Internal + override fun hasAudience(audience: Audience): Boolean { + return !audience.toSingleAudiences().any { !display.getDisplay(it).isPresent } + } + + @ApiStatus.Internal + override fun removeAudience(audience: Audience) { + audience.toSingleAudiences().forEach { + display.remove(it) + } + } + + override fun setWholeName( + player: Player, group: PrefixesGroup, audience: Audience? + ) { + setWholeName(player, groupToData(group), audience) + } + + override fun setWholeName( + player: Player, groupName: String, audience: Audience? + ) { + setWholeName(player, storedGroups.firstOrNull { it.getName() == groupName } ?: return, audience) + } + + override fun setWholeName( + player: Player, prefix: Component, color: TextColor, suffix: Component, priority: Int, audience: Audience? + ) { + setWholeName(player, PrefixesPlayerData(prefix, suffix, color, priority), audience) + } + + override fun setWholeName( + player: Player, data: PrefixesPlayerData, audience: Audience? + ) { + if (audience == null) { + display.apply(player, data, audience) + return + } + audience.toSingleAudiences().forEach { + display.apply(player, data, it) + } + } + + override fun editWholeName( + player: Player, audience: Audience?, action: (PrefixesPlayerData) -> Unit + ) { + val current = display.getCurrent(player, audience) ?: return + action(current) + setWholeName(player, current, audience) + } + + override fun setPrefix( + player: Player, prefix: Component, audience: Audience? + ) { + editWholeName(player, audience) { + it.prefix = prefix + } + } + + override fun setSuffix( + player: Player, suffix: Component, audience: Audience? + ) { + editWholeName(player, audience) { + it.suffix = suffix + } + } + + override fun getGroups(): List { + return storedGroups.toList() + } + + override fun getHighestGroup(player: Player): PrefixesGroup { + return storedGroups.filter { it.containsPlayer(player.uniqueId) }.minByOrNull { it.getPriority() } + ?: storedGroups.first() + } + + override fun addGroup(group: PrefixesGroup) { + storedGroups.add(group) + } + + override fun setColor( + player: Player, color: TextColor, audience: Audience? + ) { + editWholeName(player, audience) { + it.color = color + } + } + + override fun setConfig(config: PrefixesConfig) { + this.config = config + } + + override fun formatChatMessage( + target: Player, format: String, message: Component, audience: Audience? + ): Component { + val usedDisplay = if (audience != null) display.getDisplay(audience) + .orElseGet { display.getDefaultDisplay() } else display.getDefaultDisplay() ?: return message + val data = usedDisplay.getCurrent(target) ?: display.getDefaultDisplay()?.getCurrent(target) + val tags = mutableListOf() + if (data != null) { + tags.add(Placeholder.component("prefix", data.prefix)) + tags.add(Placeholder.component("suffix", data.suffix)) + tags.add( + Placeholder.component( + "name_colored", Component.text(target.name).color(data.color) + ) + ) + tags.add(Placeholder.unparsed("name", target.name)) + } else { + tags.add(Placeholder.unparsed("name", target.name)) + } + tags.add(Placeholder.component("message", message)) + return MiniMessageImpl.parse(format, tags) + } + + private fun groupToData(group: PrefixesGroup): PrefixesPlayerData { + return PrefixesPlayerData( + group.getPrefix() ?: Component.empty(), + group.getSuffix() ?: Component.empty(), + group.getColor() ?: NamedTextColor.WHITE, + group.getPriority() + ) + } + + private fun applyJoinName(player: Player) { + val group = getHighestGroup(player) + Bukkit.getScheduler().runTask(plugin, Runnable { + val data = groupToData(group) + val prefixData = PrefixesConfigureEvent( + player, data + ) + Bukkit.getPluginManager().callEvent(prefixData) + setWholeName( + player, data + ) + Bukkit.getPluginManager().callEvent(PrefixesConfiguredEvent(player)) + }) + } + + @EventHandler + fun onJoin(event: PlayerJoinEvent) { + applyJoinName(event.player) + name.forEntity(event.player).setName { viewer -> + val usedDisplay = display.getDisplay(viewer) + .orElseGet { display.getDefaultDisplay() } + val data = + usedDisplay.getCurrent(event.player) ?: display.getDefaultDisplay()?.getCurrent(event.player) + return@setName data?.toFormattedName(event.player.name()) + ?: event.player.name() + } + } + + // TODO: Find a better event to listen to, we want to register the audience directly after all online player infos have loaded, for now this is one tick delayed + @EventHandler + fun onPacketReady(event: PlayerClientLoadedWorldEvent) { + if (hasAudience(event.player)) return + registerAudience(event.player) + } + + @EventHandler + fun onQuit(event: PlayerQuitEvent) { + removeAudience(event.player) + display.remove(event.player) + } + + @EventHandler + fun onChat(event: AsyncChatEvent) { + event.renderer { player, _, message, viewer -> + return@renderer formatChatMessage(player, config.getChatFormat(), message, viewer) + } + } +} + +private fun Audience.toSingleAudiences(): List { + val uuid = this.get(Identity.UUID) + if (uuid.isPresent) { + return listOf(this) + } + val result = mutableListOf() + this.forEachAudience { if (it != this) result.addAll(it.toSingleAudiences()) } + return result +} \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/PaperPrefixesDisplayImpl.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/PaperPrefixesDisplayImpl.kt new file mode 100644 index 0000000..05cca9b --- /dev/null +++ b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/PaperPrefixesDisplayImpl.kt @@ -0,0 +1,125 @@ +package app.simplecloud.plugin.prefixes.paper.impl + +import app.simplecloud.plugin.prefixes.api.PrefixesDisplay +import app.simplecloud.plugin.prefixes.api.PrefixesPlayerData +import app.simplecloud.plugin.prefixes.paper.PaperPlayerTeam +import io.papermc.paper.adventure.PaperAdventure +import net.kyori.adventure.audience.Audience +import net.kyori.adventure.identity.Identity +import net.kyori.adventure.text.Component +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket +import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.level.GameType +import org.bukkit.Bukkit +import org.bukkit.craftbukkit.entity.CraftPlayer +import org.bukkit.entity.Player +import java.util.* + +class PaperPrefixesDisplayImpl( + private val audience: Audience +) : PrefixesDisplay { + + private val displayed = mutableMapOf() + + override fun transition( + player: Player, + content: PrefixesPlayerData + ) { + displayed[player.uniqueId] = content + } + + override fun apply( + player: Player, content: PrefixesPlayerData + ) { + val handles = toHandles() + if (!displayed.containsKey(player.uniqueId)) { + create(player, content, handles) + } else if (displayed[player.uniqueId]?.priority != content.priority) { + recreate(player, content, handles) + } else updateVisuals(player, content, handles) + sendUpdateDisplayNamePackets(player, content.toFormattedName(player.name()), handles) + } + + override fun getCurrent(player: Player): PrefixesPlayerData? { + return displayed[player.uniqueId] + } + + private fun updateVisuals(player: Player, content: PrefixesPlayerData, handles: List) { + displayed[player.uniqueId] = content + sendUpdatePackets(PaperPlayerTeam(player, content), handles) + } + + private fun recreate(player: Player, content: PrefixesPlayerData, handles: List) { + val oldTeam = PaperPlayerTeam(player, displayed[player.uniqueId] ?: return) + val newTeam = PaperPlayerTeam(player, content) + sendRemovePackets(oldTeam, handles) + sendCreatePackets(player, newTeam, handles) + displayed[player.uniqueId] = content + } + + private fun create(player: Player, content: PrefixesPlayerData, handles: List) { + displayed[player.uniqueId] = content + val team = PaperPlayerTeam(player, content) + sendCreatePackets(player, team, handles) + } + + override fun remove(player: Player) { + val team = PaperPlayerTeam(player, displayed[player.uniqueId] ?: return) + displayed.remove(player.uniqueId) + val handles = toHandles() + sendRemovePackets(team, handles) + sendUpdateDisplayNamePackets(player, player.name(), handles) + } + + override fun getAll(): Map { + return displayed.filter { Bukkit.getPlayer(it.key)?.isOnline ?: false } + .map { Bukkit.getPlayer(it.key)!! to it.value }.toMap() + } + + private fun sendCreatePackets(player: Player, team: PaperPlayerTeam, handles: List) { + val createTeam = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true) + val addPlayers = ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket( + team, listOf(player.name), ClientboundSetPlayerTeamPacket.Action.ADD + ) + handles.forEach { + it.connection.send(createTeam) + it.connection.send(addPlayers) + } + } + + private fun sendUpdatePackets(team: PaperPlayerTeam, handles: List) { + val updateTeam = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, false) + handles.forEach { it.connection.send(updateTeam) } + } + + private fun sendRemovePackets(team: PaperPlayerTeam, handles: List) { + val deleteTeam = ClientboundSetPlayerTeamPacket.createRemovePacket(team) + handles.forEach { it.connection.send(deleteTeam) } + } + + private fun sendUpdateDisplayNamePackets(player: Player, name: Component, handles: List) { + val update = ClientboundPlayerInfoUpdatePacket( + EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME), + ClientboundPlayerInfoUpdatePacket.Entry( + player.uniqueId, null, true, -1, GameType.ADVENTURE, PaperAdventure.asVanilla(name), true, -1, null + ) + ) + handles.forEach { it.connection.send(update) } + } + + private fun toHandles( + currentAudience: Audience = audience, current: MutableList = mutableListOf() + ): MutableList { + val uniqueId = currentAudience.get(Identity.UUID) + if (uniqueId.isPresent) { + val player = Bukkit.getPlayer(uniqueId.get()) + if (player?.isOnline ?: false) { + current.add((player as CraftPlayer).handle) + return current + } + } + currentAudience.forEachAudience { if (it != currentAudience) toHandles(it, current) } + return current + } +} \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/PaperPrefixesGlobalDisplayImpl.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/PaperPrefixesGlobalDisplayImpl.kt new file mode 100644 index 0000000..0b2932e --- /dev/null +++ b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/impl/PaperPrefixesGlobalDisplayImpl.kt @@ -0,0 +1,13 @@ +package app.simplecloud.plugin.prefixes.paper.impl + +import app.simplecloud.plugin.prefixes.api.PrefixesGlobalDisplay +import net.kyori.adventure.audience.ForwardingAudience +import org.bukkit.Bukkit +import org.bukkit.entity.Player + +class PaperPrefixesGlobalDisplayImpl : + PrefixesGlobalDisplay() { + init { + setDefaultDisplay(PaperPrefixesDisplayImpl(ForwardingAudience { Bukkit.getOnlinePlayers() })) + } +} \ No newline at end of file diff --git a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/listener/LuckPermsListener.kt b/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/listener/LuckPermsListener.kt deleted file mode 100644 index 02628a1..0000000 --- a/prefixes-paper/src/main/kotlin/app/simplecloud/plugin/prefixes/paper/listener/LuckPermsListener.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.simplecloud.plugin.prefixes.paper.listener - -import app.simplecloud.plugin.prefixes.api.PrefixesApi -import net.luckperms.api.LuckPerms -import net.luckperms.api.event.user.UserDataRecalculateEvent -import org.bukkit.plugin.Plugin - -class LuckPermsListener( - private val plugin: Plugin, - private val luckPerms: LuckPerms, - private val api: PrefixesApi -) { - - fun init() { - val eventBus = luckPerms.eventBus - eventBus.subscribe(plugin, UserDataRecalculateEvent::class.java, this::onUserUpdate) - } - - private val groups: MutableMap = mutableMapOf() - - private fun onUserUpdate(event: UserDataRecalculateEvent) { - if(groups.getOrDefault(event.user.uniqueId.toString(), "") == event.user.primaryGroup) return - groups[event.user.uniqueId.toString()] = event.user.primaryGroup - api.setWholeName(event.user.uniqueId, event.user.primaryGroup) - } - -} \ No newline at end of file diff --git a/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/ComponentSerializerImpl.kt b/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/ComponentSerializerImpl.kt index f466c83..4f63245 100644 --- a/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/ComponentSerializerImpl.kt +++ b/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/ComponentSerializerImpl.kt @@ -1,25 +1,14 @@ package app.simplecloud.plugin.prefixes.shared import net.kyori.adventure.text.Component -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer class ComponentSerializerImpl { companion object { - private val impl = - GsonComponentSerializer.builder().build() private val legacyImpl = LegacyComponentSerializer.builder().hexColors().character('§').useUnusualXRepeatedCharacterHexFormat() .hexCharacter('x').build() - private fun serialize(component: Component): String { - return impl.serialize(component) - } - - fun serializeLegacy(component: Component): String { - return legacyImpl.serialize(component) - } - fun deserializeLegacy(text: String): Component { return legacyImpl.deserialize(text) } diff --git a/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/MiniMessageImpl.kt b/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/MiniMessageImpl.kt index 77d1d5e..be80d92 100644 --- a/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/MiniMessageImpl.kt +++ b/prefixes-shared/src/main/kotlin/app/simplecloud/plugin/prefixes/shared/MiniMessageImpl.kt @@ -14,13 +14,6 @@ class MiniMessageImpl { return miniMessage.deserialize(text) } - fun parse(text: String, vararg tags: TagResolver): Component { - if (text.contains("§")) { - return ComponentSerializerImpl.deserializeLegacy(text) - } - return miniMessage.deserialize(text, TagResolver.resolver(tags.asIterable())) - } - fun parse(text: String, tags: Iterable): Component { if (text.contains("§")) { return ComponentSerializerImpl.deserializeLegacy(text)