mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-11 16:36:58 -04:00
ton of tab list fixes
This commit is contained in:
parent
c84619ffb3
commit
05f9026ac9
@ -2,6 +2,7 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard
|
||||
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.data.scoreboard.ScoreboardPositions
|
||||
import de.bixilon.minosoft.gui.rendering.Drawable
|
||||
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
|
||||
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
|
||||
@ -11,7 +12,7 @@ import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import glm_.vec2.Vec2i
|
||||
|
||||
class ScoreboardHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<ScoreboardSideElement>(hudRenderer) {
|
||||
class ScoreboardHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<ScoreboardSideElement>(hudRenderer), Drawable {
|
||||
private val connection = hudRenderer.connection
|
||||
override val layout = ScoreboardSideElement(hudRenderer)
|
||||
|
||||
@ -59,6 +60,13 @@ class ScoreboardHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<Scoreb
|
||||
})
|
||||
}
|
||||
|
||||
override fun draw() {
|
||||
// check if content was changed, and we need to re-prepare before drawing
|
||||
if (!layout.cacheUpToDate) {
|
||||
layout.recalculateSize()
|
||||
}
|
||||
}
|
||||
|
||||
companion object : HUDBuilder<ScoreboardHUDElement> {
|
||||
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:scoreboard".toResourceLocation()
|
||||
|
||||
|
@ -40,7 +40,6 @@ class ScoreboardSideElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
}
|
||||
|
||||
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
|
||||
recalculateSize()
|
||||
backgroundElement.render(offset, z, consumer, options)
|
||||
nameBackgroundElement.render(offset, z + 1, consumer, options)
|
||||
|
||||
@ -75,7 +74,7 @@ class ScoreboardSideElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
queueSizeRecalculation()
|
||||
}
|
||||
|
||||
private fun recalculateSize() {
|
||||
fun recalculateSize() {
|
||||
val size = Vec2i(MIN_WIDTH, Font.TOTAL_CHAR_HEIGHT)
|
||||
size.x = maxOf(size.x, nameElement.size.x)
|
||||
|
||||
|
@ -28,8 +28,8 @@ import de.bixilon.minosoft.util.KUtil.decide
|
||||
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
|
||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
||||
import glm_.vec2.Vec2i
|
||||
import java.lang.Integer.max
|
||||
import java.util.*
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
val header = TextElement(hudRenderer, "", background = false, fontAlignment = HorizontalAlignments.CENTER, parent = this)
|
||||
@ -38,8 +38,11 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
private val background = ColorElement(hudRenderer, Vec2i.EMPTY, color = RGBColor(0, 0, 0, 120))
|
||||
|
||||
private var entriesSize = Vec2i.EMPTY
|
||||
val entries: MutableMap<UUID, TabListEntryElement> = synchronizedMapOf()
|
||||
private val entries: MutableMap<UUID, TabListEntryElement> = synchronizedMapOf()
|
||||
private var toRender: List<TabListEntryElement> = listOf()
|
||||
private val lock = ReentrantLock()
|
||||
var needsApply = false
|
||||
private set
|
||||
|
||||
val pingBarsAtlasElements: Array<HUDAtlasElement> = arrayOf(
|
||||
hudRenderer.atlasManager["minecraft:tab_list_ping_0"]!!,
|
||||
@ -57,7 +60,6 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
val size = size
|
||||
|
||||
header.size.let {
|
||||
header.silentApply()
|
||||
header.render(offset + Vec2i(HorizontalAlignments.CENTER.getOffset(size.x, it.x), 0), z, consumer, options)
|
||||
offset.y += it.y
|
||||
}
|
||||
@ -96,15 +98,13 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
|
||||
size.y += header.size.y
|
||||
|
||||
val toRender: MutableList<TabListEntryElement> = mutableListOf()
|
||||
var toRender: MutableList<TabListEntryElement> = mutableListOf()
|
||||
toRender += entries.toSynchronizedMap().values
|
||||
|
||||
// ToDo: Sorting isn't working correct: java.lang.IllegalArgumentException: Comparison method violates its general contract!
|
||||
// Probably a threading issue
|
||||
val tabListItems = hudRenderer.connection.tabList.tabListItemsByUUID.toSynchronizedMap().entries.sortedWith { a, b -> a.value.compareTo(b.value) }
|
||||
|
||||
val previousSize = Vec2i(size)
|
||||
var columns = tabListItems.size / ENTRIES_PER_COLUMN
|
||||
if (tabListItems.size % ENTRIES_PER_COLUMN > 0) {
|
||||
var columns = toRender.size / ENTRIES_PER_COLUMN
|
||||
if (toRender.size % ENTRIES_PER_COLUMN > 0) {
|
||||
columns++
|
||||
}
|
||||
|
||||
@ -113,32 +113,47 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
var currentMaxPrefWidth = 0
|
||||
var totalEntriesWidth = 0
|
||||
|
||||
|
||||
// ToDo: Still sometimes crashing
|
||||
lock.lock()
|
||||
try {
|
||||
toRender.sort()
|
||||
} catch (exception: Exception) {
|
||||
exception.printStackTrace()
|
||||
}
|
||||
lock.unlock()
|
||||
// Minecraft limits it to 80 items. Imho this is removing a feature, but some servers use a custom tab list plugin and then players are duplicated, etc
|
||||
// ToDo: Detect custom tab list, e.g. check player names for non valid chars, etc
|
||||
toRender = toRender.subList(0, minOf(toRender.size, MAX_ENTRIES))
|
||||
|
||||
// Check width
|
||||
var index = 0
|
||||
for ((uuid, item) in tabListItems) {
|
||||
val entry = entries.getOrPut(uuid) { TabListEntryElement(hudRenderer, this, item, 0) }
|
||||
toRender += entry
|
||||
for ((index, entry) in toRender.withIndex()) {
|
||||
val prefWidth = entry.prefSize
|
||||
|
||||
currentMaxPrefWidth = max(currentMaxPrefWidth, prefWidth.x)
|
||||
currentMaxPrefWidth = maxOf(currentMaxPrefWidth, prefWidth.x)
|
||||
if ((index + 1) % ENTRIES_PER_COLUMN == 0) {
|
||||
widths[column] = currentMaxPrefWidth
|
||||
totalEntriesWidth += currentMaxPrefWidth
|
||||
currentMaxPrefWidth = 0
|
||||
column++
|
||||
}
|
||||
index++
|
||||
}
|
||||
if (currentMaxPrefWidth != 0) {
|
||||
widths[column] = currentMaxPrefWidth
|
||||
totalEntriesWidth += currentMaxPrefWidth
|
||||
}
|
||||
size.x = max(size.x, totalEntriesWidth)
|
||||
size.y += (columns > 1).decide(ENTRIES_PER_COLUMN, toRender.size) * (TabListEntryElement.HEIGHT + ENTRY_VERTICAL_SPACING)
|
||||
|
||||
size.y -= ENTRY_VERTICAL_SPACING // Remove already added space again
|
||||
|
||||
|
||||
// add horizontal spacing to columns
|
||||
if (columns >= 2) {
|
||||
totalEntriesWidth += (columns - 1) * ENTRY_HORIZONTAL_SPACING
|
||||
}
|
||||
|
||||
this.entriesSize = Vec2i(totalEntriesWidth, size.y - previousSize.y)
|
||||
size.x = maxOf(size.x, totalEntriesWidth)
|
||||
|
||||
|
||||
// apply width to every cell
|
||||
@ -150,21 +165,18 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
}
|
||||
}
|
||||
|
||||
if (columns >= 2) {
|
||||
size.x += (columns - 1) * ENTRY_HORIZONTAL_SPACING
|
||||
}
|
||||
|
||||
this.toRender = toRender
|
||||
|
||||
size.y += footer.size.y
|
||||
|
||||
size.x = max(max(size.x, header.size.x), footer.size.x)
|
||||
size.x = maxOf(size.x, header.size.x, footer.size.x)
|
||||
|
||||
|
||||
this.size = size
|
||||
this.size = size + 2 * BACKGROUND_PADDING
|
||||
|
||||
background.size = size + 2 * BACKGROUND_PADDING
|
||||
background.size = size
|
||||
cacheUpToDate = false
|
||||
needsApply = false
|
||||
}
|
||||
|
||||
override fun silentApply(): Boolean {
|
||||
@ -175,11 +187,30 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
return true
|
||||
}
|
||||
|
||||
fun update(uuid: UUID) {
|
||||
val item = hudRenderer.connection.tabList.tabListItemsByUUID[uuid] ?: return
|
||||
val entry = entries.getOrPut(uuid) { TabListEntryElement(hudRenderer, this, item, 0) }
|
||||
lock.lock()
|
||||
entry.silentApply()
|
||||
lock.unlock()
|
||||
needsApply = true
|
||||
}
|
||||
|
||||
fun remove(uuid: UUID) {
|
||||
entries -= uuid
|
||||
needsApply = true
|
||||
}
|
||||
|
||||
override fun onChildChange(child: Element) {
|
||||
needsApply = true
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val ENTRIES_PER_COLUMN = 20
|
||||
private const val ENTRY_HORIZONTAL_SPACING = 5
|
||||
private const val ENTRY_VERTICAL_SPACING = 1
|
||||
private const val BACKGROUND_PADDING = 1
|
||||
private const val BACKGROUND_PADDING = 3
|
||||
private const val MAX_ENTRIES = 80
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab
|
||||
|
||||
import de.bixilon.minosoft.data.abilities.Gamemodes
|
||||
import de.bixilon.minosoft.data.player.tab.TabListItem
|
||||
import de.bixilon.minosoft.data.text.ChatComponent
|
||||
import de.bixilon.minosoft.data.text.RGBColor
|
||||
@ -27,6 +28,7 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.Vec2Util.EMPTY
|
||||
import de.bixilon.minosoft.util.KUtil.nullCompare
|
||||
import glm_.vec2.Vec2i
|
||||
import java.lang.Integer.max
|
||||
|
||||
@ -35,7 +37,7 @@ class TabListEntryElement(
|
||||
val tabList: TabListElement,
|
||||
val item: TabListItem,
|
||||
width: Int,
|
||||
) : Element(hudRenderer), Pollable {
|
||||
) : Element(hudRenderer), Pollable, Comparable<TabListEntryElement> {
|
||||
init {
|
||||
_parent = tabList
|
||||
}
|
||||
@ -46,8 +48,11 @@ class TabListEntryElement(
|
||||
private val nameElement = TextElement(hudRenderer, "", background = false, parent = this)
|
||||
private lateinit var pingElement: ImageElement
|
||||
|
||||
private var displayName: ChatComponent = ChatComponent.EMPTY
|
||||
private var ping = -1
|
||||
private var displayName: ChatComponent = item.displayName
|
||||
private var ping = item.ping
|
||||
private var gamemode: Gamemodes = item.gamemode
|
||||
private var name: String = item.name
|
||||
private var teamName = item.team?.name
|
||||
|
||||
override var prefSize: Vec2i = Vec2i.EMPTY
|
||||
override var prefMaxSize: Vec2i
|
||||
@ -99,19 +104,45 @@ class TabListEntryElement(
|
||||
}
|
||||
|
||||
override fun poll(): Boolean {
|
||||
val ping = item.ping
|
||||
val displayName = item.tabDisplayName
|
||||
val ping = item.ping
|
||||
val gamemode = item.gamemode
|
||||
val name = item.name
|
||||
val teamName = item.team?.name
|
||||
|
||||
if (this.ping == ping && this.displayName == displayName) {
|
||||
if (this.ping == ping && this.displayName == displayName && this.gamemode == gamemode && this.name == name && this.teamName == teamName) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.ping = ping
|
||||
this.displayName = displayName
|
||||
this.gamemode = gamemode
|
||||
this.name = name
|
||||
this.teamName = teamName
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun compareTo(other: TabListEntryElement): Int {
|
||||
if (this.gamemode != other.gamemode) {
|
||||
if (this.gamemode == Gamemodes.SPECTATOR) {
|
||||
return -1
|
||||
}
|
||||
if (other.gamemode == Gamemodes.SPECTATOR) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
this.teamName?.nullCompare(other.teamName)?.let { return it }
|
||||
|
||||
this.name.lowercase().nullCompare(other.name.lowercase())?.let { return it }
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return displayName.legacyText
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val HEIGHT = 10
|
||||
|
@ -17,6 +17,7 @@ import de.bixilon.minosoft.config.key.KeyAction
|
||||
import de.bixilon.minosoft.config.key.KeyBinding
|
||||
import de.bixilon.minosoft.config.key.KeyCodes
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.gui.rendering.Drawable
|
||||
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
|
||||
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
|
||||
@ -26,11 +27,10 @@ import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import glm_.vec2.Vec2i
|
||||
|
||||
class TabListHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TabListElement>(hudRenderer) {
|
||||
class TabListHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TabListElement>(hudRenderer), Drawable {
|
||||
private val connection = renderWindow.connection
|
||||
override val layout = TabListElement(hudRenderer)
|
||||
|
||||
|
||||
override val layoutOffset: Vec2i
|
||||
get() = Vec2i((hudRenderer.scaledSize.x - layout.size.x) / 2, 20)
|
||||
|
||||
@ -44,19 +44,15 @@ class TabListHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TabListEl
|
||||
connection.registerEvent(CallbackEventInvoker.of<TabListInfoChangeEvent> {
|
||||
layout.header.text = it.header
|
||||
layout.footer.text = it.footer
|
||||
layout.forceApply()
|
||||
})
|
||||
connection.registerEvent(CallbackEventInvoker.of<TabListEntryChangeEvent> {
|
||||
for ((uuid, entry) in it.items) {
|
||||
if (entry.remove) {
|
||||
layout.entries.remove(uuid)
|
||||
layout.remove(uuid)
|
||||
continue
|
||||
}
|
||||
val element = layout.entries[uuid] ?: continue
|
||||
element.forceApply()
|
||||
layout.update(uuid)
|
||||
}
|
||||
// ToDo: Cache more?
|
||||
layout.forceApply()
|
||||
})
|
||||
|
||||
// ToDo: Also check team changes, scoreboard changes, etc
|
||||
@ -64,6 +60,13 @@ class TabListHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TabListEl
|
||||
// ToDo: Just forceApply when visible
|
||||
}
|
||||
|
||||
override fun draw() {
|
||||
// check if content was changed, and we need to re-prepare before drawing
|
||||
if (layout.needsApply) {
|
||||
layout.forceApply()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object : HUDBuilder<TabListHUDElement> {
|
||||
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:tab_list".toResourceLocation()
|
||||
|
Loading…
x
Reference in New Issue
Block a user