Skip to content

Commit

Permalink
feat(Nametags): durability and stack count (CCBlueX#5102)
Browse files Browse the repository at this point in the history
  • Loading branch information
ccetl authored and commandblock2 committed Dec 31, 2024
1 parent ce57749 commit 33dbd02
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
package net.ccbluex.liquidbounce.features.module.modules.render.nametags

import net.ccbluex.liquidbounce.config.types.Configurable
import net.ccbluex.liquidbounce.event.events.GameTickEvent
import net.ccbluex.liquidbounce.event.events.OverlayRenderEvent
import net.ccbluex.liquidbounce.event.events.WorldChangeEvent
import net.ccbluex.liquidbounce.event.handler
import net.ccbluex.liquidbounce.features.module.Category
import net.ccbluex.liquidbounce.features.module.ClientModule
Expand All @@ -29,17 +31,16 @@ import net.ccbluex.liquidbounce.render.RenderEnvironment
import net.ccbluex.liquidbounce.render.engine.Vec3
import net.ccbluex.liquidbounce.render.renderEnvironmentForGUI
import net.ccbluex.liquidbounce.utils.combat.shouldBeShown
import net.ccbluex.liquidbounce.utils.entity.interpolateCurrentPosition
import net.ccbluex.liquidbounce.utils.kotlin.EventPriorityConvention
import net.ccbluex.liquidbounce.utils.render.WorldToScreen
import net.ccbluex.liquidbounce.utils.math.sq
import net.minecraft.entity.Entity
import kotlin.math.abs

/**
* Nametags module
*
* Makes player name tags more visible and adds useful information.
*/

object ModuleNametags : ClientModule("Nametags", Category.RENDER) {

/**
Expand All @@ -50,19 +51,40 @@ object ModuleNametags : ClientModule("Nametags", Category.RENDER) {
val distance by boolean("Distance", true)
val ping by boolean("Ping", true)
val items by boolean("Items", true)
val itemInfo by boolean("ItemInfo", true)
}

init {
tree(ShowOptions)
}

val background by boolean("Background", true)
val border by boolean("Border", true)
val scale by float("Scale", 2F, 0.25F..4F)
private val maximumDistance by float("MaximumDistance", 100F, 1F..256F)
private var nametagsToRender: List<Nametag>? = null

val fontRenderer
get() = FontManager.FONT_RENDERER

@Suppress("unused")
val updateHandler = handler<GameTickEvent> {
nametagsToRender = collectAndSortNametagsToRender()
}

@Suppress("unused")
val worldChangeHandler = handler<WorldChangeEvent> {
nametagsToRender = null
}

override fun disable() {
nametagsToRender = null
}

override fun enable() {
nametagsToRender = null
}

@Suppress("unused")
val overlayRenderHandler = handler<OverlayRenderEvent>(priority = EventPriorityConvention.FIRST_PRIORITY) { event ->
renderEnvironmentForGUI {
Expand All @@ -77,39 +99,39 @@ object ModuleNametags : ClientModule("Nametags", Category.RENDER) {
}

private fun RenderEnvironment.drawNametags(nametagRenderer: NametagRenderer, tickDelta: Float) {
val nametagsToRender = collectAndSortNametagsToRender(tickDelta)
val nametagsToRender = nametagsToRender ?: return
nametagsToRender.forEach { it.calculatePosition(tickDelta) }
val filteredNameTags = nametagsToRender.filter { it.position != null }
val nametagsCount = filteredNameTags.size.toFloat()

filteredNameTags.forEachIndexed { index, nametagInfo ->
val pos = nametagInfo.position!!

nametagsToRender.forEachIndexed { index, (pos, nametagInfo) ->
// We want nametags that are closer to the player to be rendered above nametags that are further away.
val renderZ = index / nametagsToRender.size.toFloat() * 1000.0F
val renderZ = index / nametagsCount * 1000.0F

nametagRenderer.drawNametag(this, nametagInfo, Vec3(pos.x, pos.y, renderZ))
}
}

/**
* Collects all entities that should be rendered, gets the screen position, where the name tag should be displayed,
* add what should be rendered ([NametagInfo]). The nametags are sorted in order of rendering.
* add what should be rendered ([Nametag]). The nametags are sorted in order of rendering.
*/
private fun collectAndSortNametagsToRender(tickDelta: Float): List<Pair<Vec3, NametagInfo>> {
val nametagsToRender = mutableListOf<Pair<Vec3, NametagInfo>>()
private fun collectAndSortNametagsToRender(): List<Nametag> {
val nametagsToRender = mutableListOf<Nametag>()

val maximumDistanceSquared = maximumDistance * maximumDistance
val maximumDistanceSquared = maximumDistance.sq()

for (entity in ModuleESP.findRenderedEntities()) {
if (entity.squaredDistanceTo(mc.cameraEntity) > maximumDistanceSquared) continue

val nametagPos = entity.interpolateCurrentPosition(tickDelta)
.add(0.0, entity.getEyeHeight(entity.pose) + 0.55, 0.0)

val screenPos = WorldToScreen.calculateScreenPos(nametagPos) ?: continue

val nametagInfo = NametagInfo.createForEntity(entity)
if (entity.squaredDistanceTo(mc.cameraEntity) > maximumDistanceSquared) {
continue
}

nametagsToRender.add(Pair(screenPos, nametagInfo))
nametagsToRender += Nametag(entity)
}

nametagsToRender.sortByDescending { it.first.z }
nametagsToRender.sortByDescending { abs(it.entity.z - player.pos.z) }

return nametagsToRender
}
Expand All @@ -119,4 +141,5 @@ object ModuleNametags : ClientModule("Nametags", Category.RENDER) {
*/
@JvmStatic
fun shouldRenderNametag(entity: Entity) = entity.shouldBeShown()

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,39 @@
*/
package net.ccbluex.liquidbounce.features.module.modules.render.nametags

import net.ccbluex.liquidbounce.utils.item.isNothing
import net.ccbluex.liquidbounce.render.engine.Vec3
import net.ccbluex.liquidbounce.utils.entity.interpolateCurrentPosition
import net.ccbluex.liquidbounce.utils.render.WorldToScreen
import net.minecraft.entity.Entity
import net.minecraft.entity.LivingEntity
import net.minecraft.item.ItemStack
import net.minecraft.text.Text

data class NametagInfo(
@Suppress("DataClassPrivateConstructor")
data class Nametag private constructor(
val entity: Entity,
/**
* The text to render as nametag
*/
val text: Text,
/**
* The items that should be rendered above the name tag
*/
val items: List<ItemStack?>,
val items: List<ItemStack?>
) {
companion object {
fun createForEntity(entity: Entity): NametagInfo {
val text = NametagTextFormatter(entity).format()
val items = createItemList(entity)

return NametagInfo(text, items)
}
var position: Vec3? = null

constructor(entity: Entity) : this(entity, NametagTextFormatter(entity).format(), createItemList(entity))

fun calculatePosition(tickDelta: Float) {
val nametagPos = entity.interpolateCurrentPosition(tickDelta)
.add(0.0, entity.getEyeHeight(entity.pose) + 0.55, 0.0)

position = WorldToScreen.calculateScreenPos(nametagPos)
}

companion object {

/**
* Creates a list of items that should be rendered above the name tag. Currently, it is the item in main hand,
Expand All @@ -56,16 +66,12 @@ data class NametagInfo(
val firstHandItem = itemIterator.next()
val secondHandItem = itemIterator.next()

val armorItems = entity.armorItems

val heldItems =
if (secondHandItem.isNothing()) {
listOf(firstHandItem)
} else {
listOf(firstHandItem, secondHandItem)
}
val armorItems = entity.armorItems.reversed()

return heldItems + armorItems
return listOf(firstHandItem) + armorItems + secondHandItem
}

}

}

Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ private const val ITEM_SIZE: Int = 20
private const val ITEM_SCALE: Float = 1.0F

class NametagRenderer {

private val quadBuffers =
RenderBufferBuilder(
VertexFormat.DrawMode.QUADS,
Expand All @@ -49,35 +50,31 @@ class NametagRenderer {

private val fontBuffers = FontRendererBuffers()

fun drawNametag(
env: RenderEnvironment,
info: NametagInfo,
pos: Vec3,
) = with(env) {
val c = FontManager.DEFAULT_FONT_SIZE
fun drawNametag(env: RenderEnvironment, nametag: Nametag, pos: Vec3) = with(env) {
val fontSize = FontManager.DEFAULT_FONT_SIZE

val scale = 1.0F / (c * 0.15F) * ModuleNametags.scale
val scale = 1f / (fontSize * 0.15f) * ModuleNametags.scale

matrixStack.push()
matrixStack.translate(pos.x, pos.y, pos.z)
matrixStack.scale(scale, scale, 1.0F)
matrixStack.scale(scale, scale, 1f)

val x =
ModuleNametags.fontRenderer.draw(
ModuleNametags.fontRenderer.process(info.text),
0.0F,
0.0F,
ModuleNametags.fontRenderer.process(nametag.text),
0f,
0f,
shadow = true,
z = 0.001F,
z = 0.001f,
)

// Make the model view matrix center the text when rendering
matrixStack.translate(-x * 0.5F, -ModuleNametags.fontRenderer.height * 0.5F, 0.00F)
matrixStack.translate(-x * 0.5f, -ModuleNametags.fontRenderer.height * 0.5f, 0f)

ModuleNametags.fontRenderer.commit(env, fontBuffers)

val q1 = Vec3(-0.1F * c, ModuleNametags.fontRenderer.height * -0.1F, 0.0F)
val q2 = Vec3(x + 0.2F * c, ModuleNametags.fontRenderer.height * 1.1F, 0.0F)
val q1 = Vec3(-0.1f * fontSize, ModuleNametags.fontRenderer.height * -0.1f, 0f)
val q2 = Vec3(x + 0.2f * fontSize, ModuleNametags.fontRenderer.height * 1.1f, 0f)

quadBuffers.drawQuad(env, q1, q2)

Expand All @@ -86,16 +83,13 @@ class NametagRenderer {
}

if (ModuleNametags.ShowOptions.items) {
drawItemList(pos, info.items)
drawItemList(pos, nametag.items)
}

matrixStack.pop()
}

private fun drawItemList(
pos: Vec3,
itemsToRender: List<ItemStack?>,
) {
private fun drawItemList(pos: Vec3, itemsToRender: List<ItemStack?>) {
val dc = DrawContext(mc, mc.bufferBuilders.entityVertexConsumers)

dc.matrices.translate(pos.x, pos.y - NAMETAG_PADDING, pos.z)
Expand All @@ -112,8 +106,15 @@ class NametagRenderer {

dc.matrices.translate(0.0F, 0.0F, 100.0F)

val itemInfo = ModuleNametags.ShowOptions.itemInfo
itemsToRender.forEachIndexed { index, itemStack ->
dc.drawItem(itemStack, index * ITEM_SIZE, 0)
itemStack ?: return@forEachIndexed

val x = index * ITEM_SIZE
dc.drawItem(itemStack, x, 0)
if (itemInfo) {
dc.drawStackOverlay(mc.textRenderer, itemStack, x, 0)
}
}
}

Expand All @@ -139,4 +140,5 @@ class NametagRenderer {
fontBuffers.draw()
}
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
* This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
*
* Copyright (c) 2015 - 2024 CCBlueX
*
* LiquidBounce 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.
*
* LiquidBounce 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 LiquidBounce. If not, see <https://www.gnu.org/licenses/>.
*/
package net.ccbluex.liquidbounce.utils.render

import net.ccbluex.liquidbounce.event.events.WorldRenderEvent
Expand Down

0 comments on commit 33dbd02

Please sign in to comment.