mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 02:15:34 -04:00
hud: title fixes, vehicle health element
This commit is contained in:
parent
8b6389b4c1
commit
0f0c887fa7
@ -0,0 +1,49 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar
|
||||||
|
|
||||||
|
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.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.gui.mesh.GUIVertexOptions
|
||||||
|
import de.bixilon.minosoft.util.MMath.ceil
|
||||||
|
import glm_.vec2.Vec2i
|
||||||
|
|
||||||
|
abstract class AbstractHotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||||
|
abstract val totalHealth: Float
|
||||||
|
abstract val totalMaxHealth: Float
|
||||||
|
var totalMaxHearts = 0
|
||||||
|
var rows = 0
|
||||||
|
|
||||||
|
|
||||||
|
override fun forceSilentApply() {
|
||||||
|
totalMaxHearts = (totalMaxHealth / 2).ceil
|
||||||
|
|
||||||
|
rows = totalMaxHearts / HEARTS_PER_ROW
|
||||||
|
if (totalMaxHearts % HEARTS_PER_ROW != 0) {
|
||||||
|
rows++
|
||||||
|
}
|
||||||
|
|
||||||
|
_size = Vec2i(HEARTS_PER_ROW, rows) * HEART_SIZE + Vec2i(1, 0) // 1 pixel is overlapping, so we have one more for the heart
|
||||||
|
cacheUpToDate = false
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun drawCanisters(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?, atlasElement: HUDAtlasElement) {
|
||||||
|
for (heart in 0 until totalMaxHearts) {
|
||||||
|
val row = heart / HEARTS_PER_ROW
|
||||||
|
val column = heart % HEARTS_PER_ROW
|
||||||
|
|
||||||
|
val image = ImageElement(hudRenderer, atlasElement)
|
||||||
|
|
||||||
|
image.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z, consumer, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val LAYERS = 2
|
||||||
|
private const val HP_PER_ROW = 20
|
||||||
|
const val HEARTS_PER_ROW = HP_PER_ROW / 2
|
||||||
|
val HEART_SIZE = Vec2i(8, 9)
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ class HotbarCoreElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
|||||||
val hunger = HotbarHungerElement(hudRenderer)
|
val hunger = HotbarHungerElement(hudRenderer)
|
||||||
val protection = HotbarProtectionElement(hudRenderer)
|
val protection = HotbarProtectionElement(hudRenderer)
|
||||||
val air = HotbarAirElement(hudRenderer)
|
val air = HotbarAirElement(hudRenderer)
|
||||||
|
val vehicleHealth = HotbarVehicleHealthElement(hudRenderer)
|
||||||
|
|
||||||
private val topLeft = RowLayout(hudRenderer, HorizontalAlignments.LEFT, 1) // contains health, protection, etc
|
private val topLeft = RowLayout(hudRenderer, HorizontalAlignments.LEFT, 1) // contains health, protection, etc
|
||||||
private val topRight = RowLayout(hudRenderer, HorizontalAlignments.RIGHT, 1) // contains hunger, air
|
private val topRight = RowLayout(hudRenderer, HorizontalAlignments.RIGHT, 1) // contains hunger, air
|
||||||
@ -67,6 +68,7 @@ class HotbarCoreElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
|||||||
|
|
||||||
topRight += air
|
topRight += air
|
||||||
topRight += hunger
|
topRight += hunger
|
||||||
|
topRight += vehicleHealth // non notchain, but better imho
|
||||||
|
|
||||||
|
|
||||||
base.parent = this
|
base.parent = this
|
||||||
|
@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar
|
|||||||
|
|
||||||
import de.bixilon.minosoft.data.registries.effects.DefaultStatusEffects
|
import de.bixilon.minosoft.data.registries.effects.DefaultStatusEffects
|
||||||
import de.bixilon.minosoft.data.registries.effects.attributes.DefaultStatusEffectAttributeNames
|
import de.bixilon.minosoft.data.registries.effects.attributes.DefaultStatusEffectAttributeNames
|
||||||
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.Pollable
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
|
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
|
||||||
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
|
||||||
@ -24,18 +23,17 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
|||||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
||||||
import de.bixilon.minosoft.util.KUtil.decide
|
import de.bixilon.minosoft.util.KUtil.decide
|
||||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||||
import de.bixilon.minosoft.util.MMath.ceil
|
|
||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
import java.lang.Float.max
|
import java.lang.Float.max
|
||||||
import java.lang.Float.min
|
import java.lang.Float.min
|
||||||
|
|
||||||
class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Pollable {
|
class HotbarHealthElement(hudRenderer: HUDRenderer) : AbstractHotbarHealthElement(hudRenderer), Pollable {
|
||||||
private val witherStatusEffect = hudRenderer.connection.registries.statusEffectRegistry[DefaultStatusEffects.WITHER]
|
private val witherStatusEffect = hudRenderer.connection.registries.statusEffectRegistry[DefaultStatusEffects.WITHER]
|
||||||
private val poisonStatusEffect = hudRenderer.connection.registries.statusEffectRegistry[DefaultStatusEffects.POISON]
|
private val poisonStatusEffect = hudRenderer.connection.registries.statusEffectRegistry[DefaultStatusEffects.POISON]
|
||||||
private val atlasManager = hudRenderer.atlasManager
|
private val atlasManager = hudRenderer.atlasManager
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [normal|hardcore][normal|poison|wither][normal|damage][full|half]
|
* [normal|hardcore] [normal|poison|wither] [normal|damage] [full|half]
|
||||||
*/
|
*/
|
||||||
private val hearts = arrayOf(
|
private val hearts = arrayOf(
|
||||||
arrayOf(
|
arrayOf(
|
||||||
@ -140,24 +138,14 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Poll
|
|||||||
|
|
||||||
private var health = 0.0f
|
private var health = 0.0f
|
||||||
private var absorptionsAmount = 0.0f
|
private var absorptionsAmount = 0.0f
|
||||||
private var totalHealth = 0.0f
|
override var totalHealth = 0.0f
|
||||||
|
|
||||||
private var maxHealth = 0.0f
|
private var maxHealth = 0.0f
|
||||||
private var totalMaxHealth = 0.0f
|
override var totalMaxHealth = 0.0f
|
||||||
|
|
||||||
private var totalMaxHearts = 0
|
|
||||||
private var rows = 0
|
|
||||||
|
|
||||||
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
|
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
|
||||||
// ToDo: Damage animation, regeneration, caching, stacking (and eventual text replace)
|
// ToDo: Damage animation, regeneration, caching, stacking (and eventual text replace)
|
||||||
for (heart in 0 until totalMaxHearts) {
|
drawCanisters(offset, z, consumer, options, blackHeartContainer)
|
||||||
val row = heart / HEARTS_PER_ROW
|
|
||||||
val column = heart % HEARTS_PER_ROW
|
|
||||||
|
|
||||||
val image = ImageElement(hudRenderer, blackHeartContainer)
|
|
||||||
|
|
||||||
image.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z, consumer, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
val hardcoreIndex = hardcode.decide(1, 0)
|
val hardcoreIndex = hardcode.decide(1, 0)
|
||||||
|
|
||||||
@ -198,10 +186,10 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Poll
|
|||||||
|
|
||||||
|
|
||||||
val halfHeart = healthLeft < 1.5f
|
val halfHeart = healthLeft < 1.5f
|
||||||
val image = when {
|
val image = selectArray.unsafeCast<Array<HUDAtlasElement?>>()[when {
|
||||||
halfHeart -> selectArray.unsafeCast<Array<HUDAtlasElement?>>()[1]?.let { ImageElement(hudRenderer, it) }
|
halfHeart -> 1
|
||||||
else -> selectArray.unsafeCast<Array<HUDAtlasElement?>>()[0]?.let { ImageElement(hudRenderer, it) }
|
else -> 0
|
||||||
}
|
}]?.let { ImageElement(hudRenderer, it) }
|
||||||
|
|
||||||
image?.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z + 1, consumer, options)
|
image?.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z + 1, consumer, options)
|
||||||
|
|
||||||
@ -209,23 +197,14 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Poll
|
|||||||
healthLeft -= halfHeart.decide(1.0f, 2.0f)
|
healthLeft -= halfHeart.decide(1.0f, 2.0f)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 2
|
return LAYERS
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forceSilentApply() {
|
override fun forceSilentApply() {
|
||||||
totalHealth = health + absorptionsAmount
|
totalHealth = health + absorptionsAmount
|
||||||
|
|
||||||
totalMaxHealth = maxHealth + absorptionsAmount
|
totalMaxHealth = maxHealth + absorptionsAmount
|
||||||
|
super.forceSilentApply()
|
||||||
totalMaxHearts = (totalMaxHealth / 2).ceil
|
|
||||||
|
|
||||||
rows = totalMaxHearts / HEARTS_PER_ROW
|
|
||||||
if (totalMaxHearts % HEARTS_PER_ROW != 0) {
|
|
||||||
rows++
|
|
||||||
}
|
|
||||||
|
|
||||||
_size = Vec2i(HEARTS_PER_ROW, rows) * HEART_SIZE + Vec2i(1, 0) // 1 pixel is overlapping, so we have one more for the heart
|
|
||||||
cacheUpToDate = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun poll(): Boolean {
|
override fun poll(): Boolean {
|
||||||
@ -263,10 +242,4 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Poll
|
|||||||
override fun tick() {
|
override fun tick() {
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val HP_PER_ROW = 20
|
|
||||||
private const val HEARTS_PER_ROW = HP_PER_ROW / 2
|
|
||||||
private val HEART_SIZE = Vec2i(8, 9)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* 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.hotbar
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.entities.entities.LivingEntity
|
||||||
|
import de.bixilon.minosoft.data.registries.effects.attributes.DefaultStatusEffectAttributeNames
|
||||||
|
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.hud.HUDRenderer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
||||||
|
import de.bixilon.minosoft.util.KUtil.decide
|
||||||
|
import glm_.vec2.Vec2i
|
||||||
|
import java.lang.Float
|
||||||
|
import kotlin.Boolean
|
||||||
|
import kotlin.Int
|
||||||
|
import kotlin.arrayOf
|
||||||
|
import kotlin.let
|
||||||
|
|
||||||
|
class HotbarVehicleHealthElement(hudRenderer: HUDRenderer) : AbstractHotbarHealthElement(hudRenderer), Pollable {
|
||||||
|
private val atlasManager = hudRenderer.atlasManager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [full|half]
|
||||||
|
*/
|
||||||
|
private val hearts = arrayOf(
|
||||||
|
atlasManager["minecraft:vehicle_heart"],
|
||||||
|
atlasManager["minecraft:vehicle_half_heart"],
|
||||||
|
)
|
||||||
|
private val vehicleHeartContainer = atlasManager["minecraft:vehicle_heart_container"]!!
|
||||||
|
|
||||||
|
private var shown = false
|
||||||
|
override var totalHealth = 0.0f
|
||||||
|
override var totalMaxHealth = 0.0f
|
||||||
|
|
||||||
|
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
|
||||||
|
// ToDo: Eventual text replace
|
||||||
|
drawCanisters(offset, z, consumer, options, vehicleHeartContainer)
|
||||||
|
|
||||||
|
var healthLeft = totalHealth
|
||||||
|
var heart = 0
|
||||||
|
|
||||||
|
while (healthLeft >= 0.5f) {
|
||||||
|
val row = heart / HEARTS_PER_ROW
|
||||||
|
val column = heart % HEARTS_PER_ROW
|
||||||
|
|
||||||
|
|
||||||
|
val halfHeart = healthLeft < 1.5f
|
||||||
|
val image = hearts[when {
|
||||||
|
halfHeart -> 1
|
||||||
|
else -> 0
|
||||||
|
}]?.let { ImageElement(hudRenderer, it) }
|
||||||
|
|
||||||
|
image?.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z + 1, consumer, options)
|
||||||
|
|
||||||
|
heart++
|
||||||
|
healthLeft -= halfHeart.decide(1.0f, 2.0f)
|
||||||
|
}
|
||||||
|
|
||||||
|
return LAYERS
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun poll(): Boolean {
|
||||||
|
val riddenEntity = hudRenderer.connection.player.vehicle
|
||||||
|
if (riddenEntity == null || riddenEntity !is LivingEntity) {
|
||||||
|
if (this.shown) {
|
||||||
|
this.shown = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val health = riddenEntity.health.toFloat()
|
||||||
|
val maxHealth = Float.max(0.0f, riddenEntity.getAttributeValue(DefaultStatusEffectAttributeNames.GENERIC_MAX_HEALTH).toFloat())
|
||||||
|
|
||||||
|
if (health == this.totalHealth && this.totalMaxHealth == maxHealth) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
this.totalHealth = health
|
||||||
|
this.totalMaxHealth = maxHealth
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick() {
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
@ -26,8 +26,8 @@ import glm_.vec2.Vec2i
|
|||||||
import java.lang.Integer.max
|
import java.lang.Integer.max
|
||||||
|
|
||||||
class TitleElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
class TitleElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||||
val title = FadingTextElement(hudRenderer, "", scale = 4.0f, parent = this)
|
val title = FadingTextElement(hudRenderer, "", background = false, scale = 4.0f, parent = this)
|
||||||
val subtitle = FadingTextElement(hudRenderer, "", parent = this)
|
val subtitle = FadingTextElement(hudRenderer, "", background = false, parent = this)
|
||||||
var fadeInTime = 0L
|
var fadeInTime = 0L
|
||||||
set(value) {
|
set(value) {
|
||||||
title.fadeInTime = value
|
title.fadeInTime = value
|
||||||
@ -46,6 +46,16 @@ class TitleElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
|||||||
subtitle.fadeOutTime = value
|
subtitle.fadeOutTime = value
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
override var cacheEnabled: Boolean
|
||||||
|
get() = super.cacheEnabled && title.cacheEnabled && subtitle.cacheEnabled
|
||||||
|
set(value) {
|
||||||
|
super.cacheEnabled = value
|
||||||
|
}
|
||||||
|
override var cacheUpToDate: Boolean
|
||||||
|
get() = super.cacheUpToDate && title.cacheUpToDate && subtitle.cacheUpToDate
|
||||||
|
set(value) {
|
||||||
|
super.cacheEnabled = value
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
fadeInTime = DEFAULT_FADE_IN_TIME
|
fadeInTime = DEFAULT_FADE_IN_TIME
|
||||||
|
@ -23,5 +23,4 @@ class TitleHideEvent(
|
|||||||
) : PlayConnectionEvent(connection, initiator) {
|
) : PlayConnectionEvent(connection, initiator) {
|
||||||
|
|
||||||
constructor(connection: PlayConnection, packet: TitleHideS2CP) : this(connection, EventInitiators.SERVER)
|
constructor(connection: PlayConnection, packet: TitleHideS2CP) : this(connection, EventInitiators.SERVER)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -470,5 +470,26 @@
|
|||||||
"start": [25, 18],
|
"start": [25, 18],
|
||||||
"end": [34, 27]
|
"end": [34, 27]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"minecraft:vehicle_heart_container": {
|
||||||
|
"0": {
|
||||||
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
"start": [52, 9],
|
||||||
|
"end": [61, 18]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:vehicle_heart": {
|
||||||
|
"0": {
|
||||||
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
"start": [97, 9],
|
||||||
|
"end": [106, 18]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:vehicle_half_heart": {
|
||||||
|
"0": {
|
||||||
|
"texture": "minecraft:textures/gui/icons.png",
|
||||||
|
"start": [88, 9],
|
||||||
|
"end": [97, 18]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user