diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarElement.kt index 734835e22..64ee2b2c2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarElement.kt @@ -27,10 +27,10 @@ import java.lang.Integer.max class HotbarElement(hudRenderer: HUDRenderer) : Element(hudRenderer) { private val base = HotbarBaseElement(hudRenderer) + private val experience = HotbarExperienceBarElement(hudRenderer) private val health = HotbarHealthElement(hudRenderer) private val hunger = HotbarHungerElement(hudRenderer) - private val topLeft = RowLayout(hudRenderer, HorizontalAlignments.LEFT, 1) // contains health, armor, etc private val topRight = RowLayout(hudRenderer, HorizontalAlignments.RIGHT, 1) // contains hunger, air @@ -57,12 +57,14 @@ class HotbarElement(hudRenderer: HUDRenderer) : Element(hudRenderer) { silentApply() var maxZ = 0 - val topSize = topLeft.size.max(topRight.size) + val maxSize = topLeft.size.max(topRight.size) - maxZ = max(maxZ, topLeft.render(offset + Vec2i(0, HorizontalAlignments.LEFT.getOffset(topSize.y, topLeft.size.y)), z, consumer)) - maxZ = max(maxZ, topRight.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(size.x, topRight.size.x), VerticalAlignments.BOTTOM.getOffset(topSize.y, topRight.size.y)), z, consumer)) - offset.y += topSize.y + maxZ = max(maxZ, topLeft.render(offset + Vec2i(0, VerticalAlignments.TOP.getOffset(maxSize.y, topLeft.size.y)), z, consumer)) + maxZ = max(maxZ, topRight.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(size.x, topRight.size.x), VerticalAlignments.BOTTOM.getOffset(maxSize.y, topRight.size.y)), z, consumer)) + offset.y += maxSize.y + maxZ = max(maxZ, experience.render(offset + Vec2i(HorizontalAlignments.CENTER.getOffset(maxSize.y, experience.size.y), 0), z, consumer)) + offset.y += experience.size.y maxZ = max(maxZ, base.render(offset, z, consumer)) return maxZ @@ -73,7 +75,7 @@ class HotbarElement(hudRenderer: HUDRenderer) : Element(hudRenderer) { element.onParentChange() } - size = base.size + Vec2i(0, max(topLeft.size.y, topRight.size.y)) + size = base.size + Vec2i(0, max(topLeft.size.y, topRight.size.y)) + Vec2i(0, experience.size.y) } override fun tick() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarExperienceBarElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarExperienceBarElement.kt new file mode 100644 index 000000000..02385abb5 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarExperienceBarElement.kt @@ -0,0 +1,89 @@ +/* + * 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 . + * + * 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.text.TextComponent +import de.bixilon.minosoft.gui.rendering.RenderConstants +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.primitive.ImageElement +import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement +import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer +import de.bixilon.minosoft.gui.rendering.util.VecUtil.lerp +import glm_.vec2.Vec2i + +class HotbarExperienceBarElement(hudRenderer: HUDRenderer) : Element(hudRenderer) { + + /** + * [experience|horse_jump][full|empty] + */ + private val atlasElements = arrayOf( + arrayOf( + hudRenderer.atlasManager["minecraft:empty_experience_bar"]!!, + hudRenderer.atlasManager["minecraft:full_experience_bar"]!!, + ), + arrayOf( + hudRenderer.atlasManager["minecraft:empty_horse_jump_bar"]!!, + hudRenderer.atlasManager["minecraft:full_horse_jump_bar"]!!, + ), + ) + + init { + size = SIZE + cacheUpToDate = false + } + + private var jumping = false + private var barIndex = 0 + private var progress = 0.0f + private var level = 0 + + override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int { + val bars = atlasElements[barIndex] + + ImageElement(hudRenderer, bars[0].texture).render(offset, z, consumer) + + val progressAtlasElement = bars[1] + + val progress = ImageElement(hudRenderer, progressAtlasElement.texture, uvStart = progressAtlasElement.uvStart, uvEnd = lerp(progress, progressAtlasElement.uvStart, progressAtlasElement.uvEnd), size = Vec2i(lerp(progress, 0.0f, progressAtlasElement.size.x.toFloat()).toInt(), SIZE.y)) + + progress.render(offset, z + 1, consumer) + + val text = TextElement(hudRenderer, TextComponent(level).apply { color = RenderConstants.EXPERIENCE_BAR_LEVEL_COLOR }, fontAlignment = HorizontalAlignments.CENTER, true) + + text.render(offset + Vec2i(-5, HorizontalAlignments.CENTER.getOffset(size.y, text.size.y)), z + 2, consumer) + + return 2 + TextElement.LAYERS // background / foreground + text(level) + } + + override fun silentApply() { + val jumping = false // ToDo + + if (!jumping) { + val experienceCondition = hudRenderer.connection.player.experienceCondition + if (this.jumping != jumping || progress != experienceCondition.experienceBarProgress) { + progress = experienceCondition.experienceBarProgress + this.jumping = jumping + this.level = experienceCondition.level + cacheUpToDate = false + } + } + } + + companion object { + private val SIZE = Vec2i(182, 5) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt index 120d15230..994531268 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt @@ -444,6 +444,13 @@ object VecUtil { ) } + fun lerp(delta: Float, start: Vec2, end: Vec2): Vec2 { + return Vec2( + lerp(delta, start.x, end.x), + lerp(delta, start.y, end.y), + ) + } + fun lerp(delta: Double, start: Vec3d, end: Vec3d): Vec3d { when { delta <= 0.0 -> return start diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ExperienceSetS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ExperienceSetS2CP.kt index 1039cdd27..b91e72aeb 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ExperienceSetS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ExperienceSetS2CP.kt @@ -38,7 +38,7 @@ class ExperienceSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { override fun check(connection: PlayConnection) { check(bar in 0.0f..1.0f) { "Bar is invalid!" } - check(level >= 0) { "Level is negative is invalid!" } + check(level >= 0) { "Level is negative!" } check(total >= 0) { "Total experience is negative!" } } diff --git a/src/main/java/de/bixilon/minosoft/util/logging/Log.kt b/src/main/java/de/bixilon/minosoft/util/logging/Log.kt index 205d5f46e..e3a2c61aa 100644 --- a/src/main/java/de/bixilon/minosoft/util/logging/Log.kt +++ b/src/main/java/de/bixilon/minosoft/util/logging/Log.kt @@ -18,8 +18,6 @@ import de.bixilon.minosoft.config.StaticConfiguration import de.bixilon.minosoft.data.text.BaseComponent import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.data.text.TextComponent -import de.bixilon.minosoft.modding.event.events.InternalMessageReceiveEvent -import de.bixilon.minosoft.terminal.CLI import de.bixilon.minosoft.terminal.RunConfiguration import java.io.PrintStream import java.io.PrintWriter @@ -87,8 +85,8 @@ object Log { stream.println(message.ansiColoredMessage) - val cliConnection = CLI.getCurrentConnection() - cliConnection?.fireEvent(InternalMessageReceiveEvent(cliConnection, messageToSend.message)) + // val cliConnection = CLI.getCurrentConnection() + //cliConnection?.fireEvent(InternalMessageReceiveEvent(cliConnection, messageToSend.message)) } catch (exception: Throwable) { SYSTEM_ERR_STREAM.println("Can not send log message $messageToSend!") } diff --git a/src/main/resources/assets/minosoft/mapping/atlas.json b/src/main/resources/assets/minosoft/mapping/atlas.json index 5889bd4c6..016b3aa0c 100644 --- a/src/main/resources/assets/minosoft/mapping/atlas.json +++ b/src/main/resources/assets/minosoft/mapping/atlas.json @@ -407,5 +407,33 @@ "start": [97, 27], "end": [106, 36] } + }, + "minecraft:empty_experience_bar": { + "0": { + "texture": "minecraft:textures/gui/icons.png", + "start": [0, 64], + "end": [182, 69] + } + }, + "minecraft:full_experience_bar": { + "0": { + "texture": "minecraft:textures/gui/icons.png", + "start": [0, 69], + "end": [182, 74] + } + }, + "minecraft:empty_horse_jump_bar": { + "0": { + "texture": "minecraft:textures/gui/icons.png", + "start": [0, 84], + "end": [182, 89] + } + }, + "minecraft:full_horse_jump_bar": { + "0": { + "texture": "minecraft:textures/gui/icons.png", + "start": [0, 89], + "end": [182, 94] + } } }