fixes, wip health bar

This commit is contained in:
Bixilon 2021-03-12 00:22:58 +01:00
parent 97c3e3232e
commit 4aeb127f6b
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 208 additions and 16 deletions

View File

@ -21,6 +21,7 @@ import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.hud.atlas.HUDAtlasElement
import de.bixilon.minosoft.gui.rendering.hud.elements.HUDElement
import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.HealthBar
import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.ProgressBar
import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.TextElement
@ -28,6 +29,7 @@ import de.bixilon.minosoft.modding.event.EventInvokerCallback
import de.bixilon.minosoft.modding.event.events.ChangeGameStateEvent
import de.bixilon.minosoft.modding.event.events.ExperienceChangeEvent
import de.bixilon.minosoft.modding.event.events.HeldItemChangeEvent
import de.bixilon.minosoft.modding.event.events.UpdateHealthEvent
import de.bixilon.minosoft.protocol.packets.clientbound.play.PacketChangeGameState
import glm_.vec2.Vec2
@ -40,6 +42,8 @@ class HotbarHUDElement(
private lateinit var experienceBar: ProgressBar
private lateinit var levelText: TextElement
private lateinit var healthBar: HealthBar
override fun init() {
hotbarBaseAtlasElement = hudRenderer.hudAtlasElements[ResourceLocation("minecraft:hotbar_base")]!!
@ -55,6 +59,19 @@ class HotbarHUDElement(
levelText = TextElement(start = Vec2(), font = hudRenderer.renderWindow.font, background = false)
healthBar = HealthBar(
Vec2(0, 0),
hudRenderer.hudAtlasElements[ResourceLocation("minecraft:black_heart_container")]!!,
hudRenderer.hudAtlasElements[ResourceLocation("minecraft:white_heart_container")]!!,
hudRenderer.hudAtlasElements[ResourceLocation("minecraft:half_red_heart")]!!,
hudRenderer.hudAtlasElements[ResourceLocation("minecraft:full_red_heart")]!!,
20.0f,
40.0f,
RenderConstants.HP_TEXT_COLOR,
hudRenderer.renderWindow.font,
5
)
registerEvents()
prepare()
@ -83,6 +100,10 @@ class HotbarHUDElement(
}
prepare()
})
hudRenderer.connection.registerEvent(EventInvokerCallback<UpdateHealthEvent> {
healthBar.value = it.health
prepare()
})
}
@ -97,9 +118,15 @@ class HotbarHUDElement(
if (hudRenderer.connection.player.gamemode != Gamemodes.CREATIVE) {
// experience
levelText.start = Vec2((hotbarBaseAtlasElement.binding.size.x - levelText.size.x) / 2, elementList.size.y)
elementList.addChild(levelText)
healthBar.prepare()
elementList.addChild(healthBar)
if (hudRenderer.connection.player.level != 0) {
// experience
levelText.start = Vec2((hotbarBaseAtlasElement.binding.size.x - levelText.size.x) / 2, elementList.size.y - 3 * ELEMENT_PADDING)
elementList.addChild(levelText)
}
// experience bar
experienceBar.start.y = elementList.size.y - ELEMENT_PADDING

View File

@ -27,13 +27,17 @@ open class ElementListElement(
fun clear() {
clearCache()
children.clear()
synchronized(children) {
children.clear()
}
recalculateSize()
}
fun addChild(child: Element) {
child.parent = this
children.add(child)
synchronized(children) {
children.add(child)
}
cache.clear()
recalculateSize()
}
@ -50,8 +54,10 @@ open class ElementListElement(
override fun clearCache() {
cache.clear()
for (child in children) {
child.clearCache()
synchronized(children) {
for (child in children) {
child.clearCache()
}
}
}
@ -84,9 +90,12 @@ open class ElementListElement(
override fun prepareCache(start: Vec2, scaleFactor: Float, matrix: Mat4, z: Int) {
val normalStart = addToStart(start, this.start * scaleFactor)
for (child in children) {
child.checkCache(normalStart, scaleFactor, matrix, this.z + z)
cache.addCache(child.cache)
synchronized(children) {
for (child in children) {
child.checkCache(normalStart, scaleFactor, matrix, this.z + z)
cache.addCache(child.cache)
}
}
}
}

View File

@ -0,0 +1,135 @@
/*
* 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.hud.elements.primitive
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.hud.atlas.HUDAtlasElement
import de.bixilon.minosoft.util.MMath
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
class HealthBar(
start: Vec2,
var blackHeartContainerAtlasElement: HUDAtlasElement,
var whiteHeartContainerAtlasElement: HUDAtlasElement,
var halfHartAtlasElement: HUDAtlasElement,
var hartAtlasElement: HUDAtlasElement,
var maxValue: Float,
var textReplaceValue: Float,
var textColor: RGBColor,
var font: Font,
z: Int = 1,
) : ElementListElement(start, z) {
private val singleHeartSize = blackHeartContainerAtlasElement.binding.size
private val width = singleHeartSize.x * MAX_HEARTS_IN_ROW
private val alternativeText = TextElement(font = font, start = Vec2(), background = false)
private var _value = 0.0f
var value: Float
get() = _value
set(value) {
_value = if (value < 0.0f) {
0.0f
} else {
value
}
cache.clear()
}
fun prepare() {
clear()
if (value >= textReplaceValue) {
alternativeText.text = TextComponent(value.toString()).setColor(textColor)
alternativeText.start = Vec2((width - alternativeText.size.x) / 2, 0)
addChild(alternativeText)
return
}
val offset = Vec2(0, 0)
val containerCount = (maxValue + 1.0f).toInt() / 2
// heart container
val rows = MMath.divideUp(containerCount, MAX_HEARTS_IN_ROW)
for (row in 0 until rows) {
val heartsToDraw = if (row == 0 && containerCount % MAX_HEARTS_IN_ROW != 0) {
containerCount % MAX_HEARTS_IN_ROW
} else {
MAX_HEARTS_IN_ROW
}
for (i in 0 until heartsToDraw) {
drawHeart(this.start + offset, blackHeartContainerAtlasElement, z)
offset.x += singleHeartSize.x - 1
}
offset.y += singleHeartSize.y
offset.x = 0.0f
}
offset.x = 0.0f
offset.y = 0.0f
val halfHeartCount = MMath.round10Up(value)
val fullHeartCount = halfHeartCount / 2
val addHalfHeart = halfHeartCount % 2 == 1
var currentHeart = fullHeartCount - 1
if (addHalfHeart) {
currentHeart += 1
}
for (row in rows - 1 downTo 0) {
val heartsInRow = if (row == 0 && containerCount % MAX_HEARTS_IN_ROW != 0) {
containerCount % MAX_HEARTS_IN_ROW
} else {
MAX_HEARTS_IN_ROW
}
for (i in 0 until heartsInRow) {
if (currentHeart < 0) {
break
}
if (currentHeart == 0 && addHalfHeart) {
drawHeart(this.start + offset, halfHartAtlasElement, z + 1)
} else {
drawHeart(this.start + offset, hartAtlasElement, z + 1)
}
currentHeart--
offset.x += singleHeartSize.x - 1
}
offset.y += singleHeartSize.y
offset.x = 0.0f
}
}
override fun prepareCache(start: Vec2, scaleFactor: Float, matrix: Mat4, z: Int) {
prepare()
super.prepareCache(start, scaleFactor, matrix, z)
}
private fun drawHeart(elementStart: Vec2, element: HUDAtlasElement, z: Int) {
addChild(ImageElement(elementStart, elementStart + singleHeartSize, element, z))
}
companion object {
const val MAX_HEARTS_IN_ROW = 10
}
}

View File

@ -36,7 +36,7 @@ class TextElement(
var sText: String
get() = text.message
set(value) {
text = ChatComponent.valueOf(sText)
text = ChatComponent.valueOf(value)
}
init {

View File

@ -59,7 +59,7 @@ class TextureArray(val textures: MutableList<Texture>) {
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
// glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST) // ToDo: This breaks transparency again
// glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR) // ToDo: This breaks transparency again
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, maxWidth, maxHeight, textures.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?)

View File

@ -19,7 +19,7 @@ import de.bixilon.minosoft.protocol.packets.clientbound.play.PacketChangeGameSta
/**
* Fired when the player should spectate an entity
*/
public class ChangeGameStateEvent extends CancelableEvent {
public class ChangeGameStateEvent extends ConnectionEvent {
private final PacketChangeGameState.Reason reason;
private final float value;

View File

@ -22,7 +22,7 @@ import de.bixilon.minosoft.protocol.packets.clientbound.play.PacketCollectItem;
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_16W32A;
public class CollectItemAnimationEvent extends CancelableEvent {
private final ItemEntity item;
private final Entity item;
private final Entity collector;
private final int count;
@ -35,12 +35,12 @@ public class CollectItemAnimationEvent extends CancelableEvent {
public CollectItemAnimationEvent(Connection connection, PacketCollectItem pkg) {
super(connection);
this.item = (ItemEntity) connection.getPlayer().getWorld().getEntity(pkg.getItemEntityId());
this.item = connection.getPlayer().getWorld().getEntity(pkg.getItemEntityId());
this.collector = connection.getPlayer().getWorld().getEntity(pkg.getCollectorEntityId());
this.count = pkg.getCount();
}
public ItemEntity getItem() {
public Entity getItem() {
return this.item;
}

View File

@ -33,4 +33,25 @@ object MMath {
}
return value
}
fun divideUp(value: Int, divider: Int): Int {
return (value + divider - 1) / divider
}
fun divideUp(value: Float, divider: Float): Float {
return (value + divider - 1.0f) / divider
}
fun round10(value: Float): Int {
return ((value * 10).toInt() + 5) / 10
}
fun round10Up(value: Float): Int {
val intValue = value.toInt()
val rest = value / intValue
if (rest > 0) {
return intValue + 1
}
return intValue
}
}