merge HUDElements and Elements

This commit is contained in:
Bixilon 2022-01-10 20:39:06 +01:00
parent ab854ee653
commit 714c65c354
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
39 changed files with 539 additions and 479 deletions

View File

@ -0,0 +1,20 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.elements
import glm_.vec2.Vec2i
interface LayoutedElement {
val layoutOffset: Vec2i
}

View File

@ -24,7 +24,7 @@ import glm_.vec2.Vec2i
import java.lang.Integer.min
import kotlin.math.max
class GridLayout(guiRenderer: AbstractGUIRenderer, val grid: Vec2i) : Element(guiRenderer) {
open class GridLayout(guiRenderer: AbstractGUIRenderer, val grid: Vec2i) : Element(guiRenderer) {
val columnConstraints: Array<GridColumnConstraint> = Array(grid.x) { GridColumnConstraint() }
val rowConstraints: Array<GridRowConstraint> = Array(grid.y) { GridRowConstraint() }

View File

@ -0,0 +1,82 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.elements.primitive
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLike
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import glm_.vec2.Vec2
import glm_.vec2.Vec2i
open class AtlasImageElement(
guiRenderer: AbstractGUIRenderer,
val textureLike: TextureLike,
size: Vec2i = textureLike.size,
tint: RGBColor = ChatColors.WHITE,
) : Element(guiRenderer) {
override var initialCacheSize: Int = GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6
var texture: AbstractTexture = textureLike.texture
set(value) {
field = value
cacheUpToDate = false
}
var uvStart: Vec2? = null
set(value) {
field = value
cacheUpToDate = false
}
var uvEnd: Vec2? = null
set(value) {
field = value
cacheUpToDate = false
}
override var size: Vec2i
get() = super.size
set(value) {
super.size = value
cacheUpToDate = false
}
override var prefSize: Vec2i
get() = size
set(value) {
size = value
}
var tint: RGBColor = tint
set(value) {
field = value
cacheUpToDate = false
}
init {
this.size = size
}
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
consumer.addQuad(offset, offset + size, z, texture, uvStart ?: textureLike.uvStart, uvEnd ?: textureLike.uvEnd, tint, options)
return 1
}
override fun forceSilentApply() = Unit
override fun silentApply(): Boolean = false
}

View File

@ -22,6 +22,6 @@ class ColorElement(
guiRenderer: AbstractGUIRenderer,
size: Vec2i,
color: RGBColor = ChatColors.WHITE,
) : ImageElement(guiRenderer, guiRenderer.renderWindow.WHITE_TEXTURE, size, color) {
) : AtlasImageElement(guiRenderer, guiRenderer.renderWindow.WHITE_TEXTURE, size, color) {
var color by this::tint
}

View File

@ -16,7 +16,6 @@ package de.bixilon.minosoft.gui.rendering.gui.elements.primitive
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.TextureLike
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
@ -74,7 +73,6 @@ open class ImageElement(
this.size = size
}
constructor(guiRenderer: AbstractGUIRenderer, texture: TextureLike, size: Vec2i = texture.size, tint: RGBColor = ChatColors.WHITE) : this(guiRenderer, texture.texture, texture.uvStart, texture.uvEnd, size, tint)
constructor(guiRenderer: AbstractGUIRenderer, texture: AbstractTexture, uvStart: Vec2i, uvEnd: Vec2i, size: Vec2i = texture.size, tint: RGBColor = ChatColors.WHITE) : this(guiRenderer, texture, Vec2(uvStart) * texture.singlePixelSize, Vec2(uvEnd) * texture.singlePixelSize, size, tint)

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
* Copyright (C) 2020-2022 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.
*
@ -14,14 +14,14 @@
package de.bixilon.minosoft.gui.rendering.gui.elements.spacer
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import glm_.vec2.Vec2i
class LineSpacerElement(
hudRenderer: HUDRenderer,
guiRenderer: AbstractGUIRenderer,
lines: Int = 1,
) : SpacerElement(hudRenderer, Vec2i.EMPTY) {
) : SpacerElement(guiRenderer, Vec2i.EMPTY) {
var lines: Int = 0
set(value) {
field = value

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
* Copyright (C) 2020-2022 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.
*
@ -13,13 +13,13 @@
package de.bixilon.minosoft.gui.rendering.gui.elements.spacer
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
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 glm_.vec2.Vec2i
open class SpacerElement(hudRenderer: HUDRenderer, override var size: Vec2i) : Element(hudRenderer) {
open class SpacerElement(guiRenderer: AbstractGUIRenderer, override var size: Vec2i) : Element(guiRenderer) {
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int = 0

View File

@ -19,23 +19,23 @@ import de.bixilon.kutil.time.TimeUtil
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ColorElement
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.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.max
import glm_.vec2.Vec2i
class TextFlowElement(
hudRenderer: HUDRenderer,
open class TextFlowElement(
guiRenderer: AbstractGUIRenderer,
var messageExpireTime: Long,
) : Element(hudRenderer) {
) : Element(guiRenderer) {
private val messages: MutableList<TextFlowTextElement> = synchronizedListOf() // all messages **from newest to oldest**
private var visibleLines: List<TextFlowLineElement> = listOf() // all visible lines **from bottom to top**
private val background = ColorElement(hudRenderer, size, RenderConstants.TEXT_BACKGROUND_COLOR)
private val background = ColorElement(guiRenderer, size, RenderConstants.TEXT_BACKGROUND_COLOR)
// Used for scrolling in GUI (not hud)
private val active: Boolean = false // if always all lines should be displayed when possible

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.gui.elements.util
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.AtlasElement
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
@ -38,7 +39,7 @@ open class ProgressElement(
forceSilentApply()
// ToDo: Animate
}
protected val emptyImage = ImageElement(guiRenderer, emptyAtlasElement)
protected val emptyImage = AtlasImageElement(guiRenderer, emptyAtlasElement)
protected lateinit var progressImage: ImageElement

View File

@ -17,11 +17,11 @@ import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.GUIElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
abstract class Screen(
override val guiRenderer: AbstractGUIRenderer,
) : GUIElement {
override val renderWindow: RenderWindow = guiRenderer.renderWindow
val background = ImageElement(guiRenderer, renderWindow.WHITE_TEXTURE, size = guiRenderer.scaledSize, tint = RGBColor(1.0f, 1.0f, 1.0f, 0.8f))
val background = AtlasImageElement(guiRenderer, renderWindow.WHITE_TEXTURE, size = guiRenderer.scaledSize, tint = RGBColor(1.0f, 1.0f, 1.0f, 0.8f))
}

View File

@ -28,17 +28,17 @@ import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.bossbar.BossbarHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.chat.ChatHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.chat.InternalMessagesHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar.HotbarHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.bossbar.BossbarLayout
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.chat.ChatElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.chat.InternalMessagesElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar.HotbarElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.other.BreakProgressHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.other.CrosshairHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.other.DebugHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.other.WorldInfoHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard.ScoreboardHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab.TabListHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.title.TitleHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard.ScoreboardSideElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab.TabListElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.title.TitleElement
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.gui.rendering.renderer.Renderer
@ -95,16 +95,16 @@ class HUDRenderer(
private fun registerDefaultElements() {
registerElement(DebugHUDElement)
registerElement(CrosshairHUDElement)
registerElement(BossbarHUDElement)
registerElement(ChatHUDElement)
registerElement(BossbarLayout)
registerElement(ChatElement)
registerElement(InternalMessagesHUDElement)
registerElement(InternalMessagesElement)
registerElement(BreakProgressHUDElement)
registerElement(TabListHUDElement)
registerElement(HotbarHUDElement)
registerElement(TabListElement)
registerElement(HotbarElement)
registerElement(WorldInfoHUDElement)
registerElement(TitleHUDElement)
registerElement(ScoreboardHUDElement)
registerElement(TitleElement)
registerElement(ScoreboardSideElement)
}
private fun recalculateMatrices(windowSize: Vec2i = renderWindow.window.size, scale: Float = profile.scale) {
@ -114,7 +114,7 @@ class HUDRenderer(
for (element in hudElements.toSynchronizedMap().values) {
if (element is LayoutedHUDElement<*>) {
element.layout.silentApply()
element.elementLayout.silentApply()
}
element.apply()
}
@ -205,8 +205,8 @@ class HUDRenderer(
}
}
operator fun <T : LayoutedHUDElement<*>> get(hudBuilder: HUDBuilder<*>): T? {
return hudElements[hudBuilder.RESOURCE_LOCATION].unsafeCast()
operator fun <T : HUDElement> get(hudBuilder: HUDBuilder<T>): T? {
return hudElements[hudBuilder.RESOURCE_LOCATION]?.unsafeCast()
}
companion object : RendererBuilder<HUDRenderer> {

View File

@ -0,0 +1,20 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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
interface Initializable {
fun init() {}
fun postInit() {}
}

View File

@ -13,27 +13,44 @@
package de.bixilon.minosoft.gui.rendering.gui.hud.elements
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.Initializable
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import glm_.vec2.Vec2i
abstract class LayoutedHUDElement<T : Element>(final override val guiRenderer: HUDRenderer) : HUDElement {
final override val renderWindow: RenderWindow = guiRenderer.renderWindow
class LayoutedHUDElement<T : LayoutedElement>(
val layout: T,
) : HUDElement, Drawable {
val elementLayout = layout.unsafeCast<Element>()
override val guiRenderer: AbstractGUIRenderer = elementLayout.guiRenderer
override val renderWindow: RenderWindow = guiRenderer.renderWindow
override var enabled = true
var mesh: GUIMesh = GUIMesh(renderWindow, guiRenderer.matrix, DirectArrayFloatList(1000))
private var lastRevision = 0L
abstract val layout: T
abstract val layoutOffset: Vec2i
override val skipDraw: Boolean
get() = if (layout is Drawable) layout.skipDraw else false
override fun tick() {
layout.tick()
elementLayout.tick()
}
override fun init() {
if (layout is Initializable) {
layout.init()
}
}
override fun postInit() {
if (layout is Initializable) {
layout.postInit()
}
}
private fun createNewMesh() {
@ -45,10 +62,10 @@ abstract class LayoutedHUDElement<T : Element>(final override val guiRenderer: H
}
fun prepare(z: Int): Int {
val layoutOffset = layoutOffset
val usedZ = layout.render(layoutOffset, z, mesh, null)
val layoutOffset = layout.layoutOffset
val usedZ = elementLayout.render(layoutOffset, z, mesh, null)
val revision = layout.cache.revision
val revision = elementLayout.cache.revision
if (revision != lastRevision) {
createNewMesh()
this.mesh.load()
@ -58,9 +75,15 @@ abstract class LayoutedHUDElement<T : Element>(final override val guiRenderer: H
return usedZ
}
override fun draw() {
if (layout is Drawable) {
layout.draw()
}
}
fun initMesh() {
layout.cache.data = mesh.data
elementLayout.cache.data = mesh.data
mesh.load()
}
}

View File

@ -17,8 +17,10 @@ import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.minosoft.data.bossbar.Bossbar
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
import de.bixilon.minosoft.gui.rendering.gui.elements.layout.RowLayout
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.Initializable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.modding.event.events.bossbar.*
@ -26,13 +28,12 @@ import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
class BossbarHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<RowLayout>(hudRenderer) {
class BossbarLayout(hudRenderer: HUDRenderer) : RowLayout(hudRenderer, HorizontalAlignments.CENTER, 2), LayoutedElement, Initializable {
private val connection = renderWindow.connection
override val layout: RowLayout = RowLayout(hudRenderer, HorizontalAlignments.CENTER, 2)
private val bossbars: MutableMap<Bossbar, BossbarElement> = synchronizedMapOf()
override val layoutOffset: Vec2i
get() = Vec2i((guiRenderer.scaledSize.x - layout.size.x) / 2, 2)
get() = Vec2i((guiRenderer.scaledSize.x - super.size.x) / 2, 2)
val atlasManager = hudRenderer.atlasManager
@ -93,14 +94,14 @@ class BossbarHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<RowLayout
override fun postInit() {
connection.registerEvent(CallbackEventInvoker.of<BossbarAddEvent> {
val element = BossbarElement(guiRenderer, it.bossbar, atlas)
layout += element
this += element
val previous = bossbars.put(it.bossbar, element) ?: return@of
layout -= previous
this -= previous
})
connection.registerEvent(CallbackEventInvoker.of<BossbarRemoveEvent> {
val element = bossbars.remove(it.bossbar) ?: return@of
layout -= element
this -= element
})
connection.registerEvent(CallbackEventInvoker.of<BossbarValueSetEvent> {
@ -115,11 +116,11 @@ class BossbarHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<RowLayout
}
companion object : HUDBuilder<BossbarHUDElement> {
companion object : HUDBuilder<LayoutedHUDElement<BossbarLayout>> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:bossbar".toResourceLocation()
override fun build(hudRenderer: HUDRenderer): BossbarHUDElement {
return BossbarHUDElement(hudRenderer)
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<BossbarLayout> {
return LayoutedHUDElement(BossbarLayout(hudRenderer))
}
}
}

View File

@ -15,7 +15,7 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.bossbar
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.AtlasElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.util.ProgressElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
@ -29,8 +29,8 @@ open class BossbarProgressElement(
fullNotchesElement: AtlasElement?,
progress: Float = 0.0f,
) : ProgressElement(guiRenderer, emptyProgressAtlasElement, fullProgressAtlasElement, progress) {
private val emptyNotchesImage = emptyNotchesElement?.let { ImageElement(guiRenderer, it, emptyProgressAtlasElement.size) }
private val fullNotchesImage = fullNotchesElement?.let { ImageElement(guiRenderer, it, emptyProgressAtlasElement.size) }
private val emptyNotchesImage = emptyNotchesElement?.let { AtlasImageElement(guiRenderer, it, emptyProgressAtlasElement.size) }
private val fullNotchesImage = fullNotchesElement?.let { AtlasImageElement(guiRenderer, it, emptyProgressAtlasElement.size) }
constructor(guiRenderer: AbstractGUIRenderer, progressElements: Array<AtlasElement>, notchesElements: Array<AtlasElement>?, progress: Float = 0.0f) : this(guiRenderer, progressElements[0], progressElements[1], notchesElements?.get(0), notchesElements?.get(1), progress)

View File

@ -16,35 +16,38 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.chat
import de.bixilon.minosoft.config.profile.delegate.watcher.SimpleProfileDelegateWatcher.Companion.profileWatchRendering
import de.bixilon.minosoft.data.ChatTextPositions
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextFlowElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.Initializable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.modding.event.events.ChatMessageReceiveEvent
import de.bixilon.minosoft.modding.event.events.InternalMessageReceiveEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
class ChatHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TextFlowElement>(hudRenderer) {
class ChatElement(guiRenderer: AbstractGUIRenderer) : TextFlowElement(guiRenderer, 20000), LayoutedElement, Initializable, Drawable {
private val connection = renderWindow.connection
private val profile = connection.profiles.hud
private val chatProfile = profile.chat
override val layout = TextFlowElement(hudRenderer, 20000)
override var enabled: Boolean
get() = !chatProfile.hidden
override var skipDraw: Boolean
get() = chatProfile.hidden
set(value) {
chatProfile.hidden = !value
}
override val layoutOffset: Vec2i
get() = Vec2i(2, guiRenderer.scaledSize.y - layout.size.y - BOTTOM_OFFSET)
get() = Vec2i(2, guiRenderer.scaledSize.y - super.size.y - BOTTOM_OFFSET)
init {
layout.prefMaxSize = Vec2i(chatProfile.width, chatProfile.height)
chatProfile::width.profileWatchRendering(this, profile = profile) { layout.prefMaxSize = Vec2i(it, layout.prefMaxSize.y) }
chatProfile::height.profileWatchRendering(this, profile = profile) { layout.prefMaxSize = Vec2i(layout.prefMaxSize.x, it) }
super.prefMaxSize = Vec2i(chatProfile.width, chatProfile.height)
chatProfile::width.profileWatchRendering(this, profile = profile) { super.prefMaxSize = Vec2i(it, super.prefMaxSize.y) }
chatProfile::height.profileWatchRendering(this, profile = profile) { super.prefMaxSize = Vec2i(super.prefMaxSize.x, it) }
}
@ -53,23 +56,23 @@ class ChatHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TextFlowElem
if (it.position == ChatTextPositions.ABOVE_HOTBAR) {
return@of
}
layout += it.message
this += it.message
})
connection.registerEvent(CallbackEventInvoker.of<InternalMessageReceiveEvent> {
if (!profile.chat.internal.hidden) {
return@of
}
layout += it.message
this += it.message
})
}
companion object : HUDBuilder<ChatHUDElement> {
companion object : HUDBuilder<LayoutedHUDElement<ChatElement>> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:chat_hud".toResourceLocation()
private const val BOTTOM_OFFSET = 30
override fun build(hudRenderer: HUDRenderer): ChatHUDElement {
return ChatHUDElement(hudRenderer)
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<ChatElement> {
return LayoutedHUDElement(ChatElement(hudRenderer))
}
}
}

View File

@ -15,48 +15,50 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.chat
import de.bixilon.minosoft.config.profile.delegate.watcher.SimpleProfileDelegateWatcher.Companion.profileWatchRendering
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextFlowElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.Initializable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.modding.event.events.InternalMessageReceiveEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
class InternalMessagesHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TextFlowElement>(hudRenderer) {
class InternalMessagesElement(hudRenderer: HUDRenderer) : TextFlowElement(hudRenderer, 15000), LayoutedElement, Initializable, Drawable {
private val connection = renderWindow.connection
private val profile = connection.profiles.hud
private val internalChatProfile = profile.chat.internal
override val layout = TextFlowElement(hudRenderer, 15000)
override var enabled: Boolean
get() = !internalChatProfile.hidden
override var skipDraw: Boolean
get() = internalChatProfile.hidden
set(value) {
internalChatProfile.hidden = !value
}
override val layoutOffset: Vec2i
get() = guiRenderer.scaledSize - Vec2i(layout.size.x, layout.size.y + BOTTOM_OFFSET)
get() = super.size.let { return@let guiRenderer.scaledSize - Vec2i(it.x, it.y + BOTTOM_OFFSET) }
init {
layout.prefMaxSize = Vec2i(internalChatProfile.width, internalChatProfile.height)
internalChatProfile::width.profileWatchRendering(this, profile = profile) { layout.prefMaxSize = Vec2i(it, layout.prefMaxSize.y) }
internalChatProfile::height.profileWatchRendering(this, profile = profile) { layout.prefMaxSize = Vec2i(layout.prefMaxSize.x, it) }
super.prefMaxSize = Vec2i(internalChatProfile.width, internalChatProfile.height)
internalChatProfile::width.profileWatchRendering(this, profile = profile) { super.prefMaxSize = Vec2i(it, super.prefMaxSize.y) }
internalChatProfile::height.profileWatchRendering(this, profile = profile) { super.prefMaxSize = Vec2i(super.prefMaxSize.x, it) }
}
override fun init() {
connection.registerEvent(CallbackEventInvoker.of<InternalMessageReceiveEvent> { layout += it.message })
connection.registerEvent(CallbackEventInvoker.of<InternalMessageReceiveEvent> { this += it.message })
}
companion object : HUDBuilder<InternalMessagesHUDElement> {
companion object : HUDBuilder<LayoutedHUDElement<InternalMessagesElement>> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:internal_messages_hud".toResourceLocation()
private const val BOTTOM_OFFSET = 30
override fun build(hudRenderer: HUDRenderer): InternalMessagesHUDElement {
return InternalMessagesHUDElement(hudRenderer)
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<InternalMessagesElement> {
return LayoutedHUDElement(InternalMessagesElement(hudRenderer))
}
}
}

View File

@ -19,7 +19,7 @@ import de.bixilon.minosoft.data.text.RGBColor.Companion.asColor
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.AtlasElement
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
@ -59,7 +59,7 @@ abstract class AbstractHotbarHealthElement(guiRenderer: AbstractGUIRenderer) : E
val row = heart / HEARTS_PER_ROW
val column = heart % HEARTS_PER_ROW
val image = ImageElement(guiRenderer, atlasElement)
val image = AtlasImageElement(guiRenderer, atlasElement)
image.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z, consumer, options)
}

View File

@ -18,7 +18,7 @@ import de.bixilon.minosoft.data.registries.fluid.DefaultFluids
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
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.vec2.Vec2iUtil.EMPTY
@ -48,7 +48,7 @@ class HotbarAirElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer),
atlasElement = poppingAirBubble
}
val image = ImageElement(guiRenderer, atlasElement)
val image = AtlasImageElement(guiRenderer, atlasElement)
image.render(offset + Vec2i(i * BUBBLE_SIZE.x, 0), z, consumer, options)
}

View File

@ -18,7 +18,7 @@ import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.items.ContainerItemsElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.util.KUtil.toResourceLocation
@ -26,8 +26,8 @@ import glm_.vec2.Vec2i
class HotbarBaseElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer), Pollable {
private val baseAtlasElement = guiRenderer.renderWindow.atlasManager[BASE]!!
private val base = ImageElement(guiRenderer, baseAtlasElement)
private val frame = ImageElement(guiRenderer, guiRenderer.renderWindow.atlasManager[FRAME]!!, size = Vec2i(FRAME_SIZE))
private val base = AtlasImageElement(guiRenderer, baseAtlasElement)
private val frame = AtlasImageElement(guiRenderer, guiRenderer.renderWindow.atlasManager[FRAME]!!, size = Vec2i(FRAME_SIZE))
private val containerElement = ContainerItemsElement(guiRenderer, guiRenderer.renderWindow.connection.player.inventory, baseAtlasElement.slots)

View File

@ -13,23 +13,37 @@
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar
import de.bixilon.minosoft.data.ChatTextPositions
import de.bixilon.minosoft.data.inventory.InventorySlots
import de.bixilon.minosoft.data.inventory.ItemStack
import de.bixilon.minosoft.data.player.Arms
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.other.game.event.handlers.gamemode.GamemodeChangeEvent
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.FadingTextElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.Initializable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
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.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.left
import de.bixilon.minosoft.gui.rendering.util.vec.vec4.Vec4iUtil.right
import de.bixilon.minosoft.modding.event.events.ChatMessageReceiveEvent
import de.bixilon.minosoft.modding.event.events.ExperienceChangeEvent
import de.bixilon.minosoft.modding.event.events.SelectHotbarSlotEvent
import de.bixilon.minosoft.modding.event.events.container.ContainerRevisionChangeEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
import java.lang.Integer.max
class HotbarElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer) {
class HotbarElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer), LayoutedElement, Initializable {
val core = HotbarCoreElement(guiRenderer)
val offhand = HotbarOffhandElement(guiRenderer)
@ -43,6 +57,10 @@ class HotbarElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer) {
private var lastItemSlot = -1
private var itemTextShown = true
override val layoutOffset: Vec2i
get() = size.let { Vec2i((guiRenderer.scaledSize.x - it.x) / 2, guiRenderer.scaledSize.y - it.y) }
private var renderElements = setOf(
itemText,
hoverText,
@ -151,8 +169,42 @@ class HotbarElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer) {
offhand.tick()
}
companion object {
override fun postInit() {
prefMaxSize = Vec2i(-1, -1)
val connection = renderWindow.connection
connection.registerEvent(CallbackEventInvoker.of<ExperienceChangeEvent> { core.experience.apply() })
connection.registerEvent(CallbackEventInvoker.of<GamemodeChangeEvent> { forceApply() })
connection.registerEvent(CallbackEventInvoker.of<SelectHotbarSlotEvent> { core.base.apply() })
connection.registerEvent(CallbackEventInvoker.of<ContainerRevisionChangeEvent> {
if (it.container != connection.player.inventory) {
return@of
}
core.base.apply()
offhand.apply()
})
connection.registerEvent(CallbackEventInvoker.of<ChatMessageReceiveEvent> {
if (it.position != ChatTextPositions.ABOVE_HOTBAR) {
return@of
}
hoverText.text = it.message
hoverText.show()
})
}
companion object : HUDBuilder<LayoutedHUDElement<HotbarElement>> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:hotbar".toResourceLocation()
private const val HOVER_TEXT_OFFSET = 15
private const val ITEM_NAME_OFFSET = 5
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<HotbarElement> {
return LayoutedHUDElement(HotbarElement(hudRenderer))
}
}
}

View File

@ -1,79 +0,0 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.hotbar
import de.bixilon.minosoft.data.ChatTextPositions
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.other.game.event.handlers.gamemode.GamemodeChangeEvent
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
import de.bixilon.minosoft.modding.event.events.ChatMessageReceiveEvent
import de.bixilon.minosoft.modding.event.events.ExperienceChangeEvent
import de.bixilon.minosoft.modding.event.events.SelectHotbarSlotEvent
import de.bixilon.minosoft.modding.event.events.container.ContainerRevisionChangeEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
class HotbarHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<HotbarElement>(hudRenderer) {
private val connection = renderWindow.connection
override lateinit var layout: HotbarElement
override val layoutOffset: Vec2i
get() = Vec2i((guiRenderer.scaledSize.x - layout.size.x) / 2, guiRenderer.scaledSize.y - layout.size.y)
override fun postInit() {
layout = HotbarElement(guiRenderer) // ToDo: The base uses image elements, that are available after init stage
layout.prefMaxSize = Vec2i(-1, -1)
connection.registerEvent(CallbackEventInvoker.of<ExperienceChangeEvent> {
layout.core.experience.apply()
})
connection.registerEvent(CallbackEventInvoker.of<GamemodeChangeEvent> {
layout.forceApply()
})
connection.registerEvent(CallbackEventInvoker.of<SelectHotbarSlotEvent> {
layout.core.base.apply()
})
connection.registerEvent(CallbackEventInvoker.of<ContainerRevisionChangeEvent> {
if (it.container != connection.player.inventory) {
return@of
}
layout.core.base.apply()
layout.offhand.apply()
})
connection.registerEvent(CallbackEventInvoker.of<ChatMessageReceiveEvent> {
if (it.position != ChatTextPositions.ABOVE_HOTBAR) {
return@of
}
layout.hoverText.text = it.message
layout.hoverText.show()
})
}
companion object : HUDBuilder<HotbarHUDElement> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:hotbar".toResourceLocation()
override fun build(hudRenderer: HUDRenderer): HotbarHUDElement {
return HotbarHUDElement(hudRenderer)
}
}
}

View File

@ -25,7 +25,7 @@ import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.AtlasElement
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import glm_.vec2.Vec2i
@ -197,7 +197,7 @@ class HotbarHealthElement(guiRenderer: AbstractGUIRenderer) : AbstractHotbarHeal
val image = selectArray.unsafeCast<Array<AtlasElement?>>()[when {
halfHeart -> 1
else -> 0
}]?.let { ImageElement(guiRenderer, it) }
}]?.let { AtlasImageElement(guiRenderer, it) }
image?.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z + 1, consumer, options)

View File

@ -18,7 +18,7 @@ import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.AtlasElement
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import glm_.vec2.Vec2i
@ -98,7 +98,7 @@ class HotbarHungerElement(guiRenderer: AbstractGUIRenderer) : Element(guiRendere
}
else -> normalHungerContainer
}
ImageElement(guiRenderer, container).render(hungerOffset, z, consumer, options)
AtlasImageElement(guiRenderer, container).render(hungerOffset, z, consumer, options)
val selectArray: Array<*> = if (hungerEffect) {
@ -121,7 +121,7 @@ class HotbarHungerElement(guiRenderer: AbstractGUIRenderer) : Element(guiRendere
hungerElement = selectArray[0] as AtlasElement
}
ImageElement(guiRenderer, hungerElement).render(hungerOffset, z + 1, consumer, options)
AtlasImageElement(guiRenderer, hungerElement).render(hungerOffset, z + 1, consumer, options)
}

View File

@ -18,7 +18,7 @@ import de.bixilon.minosoft.data.player.Arms.Companion.opposite
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.items.ContainerItemsElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
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.vec4.Vec4iUtil.marginOf
@ -34,7 +34,7 @@ class HotbarOffhandElement(guiRenderer: AbstractGUIRenderer) : Element(guiRender
val offArm = guiRenderer.renderWindow.connection.player.mainArm.opposite // ToDo: Support arm change
private val frame = frames[offArm.ordinal]!!
private var frameImage = ImageElement(guiRenderer, frame)
private var frameImage = AtlasImageElement(guiRenderer, frame)
private val containerElement = ContainerItemsElement(guiRenderer, guiRenderer.renderWindow.connection.player.inventory, frame.slots)
init {

View File

@ -16,7 +16,7 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
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.vec2.Vec2iUtil.EMPTY
@ -47,7 +47,7 @@ class HotbarProtectionElement(guiRenderer: AbstractGUIRenderer) : Element(guiRen
else -> fullProtection
}
val image = ImageElement(guiRenderer, atlasElement)
val image = AtlasImageElement(guiRenderer, atlasElement)
image.render(offset + Vec2i(i * ARMOR_SIZE.x, 0), z, consumer, options)

View File

@ -22,7 +22,7 @@ import de.bixilon.minosoft.data.text.RGBColor.Companion.asColor
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import glm_.vec2.Vec2i
@ -65,7 +65,7 @@ class HotbarVehicleHealthElement(guiRenderer: AbstractGUIRenderer) : AbstractHot
val image = hearts[when {
halfHeart -> 1
else -> 0
}]?.let { ImageElement(guiRenderer, it) }
}]?.let { AtlasImageElement(guiRenderer, it) }
image?.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z + 1, consumer, options)

View File

@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.other
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
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.elements.HUDBuilder
@ -24,19 +25,18 @@ import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
class BreakProgressHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TextElement>(hudRenderer), Drawable {
override val layout: TextElement = TextElement(hudRenderer, "")
class BreakProgressHUDElement(hudRenderer: HUDRenderer) : TextElement(hudRenderer, ""), LayoutedElement, Drawable {
private val breakInteractionHandler = hudRenderer.renderWindow.inputHandler.interactionManager.`break`
override val layoutOffset: Vec2i
get() = Vec2i((guiRenderer.scaledSize.x / 2) + CrosshairHUDElement.CROSSHAIR_SIZE / 2 + 5, (guiRenderer.scaledSize.y - layout.size.y) / 2)
get() = Vec2i((guiRenderer.scaledSize.x / 2) + CrosshairHUDElement.CROSSHAIR_SIZE / 2 + 5, (guiRenderer.scaledSize.y - super.size.y) / 2)
private var percent = -1
override fun draw() {
val breakProgress = breakInteractionHandler.breakProgress
if (breakProgress <= 0 || breakProgress >= 1.0) {
layout.text = ""
super.text = ""
this.percent = -1
return
}
@ -44,7 +44,7 @@ class BreakProgressHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<Tex
if (percent == this.percent) {
return
}
layout.text = TextComponent("$percent%").apply {
super.text = TextComponent("$percent%").apply {
color = when {
percent <= 30 -> ChatColors.RED
percent <= 70 -> ChatColors.YELLOW
@ -54,11 +54,11 @@ class BreakProgressHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<Tex
this.percent = percent
}
companion object : HUDBuilder<BreakProgressHUDElement> {
companion object : HUDBuilder<LayoutedHUDElement<BreakProgressHUDElement>> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:progress_indicator".toResourceLocation()
override fun build(hudRenderer: HUDRenderer): BreakProgressHUDElement {
return BreakProgressHUDElement(hudRenderer)
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<BreakProgressHUDElement> {
return LayoutedHUDElement(BreakProgressHUDElement(hudRenderer))
}
}
}

View File

@ -22,12 +22,13 @@ import de.bixilon.minosoft.gui.rendering.gui.atlas.AtlasElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.CustomHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.system.base.BlendingFunctions
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
class CrosshairHUDElement(hudRenderer: HUDRenderer) : CustomHUDElement(hudRenderer) {
class CrosshairHUDElement(private val hudRenderer: HUDRenderer) : CustomHUDElement(hudRenderer) {
private val profile = hudRenderer.connection.profiles.hud
private val crosshairProfile = profile.crosshair
private lateinit var crosshairAtlasElement: AtlasElement
@ -41,7 +42,7 @@ class CrosshairHUDElement(hudRenderer: HUDRenderer) : CustomHUDElement(hudRender
}
override fun draw() {
val debugHUDElement: DebugHUDElement? = guiRenderer[DebugHUDElement]
val debugHUDElement: LayoutedHUDElement<DebugHUDElement>? = hudRenderer[DebugHUDElement]
if (debugHUDElement?.enabled != previousDebugEnabled || reapply) {
apply()
@ -75,7 +76,7 @@ class CrosshairHUDElement(hudRenderer: HUDRenderer) : CustomHUDElement(hudRender
}
}
val debugHUDElement: DebugHUDElement? = guiRenderer[DebugHUDElement]
val debugHUDElement: LayoutedHUDElement<DebugHUDElement>? = guiRenderer[DebugHUDElement]
if (debugHUDElement?.enabled == true) {
// ToDo: Debug crosshair

View File

@ -25,8 +25,10 @@ import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.data.world.Chunk
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
import de.bixilon.minosoft.gui.rendering.gui.elements.layout.RowLayout
import de.bixilon.minosoft.gui.rendering.gui.elements.layout.grid.GridGrow
import de.bixilon.minosoft.gui.rendering.gui.elements.layout.grid.GridLayout
@ -34,6 +36,7 @@ import de.bixilon.minosoft.gui.rendering.gui.elements.spacer.LineSpacerElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.AutoTextElement
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.Initializable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent
@ -53,10 +56,11 @@ import glm_.vec2.Vec2i
import glm_.vec4.Vec4i
import kotlin.math.abs
class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>(hudRenderer) {
class DebugHUDElement(hudRenderer: HUDRenderer) : GridLayout(hudRenderer, Vec2i(3, 1)), LayoutedElement, Initializable {
private val connection = renderWindow.connection
override val layoutOffset: Vec2i = Vec2i.EMPTY
override val layout = GridLayout(hudRenderer, Vec2i(3, 1)).apply {
init {
columnConstraints[0].apply {
grow = GridGrow.NEVER
}
@ -70,12 +74,11 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
override fun init() {
enabled = false
layout[Vec2i(0, 0)] = initLeft()
layout[Vec2i(2, 0)] = initRight()
this[Vec2i(0, 0)] = initLeft()
this[Vec2i(2, 0)] = initRight()
layout.prefMaxSize = Vec2i(-1, Int.MAX_VALUE)
layout.ignoreDisplaySize = true
this.prefMaxSize = Vec2i(-1, Int.MAX_VALUE)
this.ignoreDisplaySize = true
}
private fun initLeft(): Element {
@ -237,10 +240,10 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
return layout
}
private class DebugWorldInfo(hudRenderer: HUDRenderer) : RowLayout(hudRenderer) {
private class DebugWorldInfo(guiRenderer: AbstractGUIRenderer) : RowLayout(guiRenderer) {
private var lastChunk: Chunk? = null
private val world = hudRenderer.connection.world
private val entity = hudRenderer.connection.player
private val world = guiRenderer.renderWindow.connection.world
private val entity = guiRenderer.renderWindow.connection.player
init {
showWait()
@ -283,7 +286,7 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
}
}
companion object : HUDBuilder<DebugHUDElement> {
companion object : HUDBuilder<LayoutedHUDElement<DebugHUDElement>> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:debug_hud".toResourceLocation()
override val ENABLE_KEY_BINDING_NAME: ResourceLocation = "minosoft:enable_debug_hud".toResourceLocation()
override val DEFAULT_ENABLED: Boolean = false
@ -293,8 +296,8 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
),
)
override fun build(hudRenderer: HUDRenderer): DebugHUDElement {
return DebugHUDElement(hudRenderer)
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<DebugHUDElement> {
return LayoutedHUDElement(DebugHUDElement(hudRenderer)).apply { enabled = false }
}
}
}

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.other
import de.bixilon.kutil.math.MMath.round10
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
@ -23,11 +24,11 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
class WorldInfoHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TextElement>(hudRenderer), Pollable {
override val layout: TextElement = TextElement(hudRenderer, "")
class WorldInfoHUDElement(private val hudRenderer: HUDRenderer) : TextElement(hudRenderer, ""), LayoutedElement, Pollable {
override val layoutOffset: Vec2i = Vec2i(2, 2)
private var fps = -1.0
private var hide: Boolean = false
private val initialized = true
override fun tick() {
if (hide) {
@ -40,7 +41,10 @@ class WorldInfoHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TextEle
}
override fun poll(): Boolean {
val debugHUDElement: DebugHUDElement? = guiRenderer[DebugHUDElement]
if (!initialized) { // prevent NullPointerException (hudRenderer is null)
return false
}
val debugHUDElement = hudRenderer[DebugHUDElement]
val hide = debugHUDElement?.enabled == true
val fps = guiRenderer.renderWindow.renderStats.smoothAvgFPS.round10
if (this.hide == hide && this.fps == fps) {
@ -52,18 +56,18 @@ class WorldInfoHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TextEle
}
override fun apply() {
layout.text = if (hide) {
text = if (hide) {
""
} else {
"§aFPS $fps"
}
}
companion object : HUDBuilder<WorldInfoHUDElement> {
companion object : HUDBuilder<LayoutedHUDElement<WorldInfoHUDElement>> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:world_info".toResourceLocation()
override fun build(hudRenderer: HUDRenderer): WorldInfoHUDElement {
return WorldInfoHUDElement(hudRenderer)
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<WorldInfoHUDElement> {
return LayoutedHUDElement(WorldInfoHUDElement(hudRenderer))
}
}
}

View File

@ -1,95 +0,0 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.scoreboard
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.scoreboard.ScoreboardPositions
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
import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.modding.event.events.scoreboard.*
import de.bixilon.minosoft.modding.event.events.scoreboard.team.TeamUpdateEvent
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), Drawable {
private val connection = hudRenderer.connection
override val layout = ScoreboardSideElement(hudRenderer)
override val layoutOffset: Vec2i
get() = Vec2i(guiRenderer.scaledSize.x - layout.size.x, (guiRenderer.scaledSize.y - layout.size.y) / 2)
override val skipDraw: Boolean
get() = layout.objective == null
override fun init() {
connection.registerEvent(CallbackEventInvoker.of<ObjectivePositionSetEvent> {
if (it.position != ScoreboardPositions.SIDEBAR) {
return@of
}
layout.objective = it.objective
})
connection.registerEvent(CallbackEventInvoker.of<ScoreboardObjectiveUpdateEvent> {
if (it.objective != layout.objective) {
return@of
}
layout.updateName()
})
connection.registerEvent(CallbackEventInvoker.of<ScoreboardScoreRemoveEvent> {
if (it.score.objective != layout.objective) {
return@of
}
layout.removeScore(it.score)
})
connection.registerEvent(CallbackEventInvoker.of<ScoreboardScorePutEvent> {
if (it.score.objective != layout.objective) {
return@of
}
layout.updateScore(it.score)
})
connection.registerEvent(CallbackEventInvoker.of<ScoreTeamChangeEvent> {
if (it.score.objective != layout.objective) {
return@of
}
layout.updateScore(it.score)
})
connection.registerEvent(CallbackEventInvoker.of<TeamUpdateEvent> {
val objective = layout.objective ?: return@of
for ((_, score) in objective.scores) {
if (it.team != score.team) {
continue
}
layout.updateScore(score)
}
})
}
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()
override fun build(hudRenderer: HUDRenderer): ScoreboardHUDElement {
return ScoreboardHUDElement(hudRenderer)
}
}
}

View File

@ -15,27 +15,42 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard
import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedMap
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.scoreboard.ScoreboardObjective
import de.bixilon.minosoft.data.scoreboard.ScoreboardPositions
import de.bixilon.minosoft.data.scoreboard.ScoreboardScore
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
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.Initializable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.modding.event.events.scoreboard.*
import de.bixilon.minosoft.modding.event.events.scoreboard.team.TeamUpdateEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
class ScoreboardSideElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
class ScoreboardSideElement(hudRenderer: HUDRenderer) : Element(hudRenderer), LayoutedElement, Initializable, Drawable {
private val backgroundElement = ColorElement(hudRenderer, size = Vec2i.EMPTY, color = RenderConstants.TEXT_BACKGROUND_COLOR)
private val nameBackgroundElement = ColorElement(hudRenderer, size = Vec2i.EMPTY, color = RenderConstants.TEXT_BACKGROUND_COLOR)
private val nameElement = TextElement(hudRenderer, "", background = false, parent = this)
private val scores: MutableMap<ScoreboardScore, ScoreboardScoreElement> = synchronizedMapOf()
override val layoutOffset: Vec2i
get() = super.size.let { return@let Vec2i(guiRenderer.scaledSize.x - it.x, (guiRenderer.scaledSize.y - it.y) / 2) }
override val skipDraw: Boolean
get() = objective == null
var objective: ScoreboardObjective? = null
set(value) {
@ -138,10 +153,66 @@ class ScoreboardSideElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
queueSizeRecalculation()
}
companion object {
override fun init() {
val connection = renderWindow.connection
connection.registerEvent(CallbackEventInvoker.of<ObjectivePositionSetEvent> {
if (it.position != ScoreboardPositions.SIDEBAR) {
return@of
}
this.objective = it.objective
})
connection.registerEvent(CallbackEventInvoker.of<ScoreboardObjectiveUpdateEvent> {
if (it.objective != this.objective) {
return@of
}
this.updateName()
})
connection.registerEvent(CallbackEventInvoker.of<ScoreboardScoreRemoveEvent> {
if (it.score.objective != this.objective) {
return@of
}
this.removeScore(it.score)
})
connection.registerEvent(CallbackEventInvoker.of<ScoreboardScorePutEvent> {
if (it.score.objective != this.objective) {
return@of
}
this.updateScore(it.score)
})
connection.registerEvent(CallbackEventInvoker.of<ScoreTeamChangeEvent> {
if (it.score.objective != this.objective) {
return@of
}
this.updateScore(it.score)
})
connection.registerEvent(CallbackEventInvoker.of<TeamUpdateEvent> {
val objective = this.objective ?: return@of
for ((_, score) in objective.scores) {
if (it.team != score.team) {
continue
}
this.updateScore(score)
}
})
}
override fun draw() {
// check if content was changed, and we need to re-prepare before drawing
if (!cacheUpToDate) {
recalculateSize()
}
}
companion object : HUDBuilder<LayoutedHUDElement<ScoreboardSideElement>> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:scoreboard".toResourceLocation()
const val MAX_SCORES = 15
const val MIN_WIDTH = 30
const val SCORE_HEIGHT = Font.TOTAL_CHAR_HEIGHT
const val MAX_SCOREBOARD_WIDTH = 200
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<ScoreboardSideElement> {
return LayoutedHUDElement(ScoreboardSideElement(hudRenderer))
}
}
}

View File

@ -16,22 +16,36 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab
import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedMap
import de.bixilon.kutil.primitive.BooleanUtil.decide
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.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.gui.AbstractGUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.AtlasElement
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
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.Initializable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.modding.event.events.TabListEntryChangeEvent
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
import java.util.*
import java.util.concurrent.locks.ReentrantLock
class TabListElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer) {
class TabListElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer), LayoutedElement, Initializable, Drawable {
val header = TextElement(guiRenderer, "", background = false, fontAlignment = HorizontalAlignments.CENTER, parent = this)
val footer = TextElement(guiRenderer, "", background = false, fontAlignment = HorizontalAlignments.CENTER, parent = this)
@ -45,6 +59,9 @@ class TabListElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer) {
private set
private var columns = 0
override val layoutOffset: Vec2i
get() = Vec2i((guiRenderer.scaledSize.x - super.size.x) / 2, 20)
private val atlasManager = guiRenderer.renderWindow.atlasManager
val pingBarsAtlasElements: Array<AtlasElement> = arrayOf(
atlasManager["minecraft:tab_list_ping_0"]!!,
@ -55,6 +72,10 @@ class TabListElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer) {
atlasManager["minecraft:tab_list_ping_5"]!!,
)
init {
super.prefMaxSize = Vec2i(-1, -1)
}
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
background.render(offset, z, consumer, options)
@ -201,11 +222,49 @@ class TabListElement(guiRenderer: AbstractGUIRenderer) : Element(guiRenderer) {
}
companion object {
override fun init() {
val connection = renderWindow.connection
connection.registerEvent(CallbackEventInvoker.of<TabListInfoChangeEvent> {
header.text = it.header
footer.text = it.footer
})
connection.registerEvent(CallbackEventInvoker.of<TabListEntryChangeEvent> {
for ((uuid, entry) in it.items) {
if (entry == null) {
remove(uuid)
continue
}
update(uuid)
}
})
// ToDo: Also check team changes, scoreboard changes, etc
}
override fun draw() {
// check if content was changed, and we need to re-prepare before drawing
if (needsApply) {
forceApply()
}
}
companion object : HUDBuilder<LayoutedHUDElement<TabListElement>> {
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 = 3
private const val MAX_ENTRIES = 80
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:tab_list".toResourceLocation()
override val ENABLE_KEY_BINDING_NAME: ResourceLocation = "minosoft:enable_tab_list".toResourceLocation()
override val ENABLE_KEY_BINDING: KeyBinding = KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_TAB),
),
)
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<TabListElement> {
return LayoutedHUDElement(TabListElement(hudRenderer)).apply { enabled = false }
}
}
}

View File

@ -22,8 +22,8 @@ import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.AtlasImageElement
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.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
@ -46,7 +46,7 @@ class TabListEntryElement(
private val background: ColorElement
private val nameElement = TextElement(guiRenderer, "", background = false, parent = this)
private lateinit var pingElement: ImageElement
private lateinit var pingElement: AtlasImageElement
private var displayName: ChatComponent = item.displayName
private var ping = item.ping
@ -86,7 +86,7 @@ class TabListEntryElement(
override fun forceSilentApply() {
// ToDo (Performance): If something changed, should we just prepare the changed
pingElement = ImageElement(guiRenderer, tabList.pingBarsAtlasElements[when {
pingElement = AtlasImageElement(guiRenderer, tabList.pingBarsAtlasElements[when {
ping < 0 -> 0
ping < 150 -> 5
ping < 300 -> 4

View File

@ -1,82 +0,0 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.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.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.modding.event.events.TabListEntryChangeEvent
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) : LayoutedHUDElement<TabListElement>(hudRenderer), Drawable {
private val connection = renderWindow.connection
override val layout = TabListElement(hudRenderer)
override val layoutOffset: Vec2i
get() = Vec2i((guiRenderer.scaledSize.x - layout.size.x) / 2, 20)
init {
enabled = false
layout.prefMaxSize = Vec2i(-1, -1)
}
override fun init() {
connection.registerEvent(CallbackEventInvoker.of<TabListInfoChangeEvent> {
layout.header.text = it.header
layout.footer.text = it.footer
})
connection.registerEvent(CallbackEventInvoker.of<TabListEntryChangeEvent> {
for ((uuid, entry) in it.items) {
if (entry == null) {
layout.remove(uuid)
continue
}
layout.update(uuid)
}
})
// ToDo: Also check team changes, scoreboard changes, etc
}
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()
override val ENABLE_KEY_BINDING_NAME: ResourceLocation = "minosoft:enable_tab_list".toResourceLocation()
override val ENABLE_KEY_BINDING: KeyBinding = KeyBinding(
mapOf(
KeyAction.CHANGE to setOf(KeyCodes.KEY_TAB),
),
)
override fun build(hudRenderer: HUDRenderer): TabListHUDElement {
return TabListHUDElement(hudRenderer)
}
}
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
* Copyright (C) 2020-2022 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.
*
@ -13,20 +13,29 @@
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.title
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.LayoutedElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.FadingTextElement
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.Initializable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
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.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.modding.event.events.title.*
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
import java.lang.Integer.max
// ToDo: Remove subtitle when hidden
class TitleElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
class TitleElement(hudRenderer: HUDRenderer) : Element(hudRenderer), LayoutedElement, Initializable {
val title = FadingTextElement(hudRenderer, "", background = false, scale = 4.0f, parent = this)
val subtitle = FadingTextElement(hudRenderer, "", background = false, scale = 2.0f, parent = this)
var fadeInTime = 0L
@ -58,6 +67,18 @@ class TitleElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
super.cacheEnabled = value
}
override val layoutOffset: Vec2i
get() {
val layoutOffset = Vec2i.EMPTY
val scaledSize = guiRenderer.scaledSize
layoutOffset.x = (scaledSize.x - super.size.x / 2) / 2
layoutOffset.y = (scaledSize.y / 2 - title.size.y)
return layoutOffset
}
init {
fadeInTime = DEFAULT_FADE_IN_TIME
stayTime = DEFAULT_STAY_TIME
@ -103,10 +124,39 @@ class TitleElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
fadeOutTime = DEFAULT_FADE_OUT_TIME
}
companion object {
override fun init() {
val connection = renderWindow.connection
connection.registerEvent(CallbackEventInvoker.of<TitleResetEvent> {
this.reset()
})
connection.registerEvent(CallbackEventInvoker.of<TitleHideEvent> {
this.hide()
})
connection.registerEvent(CallbackEventInvoker.of<TitleSetEvent> {
this.title.text = it.title
this.show()
})
connection.registerEvent(CallbackEventInvoker.of<TitleSubtitleSetEvent> {
this.subtitle.text = it.subtitle
// layout.show() // non vanilla behavior
})
connection.registerEvent(CallbackEventInvoker.of<TitleTimesSetEvent> {
this.fadeInTime = it.fadeInTime * ProtocolDefinition.TICK_TIME.toLong()
this.stayTime = it.stayTime * ProtocolDefinition.TICK_TIME.toLong()
this.fadeOutTime = it.fadeOutTime * ProtocolDefinition.TICK_TIME.toLong()
})
}
companion object : HUDBuilder<LayoutedHUDElement<TitleElement>> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:title".toResourceLocation()
const val SUBTITLE_VERTICAL_OFFSET = 10
const val DEFAULT_FADE_IN_TIME = 20L * ProtocolDefinition.TICK_TIME
const val DEFAULT_STAY_TIME = 60L * ProtocolDefinition.TICK_TIME
const val DEFAULT_FADE_OUT_TIME = 20L * ProtocolDefinition.TICK_TIME
override fun build(hudRenderer: HUDRenderer): LayoutedHUDElement<TitleElement> {
return LayoutedHUDElement(TitleElement(hudRenderer))
}
}
}

View File

@ -1,74 +0,0 @@
/*
* Minosoft
* Copyright (C) 2020-2022 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.title
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.LayoutedHUDElement
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.modding.event.events.title.*
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
class TitleHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<TitleElement>(hudRenderer) {
override val layout: TitleElement = TitleElement(hudRenderer)
override val layoutOffset: Vec2i
get() {
val layoutOffset = Vec2i.EMPTY
val scaledSize = guiRenderer.scaledSize
layoutOffset.x = (scaledSize.x - layout.size.x / 2) / 2
layoutOffset.y = (scaledSize.y / 2 - layout.title.size.y)
return layoutOffset
}
override fun init() {
val connection = guiRenderer.connection
connection.registerEvent(CallbackEventInvoker.of<TitleResetEvent> {
layout.reset()
})
connection.registerEvent(CallbackEventInvoker.of<TitleHideEvent> {
layout.hide()
})
connection.registerEvent(CallbackEventInvoker.of<TitleSetEvent> {
layout.title.text = it.title
layout.show()
})
connection.registerEvent(CallbackEventInvoker.of<TitleSubtitleSetEvent> {
layout.subtitle.text = it.subtitle
// layout.show() // non vanilla behavior
})
connection.registerEvent(CallbackEventInvoker.of<TitleTimesSetEvent> {
layout.fadeInTime = it.fadeInTime * ProtocolDefinition.TICK_TIME.toLong()
layout.stayTime = it.stayTime * ProtocolDefinition.TICK_TIME.toLong()
layout.fadeOutTime = it.fadeOutTime * ProtocolDefinition.TICK_TIME.toLong()
})
}
companion object : HUDBuilder<TitleHUDElement> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:title".toResourceLocation()
override fun build(hudRenderer: HUDRenderer): TitleHUDElement {
return TitleHUDElement(hudRenderer)
}
}
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
* Copyright (C) 2020-2022 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.
*
@ -20,5 +20,5 @@ interface Drawable {
/**
* Functions gets called every frame
*/
fun draw()
fun draw() {}
}