Instantly share code, notes, and snippets.
Last active
March 1, 2022 14:32
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save nathanfranke/1ddd81ad8913d33b8b7c46f931ee5250 to your computer and use it in GitHub Desktop.
All Zeros Sidebar in Paper 1.18.2 (1.8 Compatible)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.nathanfranke.sidebarplugin | |
import net.kyori.adventure.text.Component | |
import net.kyori.adventure.text.format.NamedTextColor | |
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer | |
import org.bukkit.ChatColor | |
import org.bukkit.entity.Player | |
import org.bukkit.event.EventHandler | |
import org.bukkit.event.Listener | |
import org.bukkit.event.player.PlayerJoinEvent | |
import org.bukkit.plugin.java.JavaPlugin | |
import org.bukkit.scoreboard.DisplaySlot | |
import org.bukkit.scoreboard.Objective | |
private val objectiveEntries = mutableMapOf<Objective, Set<String>>() | |
fun Player.updateSidebar(title: Component, items: List<Component>) { | |
// Create the sidebar objective if it does not exist. | |
val objective = scoreboard.getObjective(DisplaySlot.SIDEBAR) ?: run { | |
scoreboard.registerNewObjective("@sidebar", "dummy", null).apply { | |
displaySlot = DisplaySlot.SIDEBAR | |
} | |
} | |
objective.displayName(title) | |
// Prefix all scoreboard prefixes with this text to ensure they are ordered properly. | |
val orderedLetters = ('a'..'z').toList() | |
fun getOrderedPrefix(index: Int) = "\u00A7${orderedLetters[index]}\u00A7r" | |
// Keep track of added objective scores, so they can be removed later. | |
val entries = mutableSetOf<String>() | |
for ((i, item) in items.withIndex()) { | |
// Legacy players (pre-1.13) can only have 42 characters per line (14 prefix, 12 entry, 16 suffix). | |
if (protocolVersion < 393) { | |
val prefixLength = 14 // Maximum of 16, with 2 characters reserved for the team color (used internally). | |
val entryLength = 12 // Maximum of 16, with 4 characters reserved for the ordering prefix. | |
val suffixLength = 16 // Maximum of 16. | |
// Convert item text into legacy text. | |
var text = LegacyComponentSerializer.legacySection().serialize(item) | |
// Separate as much text as possible into the prefix. | |
val (prefix, prefixRemaining) = run { | |
for (n in Integer.min(text.length, prefixLength) downTo 0) { | |
val prefix = text.substring(0, n) | |
if (prefix.endsWith(ChatColor.COLOR_CHAR)) { | |
continue | |
} | |
val lastColors = ChatColor.getLastColors(prefix) | |
val remaining = text.substring(n) | |
return@run Pair(prefix, lastColors + remaining) | |
} | |
throw IllegalStateException() | |
} | |
text = prefixRemaining | |
// Separate as much text as possible into the suffix. | |
val (suffix, suffixRemaining) = run { | |
for (n in Integer.min(text.length, suffixLength) downTo 0) { | |
val suffix = text.substring(text.length - n) | |
val remaining = text.substring(0, text.length - n) | |
if (remaining.endsWith(ChatColor.COLOR_CHAR) && !suffix.startsWith(ChatColor.COLOR_CHAR)) { | |
continue | |
} | |
val lastColors = ChatColor.getLastColors(remaining) | |
if (lastColors.length + suffix.length > suffixLength) { | |
continue | |
} | |
return@run Pair(lastColors + suffix, remaining) | |
} | |
throw IllegalStateException() | |
} | |
text = suffixRemaining | |
// Ensure remaining text (entry) is not too long. | |
if (text.length > entryLength) { | |
text = text.substring(0, entryLength) | |
} | |
// Prepend the entry with the ordering prefix. | |
val entry = getOrderedPrefix(i) + text | |
// Create the entry team if it does not exist. | |
val team = scoreboard.getTeam("@sidebar$i") ?: run { | |
scoreboard.registerNewTeam("@sidebar$i") | |
} | |
team.addEntry(entry) | |
team.prefix(LegacyComponentSerializer.legacySection().deserialize(prefix)) | |
team.suffix(LegacyComponentSerializer.legacySection().deserialize(suffix)) | |
objective.getScore(entry).score = 0 | |
entries.add(entry) | |
} else { | |
val entry = getOrderedPrefix(i) | |
val team = scoreboard.getTeam("@sidebar$i") ?: run { | |
scoreboard.registerNewTeam("@sidebar$i") | |
} | |
team.addEntry(entry) | |
team.prefix(item) | |
objective.getScore(entry).score = 0 | |
entries.add(entry) | |
} | |
} | |
// Remove obsolete entries. | |
for (entry in objectiveEntries[objective] ?: setOf()) { | |
if (entry !in entries) { | |
objective.getScore(entry).resetScore() | |
} | |
} | |
objectiveEntries[objective] = entries | |
} | |
@Suppress("UNUSED") | |
class SidebarPlugin : JavaPlugin(), Listener { | |
override fun onEnable() { | |
server.scheduler.scheduleSyncRepeatingTask( | |
this, | |
{ | |
for (p in server.onlinePlayers) { | |
val lines = (Math.random() * 10).toInt() + 1 | |
p.updateSidebar( | |
Component.text("Lines: ").append(Component.text(lines)), | |
(1..lines).map { i -> | |
Component.text("Line #").append(Component.text(i)).color(NamedTextColor.NAMES.values().random()) | |
}, | |
) | |
} | |
}, | |
0, 20, | |
) | |
server.pluginManager.registerEvents(this, this) | |
} | |
@EventHandler | |
fun onPlayerJoin(event: PlayerJoinEvent) { | |
event.player.scoreboard = server.scoreboardManager.newScoreboard | |
} | |
} |
Author
nathanfranke
commented
Mar 1, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment