mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 10:55:01 -04:00
wip: hud tab list
This commit is contained in:
parent
aa7f5ca36e
commit
c143c52e22
@ -19,4 +19,8 @@ class PlayerProperty(
|
|||||||
) {
|
) {
|
||||||
val isSigned: Boolean
|
val isSigned: Boolean
|
||||||
get() = signature != null // ToDo check signature
|
get() = signature != null // ToDo check signature
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "$key: $value"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ import de.bixilon.minosoft.data.text.ChatComponent
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class TabList {
|
class TabList {
|
||||||
val tabListItems: MutableMap<UUID, TabListItem> = mutableMapOf()
|
val tabListItemsByUUID: MutableMap<UUID, TabListItem> = mutableMapOf()
|
||||||
|
val tabListItemsByName: MutableMap<String, TabListItem> = mutableMapOf()
|
||||||
var header = ChatComponent.of("")
|
var header = ChatComponent.of("")
|
||||||
var footer = ChatComponent.of("")
|
var footer = ChatComponent.of("")
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ package de.bixilon.minosoft.data.player.tab
|
|||||||
|
|
||||||
import de.bixilon.minosoft.data.abilities.Gamemodes
|
import de.bixilon.minosoft.data.abilities.Gamemodes
|
||||||
import de.bixilon.minosoft.data.player.PlayerProperty
|
import de.bixilon.minosoft.data.player.PlayerProperty
|
||||||
|
import de.bixilon.minosoft.data.scoreboard.Team
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
|
|
||||||
data class TabListItem(
|
data class TabListItem(
|
||||||
@ -23,6 +24,7 @@ data class TabListItem(
|
|||||||
var gamemode: Gamemodes = Gamemodes.SURVIVAL,
|
var gamemode: Gamemodes = Gamemodes.SURVIVAL,
|
||||||
var displayName: ChatComponent = ChatComponent.of(name),
|
var displayName: ChatComponent = ChatComponent.of(name),
|
||||||
var properties: Map<String, PlayerProperty> = mutableMapOf(),
|
var properties: Map<String, PlayerProperty> = mutableMapOf(),
|
||||||
|
var team: Team? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun merge(data: TabListItemData) {
|
fun merge(data: TabListItemData) {
|
||||||
@ -42,5 +44,10 @@ data class TabListItem(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.properties?.let { properties = it }
|
data.properties?.let { properties = it }
|
||||||
|
|
||||||
|
if (data.removeFromTeam) {
|
||||||
|
this.team = null
|
||||||
|
}
|
||||||
|
data.team?.let { team = it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ package de.bixilon.minosoft.data.player.tab
|
|||||||
|
|
||||||
import de.bixilon.minosoft.data.abilities.Gamemodes
|
import de.bixilon.minosoft.data.abilities.Gamemodes
|
||||||
import de.bixilon.minosoft.data.player.PlayerProperty
|
import de.bixilon.minosoft.data.player.PlayerProperty
|
||||||
|
import de.bixilon.minosoft.data.scoreboard.Team
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
|
|
||||||
data class TabListItemData(
|
data class TabListItemData(
|
||||||
@ -25,4 +26,6 @@ data class TabListItemData(
|
|||||||
var displayName: ChatComponent? = null,
|
var displayName: ChatComponent? = null,
|
||||||
val properties: Map<String, PlayerProperty>? = null,
|
val properties: Map<String, PlayerProperty>? = null,
|
||||||
var remove: Boolean = false, // used for legacy tab list
|
var remove: Boolean = false, // used for legacy tab list
|
||||||
|
var team: Team? = null,
|
||||||
|
var removeFromTeam: Boolean = false,
|
||||||
)
|
)
|
||||||
|
@ -15,7 +15,7 @@ package de.bixilon.minosoft.data.scoreboard
|
|||||||
import de.bixilon.minosoft.data.text.ChatCode
|
import de.bixilon.minosoft.data.text.ChatCode
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
|
|
||||||
class Team(
|
data class Team(
|
||||||
val name: String,
|
val name: String,
|
||||||
var displayName: ChatComponent,
|
var displayName: ChatComponent,
|
||||||
var prefix: ChatComponent,
|
var prefix: ChatComponent,
|
||||||
@ -26,4 +26,8 @@ class Team(
|
|||||||
var nameTagVisibility: NameTagVisibilities,
|
var nameTagVisibility: NameTagVisibilities,
|
||||||
var formattingCode: ChatCode?,
|
var formattingCode: ChatCode?,
|
||||||
val members: MutableSet<String>,
|
val members: MutableSet<String>,
|
||||||
)
|
) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -57,6 +57,13 @@ open class ImageElement(
|
|||||||
super.size = value
|
super.size = value
|
||||||
cacheUpToDate = false
|
cacheUpToDate = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var prefSize: Vec2i
|
||||||
|
get() = size
|
||||||
|
set(value) {
|
||||||
|
size = value
|
||||||
|
}
|
||||||
|
|
||||||
var tint: RGBColor = tint
|
var tint: RGBColor = tint
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
|
@ -41,6 +41,7 @@ open class TextElement(
|
|||||||
private var previousOffset = Vec2i.EMPTY
|
private var previousOffset = Vec2i.EMPTY
|
||||||
private var previousMatrix = hudRenderer.matrix
|
private var previousMatrix = hudRenderer.matrix
|
||||||
|
|
||||||
|
private var previousMaxSize = Vec2i.EMPTY
|
||||||
private var preparedSize = Vec2i.EMPTY
|
private var preparedSize = Vec2i.EMPTY
|
||||||
var renderInfo = TextRenderInfo()
|
var renderInfo = TextRenderInfo()
|
||||||
|
|
||||||
@ -73,6 +74,7 @@ open class TextElement(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun silentApply() {
|
override fun silentApply() {
|
||||||
|
val maxSize = maxSize
|
||||||
val size = Vec2i.EMPTY
|
val size = Vec2i.EMPTY
|
||||||
if (!emptyMessage) {
|
if (!emptyMessage) {
|
||||||
val renderInfo = TextRenderInfo()
|
val renderInfo = TextRenderInfo()
|
||||||
@ -81,6 +83,8 @@ open class TextElement(
|
|||||||
this.renderInfo = renderInfo
|
this.renderInfo = renderInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.previousMaxSize = maxSize
|
||||||
this.cacheUpToDate = false
|
this.cacheUpToDate = false
|
||||||
this.size = size
|
this.size = size
|
||||||
preparedSize = size
|
preparedSize = size
|
||||||
@ -90,6 +94,10 @@ open class TextElement(
|
|||||||
|
|
||||||
override fun onParentChange() {
|
override fun onParentChange() {
|
||||||
val maxSize = maxSize
|
val maxSize = maxSize
|
||||||
|
if (previousMaxSize == maxSize) {
|
||||||
|
// no change in size
|
||||||
|
return
|
||||||
|
}
|
||||||
val prefSize = prefSize
|
val prefSize = prefSize
|
||||||
|
|
||||||
if (preparedSize.x < prefSize.x || preparedSize.x > maxSize.x) {
|
if (preparedSize.x < prefSize.x || preparedSize.x > maxSize.x) {
|
||||||
|
@ -56,7 +56,7 @@ class TextFlowElement(
|
|||||||
yOffset += Font.TOTAL_CHAR_HEIGHT
|
yOffset += Font.TOTAL_CHAR_HEIGHT
|
||||||
}
|
}
|
||||||
|
|
||||||
background.render(offset, z, consumer)
|
background.render(Vec2i(offset), z, consumer)
|
||||||
return LAYERS
|
return LAYERS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +159,6 @@ class TextFlowElement(
|
|||||||
companion object {
|
companion object {
|
||||||
const val LAYERS = TextElement.LAYERS
|
const val LAYERS = TextElement.LAYERS
|
||||||
|
|
||||||
const val MAX_TOTAL_MESSAGES = 500 // ToDo: Used for scrolling
|
const val MAX_TOTAL_MESSAGES = 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import de.bixilon.minosoft.gui.rendering.Renderer
|
|||||||
import de.bixilon.minosoft.gui.rendering.RendererBuilder
|
import de.bixilon.minosoft.gui.rendering.RendererBuilder
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.HUDAtlasManager
|
import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.HUDAtlasManager
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.*
|
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.*
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab.TabListHUDElement
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
|
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.Vec2Util.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.Vec2Util.EMPTY
|
||||||
@ -77,6 +78,7 @@ class HUDRenderer(
|
|||||||
if (Minosoft.config.config.game.hud.internalMessages.enabled) {
|
if (Minosoft.config.config.game.hud.internalMessages.enabled) {
|
||||||
registerElement(InternalMessagesHUDElement)
|
registerElement(InternalMessagesHUDElement)
|
||||||
}
|
}
|
||||||
|
registerElement(TabListHUDElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
|
@ -23,7 +23,7 @@ class HUDAtlasElement(
|
|||||||
val end: Vec2i,
|
val end: Vec2i,
|
||||||
val slots: Map<Int, Vec2Binding<Int>>, // ToDo: Use an array?
|
val slots: Map<Int, Vec2Binding<Int>>, // ToDo: Use an array?
|
||||||
) : TextureLike {
|
) : TextureLike {
|
||||||
override val size: Vec2i = start - end
|
override val size: Vec2i = end - start
|
||||||
override lateinit var uvStart: Vec2
|
override lateinit var uvStart: Vec2
|
||||||
override lateinit var uvEnd: Vec2
|
override lateinit var uvEnd: Vec2
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.abilities.Gamemodes
|
||||||
|
import de.bixilon.minosoft.data.text.RGBColor
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.ElementAlignments
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.ElementAlignments.Companion.getOffset
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ColorElement
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.HUDAtlasElement
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.vec.Vec2Util.EMPTY
|
||||||
|
import de.bixilon.minosoft.util.KUtil.decide
|
||||||
|
import de.bixilon.minosoft.util.KUtil.nullCompare
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
||||||
|
import glm_.vec2.Vec2i
|
||||||
|
import java.lang.Integer.max
|
||||||
|
|
||||||
|
class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||||
|
val header = TextElement(hudRenderer, "", background = false, fontAlignment = ElementAlignments.CENTER, parent = this)
|
||||||
|
val footer = TextElement(hudRenderer, "", background = false, fontAlignment = ElementAlignments.CENTER, parent = this)
|
||||||
|
|
||||||
|
private val background = ColorElement(hudRenderer, Vec2i.EMPTY, color = RGBColor(0, 0, 0, 120))
|
||||||
|
private var entriesSize = Vec2i.EMPTY
|
||||||
|
private var entries: List<TabListEntryElement> = listOf()
|
||||||
|
|
||||||
|
val PING_BARS: Array<HUDAtlasElement> = arrayOf(
|
||||||
|
hudRenderer.atlasManager["minecraft:tab_list_ping_0".toResourceLocation()]!!,
|
||||||
|
hudRenderer.atlasManager["minecraft:tab_list_ping_1".toResourceLocation()]!!,
|
||||||
|
hudRenderer.atlasManager["minecraft:tab_list_ping_2".toResourceLocation()]!!,
|
||||||
|
hudRenderer.atlasManager["minecraft:tab_list_ping_3".toResourceLocation()]!!,
|
||||||
|
hudRenderer.atlasManager["minecraft:tab_list_ping_4".toResourceLocation()]!!,
|
||||||
|
hudRenderer.atlasManager["minecraft:tab_list_ping_5".toResourceLocation()]!!,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
|
||||||
|
silentApply()
|
||||||
|
background.render(Vec2i(offset), z, consumer)
|
||||||
|
val size = size
|
||||||
|
|
||||||
|
header.size.let {
|
||||||
|
header.onParentChange()
|
||||||
|
header.render(offset + Vec2i(ElementAlignments.CENTER.getOffset(size.x, it.x), 0), z, consumer)
|
||||||
|
offset.y += it.y
|
||||||
|
}
|
||||||
|
|
||||||
|
val offsetBefore = Vec2i(offset)
|
||||||
|
offset.x += ElementAlignments.CENTER.getOffset(size.x, entriesSize.x)
|
||||||
|
|
||||||
|
var columns = entries.size / ENTRIES_PER_COLUMN
|
||||||
|
if (entries.size % ENTRIES_PER_COLUMN > 0) {
|
||||||
|
columns++
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((index, entry) in entries.withIndex()) {
|
||||||
|
entry.render(Vec2i(offset), z + 1, consumer)
|
||||||
|
offset.y += TabListEntryElement.HEIGHT + ENTRY_VERTICAL_SPACING
|
||||||
|
if ((index + 1) % ENTRIES_PER_COLUMN == 0) {
|
||||||
|
offset.x += entry.width + ENTRY_HORIZONTAL_SPACING
|
||||||
|
offset.y = offsetBefore.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset.x = offsetBefore.x
|
||||||
|
offset.y = offsetBefore.y + (columns > 1).decide(ENTRIES_PER_COLUMN, entries.size) * (TabListEntryElement.HEIGHT + ENTRY_VERTICAL_SPACING)
|
||||||
|
|
||||||
|
|
||||||
|
footer.size.let {
|
||||||
|
footer.render(offset + Vec2i(ElementAlignments.CENTER.getOffset(size.x, it.x), 0), z, consumer)
|
||||||
|
offset.y += it.y
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextElement.LAYERS + 1 // ToDo
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun silentApply() {
|
||||||
|
val maxSize = maxSize
|
||||||
|
val size = Vec2i.EMPTY
|
||||||
|
|
||||||
|
|
||||||
|
header.onParentChange()
|
||||||
|
footer.onParentChange()
|
||||||
|
|
||||||
|
size.y += header.size.y
|
||||||
|
|
||||||
|
val entries: MutableList<TabListEntryElement> = mutableListOf()
|
||||||
|
|
||||||
|
val tabListItems = hudRenderer.connection.tabList.tabListItemsByUUID.toSynchronizedMap().values.sortedWith { a, b ->
|
||||||
|
if (a.gamemode != b.gamemode) {
|
||||||
|
if (a.gamemode == Gamemodes.SPECTATOR) {
|
||||||
|
return@sortedWith -1
|
||||||
|
}
|
||||||
|
if (b.gamemode == Gamemodes.SPECTATOR) {
|
||||||
|
return@sortedWith 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.team?.name?.nullCompare(b.team?.name)?.let { return@sortedWith it }
|
||||||
|
|
||||||
|
a.name.nullCompare(b?.name)?.let { return@sortedWith it } // ToDo: Case?
|
||||||
|
|
||||||
|
return@sortedWith 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val previousSize = Vec2i(size)
|
||||||
|
var columns = tabListItems.size / ENTRIES_PER_COLUMN
|
||||||
|
if (tabListItems.size % ENTRIES_PER_COLUMN > 0) {
|
||||||
|
columns++
|
||||||
|
}
|
||||||
|
|
||||||
|
var column = 0
|
||||||
|
val widths = IntArray(columns)
|
||||||
|
var currentMaxPrefWidth = 0
|
||||||
|
var totalEntriesWidth = 0
|
||||||
|
|
||||||
|
// Check width
|
||||||
|
for ((index, item) in tabListItems.withIndex()) {
|
||||||
|
val entry = TabListEntryElement(hudRenderer, this, item, 0)
|
||||||
|
entries += entry
|
||||||
|
val prefWidth = entry.prefSize
|
||||||
|
|
||||||
|
currentMaxPrefWidth = max(currentMaxPrefWidth, prefWidth.x)
|
||||||
|
if ((index + 1) % ENTRIES_PER_COLUMN == 0) {
|
||||||
|
widths[column] = currentMaxPrefWidth
|
||||||
|
totalEntriesWidth += currentMaxPrefWidth
|
||||||
|
currentMaxPrefWidth = 0
|
||||||
|
column++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentMaxPrefWidth != 0) {
|
||||||
|
widths[column] = currentMaxPrefWidth
|
||||||
|
totalEntriesWidth += currentMaxPrefWidth
|
||||||
|
}
|
||||||
|
size.x = max(size.x, totalEntriesWidth)
|
||||||
|
size.y += (columns > 1).decide(ENTRIES_PER_COLUMN, entries.size) * (TabListEntryElement.HEIGHT + ENTRY_VERTICAL_SPACING)
|
||||||
|
|
||||||
|
this.entriesSize = Vec2i(totalEntriesWidth, size.y - previousSize.y)
|
||||||
|
|
||||||
|
|
||||||
|
// apply width to every cell
|
||||||
|
column = 0
|
||||||
|
for ((index, entry) in entries.withIndex()) {
|
||||||
|
entry.width = widths[column]
|
||||||
|
if ((index + 1) % ENTRIES_PER_COLUMN == 0) {
|
||||||
|
column++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (columns >= 2) {
|
||||||
|
size.x += (columns - 1) * ENTRY_HORIZONTAL_SPACING
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entries = entries
|
||||||
|
|
||||||
|
size.y += footer.size.y
|
||||||
|
|
||||||
|
size.x = max(max(size.x, header.size.x), footer.size.x)
|
||||||
|
|
||||||
|
|
||||||
|
this.size = size
|
||||||
|
|
||||||
|
background.size = size
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ENTRIES_PER_COLUMN = 20
|
||||||
|
private const val ENTRY_HORIZONTAL_SPACING = 5
|
||||||
|
private const val ENTRY_VERTICAL_SPACING = 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.player.tab.TabListItem
|
||||||
|
import de.bixilon.minosoft.data.text.BaseComponent
|
||||||
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
|
import de.bixilon.minosoft.data.text.RGBColor
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.ElementAlignments
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.ElementAlignments.Companion.getOffset
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ColorElement
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.vec.Vec2Util.EMPTY
|
||||||
|
import glm_.vec2.Vec2i
|
||||||
|
import java.lang.Integer.max
|
||||||
|
|
||||||
|
class TabListEntryElement(
|
||||||
|
hudRenderer: HUDRenderer,
|
||||||
|
val tabList: TabListElement,
|
||||||
|
val item: TabListItem,
|
||||||
|
width: Int,
|
||||||
|
) : Element(hudRenderer) {
|
||||||
|
// ToDo: Skin
|
||||||
|
private val background: ColorElement
|
||||||
|
|
||||||
|
private val nameElement = TextElement(hudRenderer, "", background = false, parent = this)
|
||||||
|
private lateinit var pingElement: ImageElement
|
||||||
|
|
||||||
|
private var lastDisplayName: ChatComponent? = null
|
||||||
|
private var lastPing = -1
|
||||||
|
|
||||||
|
override var prefSize: Vec2i = Vec2i.EMPTY
|
||||||
|
override var prefMaxSize: Vec2i
|
||||||
|
get() = Vec2i(width, HEIGHT)
|
||||||
|
set(value) {}
|
||||||
|
override var size: Vec2i
|
||||||
|
get() = maxSize
|
||||||
|
set(value) {}
|
||||||
|
|
||||||
|
private var forcePrepare = true
|
||||||
|
var width: Int = width
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
forcePrepare = true
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
background = ColorElement(hudRenderer, size, RGBColor(80, 80, 80, 130))
|
||||||
|
silentApply()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int {
|
||||||
|
background.render(Vec2i(offset), z, consumer)
|
||||||
|
nameElement.render(Vec2i(offset), z, consumer)
|
||||||
|
pingElement.render(offset + Vec2i(ElementAlignments.RIGHT.getOffset(maxSize.x, pingElement.size.x + PADDING), PADDING), z + 1, consumer)
|
||||||
|
|
||||||
|
return TextElement.LAYERS
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun silentApply() {
|
||||||
|
val ping = item.ping
|
||||||
|
|
||||||
|
if (forcePrepare || ping != lastPing) {
|
||||||
|
pingElement = ImageElement(hudRenderer, tabList.PING_BARS[when {
|
||||||
|
ping < 0 -> 0
|
||||||
|
ping < 150 -> 5
|
||||||
|
ping < 300 -> 4
|
||||||
|
ping < 600 -> 3
|
||||||
|
ping < 1000 -> 2
|
||||||
|
else -> 1
|
||||||
|
}])
|
||||||
|
nameElement.prefMaxSize = Vec2i(max(0, maxSize.x - pingElement.size.x), HEIGHT)
|
||||||
|
lastPing = ping
|
||||||
|
}
|
||||||
|
val displayName = BaseComponent()
|
||||||
|
item.team?.prefix?.let {
|
||||||
|
displayName += it
|
||||||
|
}
|
||||||
|
displayName += item.displayName.apply {
|
||||||
|
// ToDo: Set correct formatting code
|
||||||
|
val color = item.team?.formattingCode
|
||||||
|
if (color is RGBColor) {
|
||||||
|
applyDefaultColor(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.team?.suffix?.let {
|
||||||
|
displayName += it
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forcePrepare || displayName !== lastDisplayName) {
|
||||||
|
nameElement.text = displayName
|
||||||
|
lastDisplayName = displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
this.prefSize = Vec2i((PADDING * 2) + nameElement.prefSize.x + INNER_MARGIN + pingElement.prefSize.x, HEIGHT)
|
||||||
|
background.size = size
|
||||||
|
forcePrepare = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val HEIGHT = 10
|
||||||
|
const val INNER_MARGIN = 5
|
||||||
|
const val PADDING = 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
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.HUDElement
|
||||||
|
import de.bixilon.minosoft.modding.event.events.TabListInfoChangeEvent
|
||||||
|
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
|
import glm_.vec2.Vec2i
|
||||||
|
|
||||||
|
class TabListHUDElement(hudRenderer: HUDRenderer) : HUDElement<TabListElement>(hudRenderer) {
|
||||||
|
private val connection = renderWindow.connection
|
||||||
|
override val layout = TabListElement(hudRenderer)
|
||||||
|
|
||||||
|
|
||||||
|
override val layoutOffset: Vec2i
|
||||||
|
get() = Vec2i((hudRenderer.scaledSize.x - layout.size.x) / 2, 20)
|
||||||
|
|
||||||
|
init {
|
||||||
|
layout.prefMaxSize = Vec2i(-1, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun init() {
|
||||||
|
connection.registerEvent(CallbackEventInvoker.of<TabListInfoChangeEvent> {
|
||||||
|
layout.header.text = it.header
|
||||||
|
layout.footer.text = it.footer
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object : HUDBuilder<TabListHUDElement> {
|
||||||
|
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:tab_list".toResourceLocation()
|
||||||
|
|
||||||
|
override fun build(hudRenderer: HUDRenderer): TabListHUDElement {
|
||||||
|
return TabListHUDElement(hudRenderer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,7 @@ import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEv
|
|||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.packets.s2c.play.TabListTextSetS2CP
|
import de.bixilon.minosoft.protocol.packets.s2c.play.TabListTextSetS2CP
|
||||||
|
|
||||||
class PlayerListInfoChangeEvent(
|
class TabListInfoChangeEvent(
|
||||||
connection: PlayConnection,
|
connection: PlayConnection,
|
||||||
initiator: EventInitiators,
|
initiator: EventInitiators,
|
||||||
val header: ChatComponent,
|
val header: ChatComponent,
|
@ -86,7 +86,7 @@ class PlayerEntitySpawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(connection: PlayConnection) {
|
override fun handle(connection: PlayConnection) {
|
||||||
connection.tabList.tabListItems[entityUUID]?.let { entity.tabListItem = it }
|
// connection.tabList.tabListItemsByUUID[entityUUID]?.let { entity.tabListItem = it }
|
||||||
|
|
||||||
connection.fireEvent(EntitySpawnEvent(connection, this))
|
connection.fireEvent(EntitySpawnEvent(connection, this))
|
||||||
connection.world.entities.add(entityId, entityUUID, entity)
|
connection.world.entities.add(entityId, entityUUID, entity)
|
||||||
|
@ -24,6 +24,7 @@ import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
|||||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
|
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
|
||||||
import de.bixilon.minosoft.util.KUtil
|
import de.bixilon.minosoft.util.KUtil
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
||||||
import de.bixilon.minosoft.util.enum.ValuesEnum
|
import de.bixilon.minosoft.util.enum.ValuesEnum
|
||||||
import de.bixilon.minosoft.util.logging.Log
|
import de.bixilon.minosoft.util.logging.Log
|
||||||
import de.bixilon.minosoft.util.logging.LogLevels
|
import de.bixilon.minosoft.util.logging.LogLevels
|
||||||
@ -123,36 +124,47 @@ class TabListDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
if (connection.version.versionId < ProtocolVersions.V_14W19A) { // ToDo: 19?
|
if (connection.version.versionId < ProtocolVersions.V_14W19A) { // ToDo: 19?
|
||||||
val item: TabListItem = if (data.remove) {
|
val item: TabListItem = if (data.remove) {
|
||||||
// add or remove
|
// add or remove
|
||||||
connection.tabList.tabListItems[uuid]?.apply {
|
connection.tabList.tabListItemsByUUID[uuid]?.apply {
|
||||||
connection.tabList.tabListItems.remove(uuid)
|
connection.tabList.tabListItemsByUUID.remove(uuid)
|
||||||
} ?: let {
|
connection.tabList.tabListItemsByName.remove(data.name)
|
||||||
|
} ?: TabListItem(name = data.name!!).apply {
|
||||||
// add
|
// add
|
||||||
val itemToAdd = TabListItem(name = data.name!!)
|
connection.tabList.tabListItemsByUUID[uuid] = this
|
||||||
connection.tabList.tabListItems[uuid] = itemToAdd
|
connection.tabList.tabListItemsByName[data.name] = this
|
||||||
itemToAdd
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
connection.tabList.tabListItems[uuid]!!
|
connection.tabList.tabListItemsByUUID[uuid]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
item.merge(data)
|
item.merge(data)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (data.remove) {
|
if (data.remove) {
|
||||||
connection.tabList.tabListItems.remove(uuid)
|
val item = connection.tabList.tabListItemsByUUID.remove(uuid) ?: continue
|
||||||
|
connection.tabList.tabListItemsByName.remove(item.name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val entity = connection.world.entities[uuid]
|
val entity = connection.world.entities[uuid]
|
||||||
|
|
||||||
|
|
||||||
val tabListItem = connection.tabList.tabListItems[uuid] ?: run {
|
val tabListItem = connection.tabList.tabListItemsByUUID[uuid] ?: run {
|
||||||
if (data.name == null) {
|
if (data.name == null) {
|
||||||
// item not yet created
|
// item not yet created
|
||||||
return@run null
|
return@run null
|
||||||
}
|
}
|
||||||
val item = TabListItem(name = data.name)
|
val item = TabListItem(name = data.name)
|
||||||
connection.tabList.tabListItems[uuid] = item
|
connection.tabList.tabListItemsByUUID[uuid] = item
|
||||||
|
connection.tabList.tabListItemsByName[data.name] = item
|
||||||
|
|
||||||
|
// set team
|
||||||
|
|
||||||
|
for (team in connection.scoreboardManager.teams.toSynchronizedMap().values) {
|
||||||
|
if (team.members.contains(data.name)) {
|
||||||
|
item.team = team
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
item
|
item
|
||||||
} ?: continue
|
} ?: continue
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
package de.bixilon.minosoft.protocol.packets.s2c.play
|
package de.bixilon.minosoft.protocol.packets.s2c.play
|
||||||
|
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
import de.bixilon.minosoft.modding.event.events.PlayerListInfoChangeEvent
|
import de.bixilon.minosoft.modding.event.events.TabListInfoChangeEvent
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
||||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||||
@ -26,7 +26,7 @@ class TabListTextSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
val footer: ChatComponent = buffer.readChatComponent()
|
val footer: ChatComponent = buffer.readChatComponent()
|
||||||
|
|
||||||
override fun handle(connection: PlayConnection) {
|
override fun handle(connection: PlayConnection) {
|
||||||
if (connection.fireEvent(PlayerListInfoChangeEvent(connection, this))) {
|
if (connection.fireEvent(TabListInfoChangeEvent(connection, this))) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
connection.tabList.header = header
|
connection.tabList.header = header
|
||||||
|
@ -101,7 +101,7 @@ class TeamCreateS2CP(val name: String, buffer: PlayInByteBuffer) : PlayS2CPacket
|
|||||||
|
|
||||||
|
|
||||||
override fun handle(connection: PlayConnection) {
|
override fun handle(connection: PlayConnection) {
|
||||||
connection.scoreboardManager.teams[name] = Team(
|
val team = Team(
|
||||||
name = name,
|
name = name,
|
||||||
displayName = displayName,
|
displayName = displayName,
|
||||||
prefix = prefix,
|
prefix = prefix,
|
||||||
@ -113,6 +113,11 @@ class TeamCreateS2CP(val name: String, buffer: PlayInByteBuffer) : PlayS2CPacket
|
|||||||
formattingCode = formattingCode,
|
formattingCode = formattingCode,
|
||||||
members = members.toMutableSet(),
|
members = members.toMutableSet(),
|
||||||
)
|
)
|
||||||
|
connection.scoreboardManager.teams[name] = team
|
||||||
|
|
||||||
|
for (member in members) {
|
||||||
|
connection.tabList.tabListItemsByName[member]?.team = team
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun log() {
|
override fun log() {
|
||||||
|
@ -32,7 +32,12 @@ class TeamMemberAddS2CP(val name: String, buffer: PlayInByteBuffer) : PlayS2CPac
|
|||||||
|
|
||||||
|
|
||||||
override fun handle(connection: PlayConnection) {
|
override fun handle(connection: PlayConnection) {
|
||||||
connection.scoreboardManager.teams[name]?.members?.addAll(members)
|
val team = connection.scoreboardManager.teams[name] ?: return
|
||||||
|
team.members += members
|
||||||
|
|
||||||
|
for (member in members) {
|
||||||
|
connection.tabList.tabListItemsByName[member]?.team = team
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun log() {
|
override fun log() {
|
||||||
|
@ -31,7 +31,16 @@ class TeamMemberRemoveS2CP(val name: String, buffer: PlayInByteBuffer) : PlayS2C
|
|||||||
|
|
||||||
|
|
||||||
override fun handle(connection: PlayConnection) {
|
override fun handle(connection: PlayConnection) {
|
||||||
connection.scoreboardManager.teams[name]?.members?.removeAll(members)
|
val team = connection.scoreboardManager.teams[name] ?: return
|
||||||
|
team.members -= members
|
||||||
|
|
||||||
|
for (member in members) {
|
||||||
|
val item = connection.tabList.tabListItemsByName[member] ?: continue
|
||||||
|
if (item.team != team) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
item.team = team
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun log() {
|
override fun log() {
|
||||||
|
@ -211,14 +211,14 @@ class PacketTypes {
|
|||||||
PLAY_COMBAT_EVENT_END({ CombatEventEndS2CP(it) }),
|
PLAY_COMBAT_EVENT_END({ CombatEventEndS2CP(it) }),
|
||||||
PLAY_COMBAT_EVENT_ENTER({ CombatEventEnterS2CP() }),
|
PLAY_COMBAT_EVENT_ENTER({ CombatEventEnterS2CP() }),
|
||||||
PLAY_COMBAT_EVENT_KILL({ CombatEventKillS2CP(it) }),
|
PLAY_COMBAT_EVENT_KILL({ CombatEventKillS2CP(it) }),
|
||||||
PLAY_TAB_LIST_DATA({ TabListDataS2CP(it) }),
|
PLAY_TAB_LIST_DATA({ TabListDataS2CP(it) }, isThreadSafe = false),
|
||||||
PLAY_PLAYER_FACE({ PlayerFaceS2CP(it) }),
|
PLAY_PLAYER_FACE({ PlayerFaceS2CP(it) }),
|
||||||
PLAY_POSITION_AND_ROTATION({ PositionAndRotationS2CP(it) }),
|
PLAY_POSITION_AND_ROTATION({ PositionAndRotationS2CP(it) }),
|
||||||
PLAY_UNLOCK_RECIPES({ PacketUnlockRecipes(it) }),
|
PLAY_UNLOCK_RECIPES({ PacketUnlockRecipes(it) }),
|
||||||
PLAY_ENTITY_DESTROY({ EntityDestroyS2CP(it) }),
|
PLAY_ENTITY_DESTROY({ EntityDestroyS2CP(it) }),
|
||||||
PLAY_ENTITY_STATUS_EFFECT_REMOVE({ EntityStatusEffectRemoveS2CP(it) }),
|
PLAY_ENTITY_STATUS_EFFECT_REMOVE({ EntityStatusEffectRemoveS2CP(it) }),
|
||||||
PLAY_RESOURCEPACK_REQUEST({ ResourcepackRequestS2CP(it) }),
|
PLAY_RESOURCEPACK_REQUEST({ ResourcepackRequestS2CP(it) }),
|
||||||
PLAY_RESPAWN({ RespawnS2CP(it) }, isThreadSafe = false),
|
PLAY_RESPAWN({ RespawnS2CP(it) }),
|
||||||
PLAY_ENTITY_HEAD_ROTATION({ EntityHeadRotationS2CP(it) }),
|
PLAY_ENTITY_HEAD_ROTATION({ EntityHeadRotationS2CP(it) }),
|
||||||
PLAY_SELECT_ADVANCEMENT_TAB({ PacketSelectAdvancementTab(it) }),
|
PLAY_SELECT_ADVANCEMENT_TAB({ PacketSelectAdvancementTab(it) }),
|
||||||
PLAY_WORLD_BORDER({ WorldBorderS2CF.createPacket(it) }),
|
PLAY_WORLD_BORDER({ WorldBorderS2CF.createPacket(it) }),
|
||||||
|
@ -31,7 +31,7 @@ public class CommandTabList extends Command {
|
|||||||
new CommandLiteralNode("list", (connection, stack) -> {
|
new CommandLiteralNode("list", (connection, stack) -> {
|
||||||
print(connection.getTabList().getHeader().getAnsiColoredMessage());
|
print(connection.getTabList().getHeader().getAnsiColoredMessage());
|
||||||
|
|
||||||
int entries = connection.getTabList().getTabListItems().size();
|
int entries = connection.getTabList().getTabListItemsByUUID().size();
|
||||||
int columns = (entries / 20) + 1;
|
int columns = (entries / 20) + 1;
|
||||||
if (columns > 4) {
|
if (columns > 4) {
|
||||||
columns = 4;
|
columns = 4;
|
||||||
@ -43,12 +43,12 @@ public class CommandTabList extends Command {
|
|||||||
|
|
||||||
ArrayList<Object[]> tableData = new ArrayList<>();
|
ArrayList<Object[]> tableData = new ArrayList<>();
|
||||||
|
|
||||||
Iterator<TabListItem> playerListItems = connection.getTabList().getTabListItems().values().iterator();
|
Iterator<TabListItem> tabListItemIterator = connection.getTabList().getTabListItemsByUUID().values().iterator();
|
||||||
for (int row = 0; row < rows; row++) {
|
for (int row = 0; row < rows; row++) {
|
||||||
ArrayList<Object> current = new ArrayList<>();
|
ArrayList<Object> current = new ArrayList<>();
|
||||||
for (int column = 0; column < columns; column++) {
|
for (int column = 0; column < columns; column++) {
|
||||||
if (playerListItems.hasNext()) {
|
if (tabListItemIterator.hasNext()) {
|
||||||
current.add(playerListItems.next().getDisplayName());
|
current.add(tabListItemIterator.next().getDisplayName());
|
||||||
} else {
|
} else {
|
||||||
current.add(null);
|
current.add(null);
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ public class CommandTabList extends Command {
|
|||||||
|
|
||||||
ArrayList<Object[]> tableData = new ArrayList<>();
|
ArrayList<Object[]> tableData = new ArrayList<>();
|
||||||
|
|
||||||
for (var entry : connection.getTabList().getTabListItems().entrySet()) {
|
for (var entry : connection.getTabList().getTabListItemsByUUID().entrySet()) {
|
||||||
PlayerEntity playerEntity = (PlayerEntity) connection.getWorld().getEntities().get(entry.getKey());
|
PlayerEntity playerEntity = (PlayerEntity) connection.getWorld().getEntities().get(entry.getKey());
|
||||||
Integer entityId = playerEntity != null ? connection.getWorld().getEntities().getId(playerEntity) : null;
|
Integer entityId = playerEntity != null ? connection.getWorld().getEntities().getId(playerEntity) : null;
|
||||||
tableData.add(new Object[]{entry.getKey(), entityId, entry.getValue().getName(), entry.getValue().getDisplayName(), entry.getValue().getGamemode(), entry.getValue().getPing() + "ms"});
|
tableData.add(new Object[]{entry.getKey(), entityId, entry.getValue().getName(), entry.getValue().getDisplayName(), entry.getValue().getGamemode(), entry.getValue().getPing() + "ms"});
|
||||||
|
@ -409,4 +409,14 @@ object KUtil {
|
|||||||
fun ByteArray.toBase64(): String {
|
fun ByteArray.toBase64(): String {
|
||||||
return Base64.getEncoder().encodeToString(this)
|
return Base64.getEncoder().encodeToString(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun String?.nullCompare(other: String?): Int? {
|
||||||
|
(this ?: "").compareTo(other ?: "").let {
|
||||||
|
if (it != 0) {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ import de.bixilon.minosoft.config.StaticConfiguration
|
|||||||
import de.bixilon.minosoft.data.text.BaseComponent
|
import de.bixilon.minosoft.data.text.BaseComponent
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
import de.bixilon.minosoft.data.text.TextComponent
|
import de.bixilon.minosoft.data.text.TextComponent
|
||||||
|
import de.bixilon.minosoft.modding.event.events.InternalMessageReceiveEvent
|
||||||
|
import de.bixilon.minosoft.terminal.CLI
|
||||||
import de.bixilon.minosoft.terminal.RunConfiguration
|
import de.bixilon.minosoft.terminal.RunConfiguration
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
@ -84,6 +86,9 @@ object Log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stream.println(message.ansiColoredMessage)
|
stream.println(message.ansiColoredMessage)
|
||||||
|
|
||||||
|
val cliConnection = CLI.getCurrentConnection()
|
||||||
|
cliConnection?.fireEvent(InternalMessageReceiveEvent(cliConnection, messageToSend.message))
|
||||||
} catch (exception: Throwable) {
|
} catch (exception: Throwable) {
|
||||||
SYSTEM_ERR_STREAM.println("Can not send log message $messageToSend!")
|
SYSTEM_ERR_STREAM.println("Can not send log message $messageToSend!")
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,48 @@
|
|||||||
"end": [16, 16]
|
"end": [16, 16]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"minecraft:tab_list_ping_5": {
|
||||||
|
"0": {
|
||||||
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
"start": [0, 16],
|
||||||
|
"end": [10, 23]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:tab_list_ping_4": {
|
||||||
|
"0": {
|
||||||
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
"start": [0, 24],
|
||||||
|
"end": [10, 31]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:tab_list_ping_3": {
|
||||||
|
"0": {
|
||||||
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
"start": [0, 32],
|
||||||
|
"end": [10, 39]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:tab_list_ping_2": {
|
||||||
|
"0": {
|
||||||
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
"start": [0, 40],
|
||||||
|
"end": [10, 47]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:tab_list_ping_1": {
|
||||||
|
"0": {
|
||||||
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
"start": [0, 48],
|
||||||
|
"end": [10, 55]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:tab_list_ping_0": {
|
||||||
|
"0": {
|
||||||
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
"start": [0, 56],
|
||||||
|
"end": [10, 63]
|
||||||
|
}
|
||||||
|
},
|
||||||
"minecraft:experience_bar_empty": {
|
"minecraft:experience_bar_empty": {
|
||||||
"0": {
|
"0": {
|
||||||
"texture": "minecraft:textures/gui/icons.png",
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user