mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 09:56:37 -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 protection = HotbarProtectionElement(hudRenderer)
|
||||
val air = HotbarAirElement(hudRenderer)
|
||||
val vehicleHealth = HotbarVehicleHealthElement(hudRenderer)
|
||||
|
||||
private val topLeft = RowLayout(hudRenderer, HorizontalAlignments.LEFT, 1) // contains health, protection, etc
|
||||
private val topRight = RowLayout(hudRenderer, HorizontalAlignments.RIGHT, 1) // contains hunger, air
|
||||
@ -67,6 +68,7 @@ class HotbarCoreElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
|
||||
topRight += air
|
||||
topRight += hunger
|
||||
topRight += vehicleHealth // non notchain, but better imho
|
||||
|
||||
|
||||
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.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.primitive.ImageElement
|
||||
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.util.KUtil.decide
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import de.bixilon.minosoft.util.MMath.ceil
|
||||
import glm_.vec2.Vec2i
|
||||
import java.lang.Float.max
|
||||
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 poisonStatusEffect = hudRenderer.connection.registries.statusEffectRegistry[DefaultStatusEffects.POISON]
|
||||
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(
|
||||
arrayOf(
|
||||
@ -140,24 +138,14 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Poll
|
||||
|
||||
private var health = 0.0f
|
||||
private var absorptionsAmount = 0.0f
|
||||
private var totalHealth = 0.0f
|
||||
override var totalHealth = 0.0f
|
||||
|
||||
private var maxHealth = 0.0f
|
||||
private var totalMaxHealth = 0.0f
|
||||
|
||||
private var totalMaxHearts = 0
|
||||
private var rows = 0
|
||||
override var totalMaxHealth = 0.0f
|
||||
|
||||
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
|
||||
// ToDo: Damage animation, regeneration, caching, stacking (and eventual text replace)
|
||||
for (heart in 0 until totalMaxHearts) {
|
||||
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)
|
||||
}
|
||||
drawCanisters(offset, z, consumer, options, blackHeartContainer)
|
||||
|
||||
val hardcoreIndex = hardcode.decide(1, 0)
|
||||
|
||||
@ -198,10 +186,10 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Poll
|
||||
|
||||
|
||||
val halfHeart = healthLeft < 1.5f
|
||||
val image = when {
|
||||
halfHeart -> selectArray.unsafeCast<Array<HUDAtlasElement?>>()[1]?.let { ImageElement(hudRenderer, it) }
|
||||
else -> selectArray.unsafeCast<Array<HUDAtlasElement?>>()[0]?.let { ImageElement(hudRenderer, it) }
|
||||
}
|
||||
val image = selectArray.unsafeCast<Array<HUDAtlasElement?>>()[when {
|
||||
halfHeart -> 1
|
||||
else -> 0
|
||||
}]?.let { ImageElement(hudRenderer, it) }
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
return 2
|
||||
return LAYERS
|
||||
}
|
||||
|
||||
override fun forceSilentApply() {
|
||||
totalHealth = health + absorptionsAmount
|
||||
|
||||
totalMaxHealth = maxHealth + absorptionsAmount
|
||||
|
||||
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
|
||||
super.forceSilentApply()
|
||||
}
|
||||
|
||||
override fun poll(): Boolean {
|
||||
@ -263,10 +242,4 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Poll
|
||||
override fun tick() {
|
||||
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
|
||||
|
||||
class TitleElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
val title = FadingTextElement(hudRenderer, "", scale = 4.0f, parent = this)
|
||||
val subtitle = FadingTextElement(hudRenderer, "", parent = this)
|
||||
val title = FadingTextElement(hudRenderer, "", background = false, scale = 4.0f, parent = this)
|
||||
val subtitle = FadingTextElement(hudRenderer, "", background = false, parent = this)
|
||||
var fadeInTime = 0L
|
||||
set(value) {
|
||||
title.fadeInTime = value
|
||||
@ -46,6 +46,16 @@ class TitleElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
|
||||
subtitle.fadeOutTime = 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 {
|
||||
fadeInTime = DEFAULT_FADE_IN_TIME
|
||||
|
@ -23,5 +23,4 @@ class TitleHideEvent(
|
||||
) : PlayConnectionEvent(connection, initiator) {
|
||||
|
||||
constructor(connection: PlayConnection, packet: TitleHideS2CP) : this(connection, EventInitiators.SERVER)
|
||||
|
||||
}
|
||||
|
@ -470,5 +470,26 @@
|
||||
"start": [25, 18],
|
||||
"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