Skip to content

Commit 7e909ca

Browse files
feat(Hats): image mode (#7582)
1 parent 1bad4da commit 7e909ca

File tree

9 files changed

+110
-27
lines changed

9 files changed

+110
-27
lines changed

src/main/kotlin/net/ccbluex/liquidbounce/config/types/ValueUtils.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.filter
2626
import kotlinx.coroutines.launch
2727
import kotlinx.coroutines.withContext
2828
import net.ccbluex.liquidbounce.api.core.ioScope
29-
import net.ccbluex.liquidbounce.config.types.nesting.ToggleableConfigurable
29+
import net.ccbluex.liquidbounce.event.EventListener
3030
import net.ccbluex.liquidbounce.utils.client.asPlainText
3131
import net.ccbluex.liquidbounce.utils.client.chat
3232
import net.ccbluex.liquidbounce.utils.client.inGame
@@ -47,10 +47,10 @@ import kotlin.time.Duration.Companion.seconds
4747
/**
4848
* Convert the [FileValue] to a [ReadOnlyProperty] of [DynamicTexture].
4949
*/
50-
fun FileValue.toTextureProperty(
51-
owner: ToggleableConfigurable,
50+
fun <V> FileValue.toTextureProperty(
51+
owner: V,
5252
printErrorToChat: Boolean = true,
53-
): ReadOnlyProperty<Any?, DynamicTexture?> {
53+
): ReadOnlyProperty<Any?, DynamicTexture?> where V : EventListener, V : Value<*> {
5454
var texture: DynamicTexture? = null
5555
ioScope.launch {
5656
asStateFlow().filter { it.isFile }.collectLatest { file ->

src/main/kotlin/net/ccbluex/liquidbounce/config/types/nesting/Configurable.kt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import com.google.gson.JsonArray
2222
import com.google.gson.JsonNull
2323
import com.google.gson.JsonObject
2424
import com.google.gson.JsonPrimitive
25+
import com.mojang.blaze3d.platform.InputConstants
26+
import net.ccbluex.fastutil.enumSetOf
27+
import net.ccbluex.fastutil.toEnumSet
2528
import net.ccbluex.liquidbounce.config.types.BindValue
2629
import net.ccbluex.liquidbounce.config.types.ChooseListValue
2730
import net.ccbluex.liquidbounce.config.types.CurveValue
@@ -40,25 +43,24 @@ import net.ccbluex.liquidbounce.config.types.Value
4043
import net.ccbluex.liquidbounce.config.types.ValueType
4144
import net.ccbluex.liquidbounce.event.EventListener
4245
import net.ccbluex.liquidbounce.render.engine.type.Color4b
46+
import net.ccbluex.liquidbounce.utils.client.logger
4347
import net.ccbluex.liquidbounce.utils.client.toLowerCamelCase
4448
import net.ccbluex.liquidbounce.utils.input.InputBind
4549
import net.ccbluex.liquidbounce.utils.math.Easing
46-
import net.minecraft.world.level.block.Block
47-
import com.mojang.blaze3d.platform.InputConstants
48-
import net.ccbluex.fastutil.enumSetOf
49-
import net.ccbluex.fastutil.toEnumSet
50-
import net.ccbluex.liquidbounce.utils.client.logger
51-
import net.minecraft.world.entity.EntityType
50+
import net.minecraft.core.Vec3i
51+
import net.minecraft.resources.Identifier
52+
import net.minecraft.sounds.SoundEvent
5253
import net.minecraft.world.effect.MobEffect
54+
import net.minecraft.world.entity.EntityType
5355
import net.minecraft.world.item.Item
54-
import net.minecraft.sounds.SoundEvent
55-
import net.minecraft.resources.Identifier
56+
import net.minecraft.world.level.block.Block
5657
import net.minecraft.world.phys.Vec3
57-
import net.minecraft.core.Vec3i
5858
import org.joml.Vector2f
59+
import org.joml.Vector2fc
5960
import org.lwjgl.glfw.GLFW
6061
import java.io.File
61-
import java.util.*
62+
import java.util.EnumSet
63+
import java.util.SequencedSet
6264
import java.util.function.ToIntFunction
6365

6466
@Suppress("TooManyFunctions")
@@ -352,6 +354,8 @@ open class Configurable(
352354

353355
fun block(name: String, default: Block) = value(name, default, ValueType.BLOCK)
354356

357+
fun vec2f(name: String, default: Vector2fc) = value(name, default, ValueType.VECTOR2_F)
358+
355359
fun vec3i(name: String, default: Vec3i) = value(name, default, ValueType.VECTOR3_I)
356360

357361
fun vec3d(name: String, default: Vec3) = value(name, default, ValueType.VECTOR3_D)

src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/hats/HatsMode.kt

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,19 @@ import net.ccbluex.liquidbounce.features.module.modules.render.hats.ModuleHats.m
3030
import net.ccbluex.liquidbounce.render.WorldRenderEnvironment
3131
import net.ccbluex.liquidbounce.render.renderEnvironmentForWorld
3232
import net.ccbluex.liquidbounce.render.withPositionRelativeToCamera
33+
import net.ccbluex.liquidbounce.render.withPush
3334
import net.ccbluex.liquidbounce.utils.entity.interpolateCurrentPosition
35+
import net.ccbluex.liquidbounce.utils.entity.interpolateCurrentRotation
3436
import net.minecraft.util.Mth
3537
import net.minecraft.world.entity.EquipmentSlot
38+
import org.joml.Quaternionf
3639
import org.joml.Vector2f
3740
import org.joml.Vector3f
3841
import kotlin.math.cos
3942
import kotlin.math.sin
4043

44+
private val ROTATION = Quaternionf()
45+
4146
/**
4247
* @author minecrrrr
4348
*/
@@ -46,7 +51,9 @@ abstract class HatsMode(name: String) : Choice(name) {
4651
get() = modes
4752

4853
// --- Settings ---
49-
protected val height by float("HeightOffset", 0.1f, 0f..2f)
54+
private val followRotation by boolean("FollowRotation", false)
55+
56+
protected val height by float("HeightOffset", 0.2f, 0f..2f)
5057

5158
protected object EquipOffset : Configurable("EquipmentOffset") {
5259
val equipmentOffset by float("ArmorOffset", 0.1f, 0f..1f)
@@ -70,7 +77,6 @@ abstract class HatsMode(name: String) : Choice(name) {
7077

7178
@Suppress("unused")
7279
private val renderHandler = handler<WorldRenderEvent> {
73-
val world = net.ccbluex.liquidbounce.utils.client.world
7480
val player = mc.player ?: return@handler
7581

7682
for (entity in world.players()) {
@@ -85,19 +91,23 @@ abstract class HatsMode(name: String) : Choice(name) {
8591
}
8692

8793
if (shouldRender) {
88-
8994
val hurtMarked = entity.hurtTime > 0 && hurtMarked
9095
val pos = entity.interpolateCurrentPosition(it.partialTicks)
96+
val rotation = entity.interpolateCurrentRotation(it.partialTicks)
9197

9298
val equipOffset = if (!entity.getItemBySlot(EquipmentSlot.HEAD).isEmpty) {
93-
EquipOffset.equipmentOffset.toDouble()
99+
EquipOffset.equipmentOffset
94100
} else {
95-
0.0
101+
0.0F
96102
}
97103

98104
renderEnvironmentForWorld(it.matrixStack) {
99-
withPositionRelativeToCamera(pos.add(0.0, entity.bbHeight + height.toDouble() + equipOffset, 0.0)) {
100-
drawHat(hurtMarked)
105+
withPositionRelativeToCamera(pos.add(0.0, entity.eyeHeight.toDouble(), 0.0)) {
106+
matrixStack.withPush {
107+
if (followRotation) mulPose(rotation.toQuaternion(ROTATION))
108+
translate(0F, entity.bbHeight - entity.eyeHeight + height + equipOffset, 0F)
109+
drawHat(hurtMarked)
110+
}
101111
}
102112
}
103113
}

src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/hats/ModuleHats.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import net.ccbluex.liquidbounce.features.module.ClientModule
2424
import net.ccbluex.liquidbounce.features.module.modules.render.hats.modes.HatsCone
2525
import net.ccbluex.liquidbounce.features.module.modules.render.hats.modes.HatsFlower
2626
import net.ccbluex.liquidbounce.features.module.modules.render.hats.modes.HatsHalo
27+
import net.ccbluex.liquidbounce.features.module.modules.render.hats.modes.HatsImage
2728
import net.ccbluex.liquidbounce.features.module.modules.render.hats.modes.HatsOrbs
2829
import net.ccbluex.liquidbounce.features.module.modules.render.hats.modes.HatsStar
2930

@@ -32,14 +33,15 @@ import net.ccbluex.liquidbounce.features.module.modules.render.hats.modes.HatsSt
3233
*/
3334
object ModuleHats : ClientModule("Hats", Category.RENDER) {
3435

35-
val modes = choices(
36-
"Mode", HatsCone, arrayOf(
36+
val modes = choices("Mode", 0) {
37+
arrayOf(
3738
HatsCone,
3839
HatsHalo,
3940
HatsOrbs,
4041
HatsFlower,
4142
HatsStar,
43+
HatsImage,
4244
)
43-
).apply { tagBy(this) }
45+
}.apply { tagBy(this) }
4446

4547
}

src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/hats/modes/HatsFlower.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ internal object HatsFlower : HatsMode("Flower") {
4343
val innerRadius by float("Thickness", 0.05f, 0.01f..1f)
4444
val sharpness by float("Sharpness", 0.6f, 0.1f..0.9f)
4545
val petalCount by int("PetalCount", 5, 5..15)
46-
val spinSpeed by float("SpinSpeed", 1f, 0f..10f)
46+
val spinSpeed by float("SpinSpeed", 1f, -10f..10f)
4747
}
4848

4949
init {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
3+
*
4+
* Copyright (c) 2015 - 2026 CCBlueX
5+
*
6+
* LiquidBounce is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* LiquidBounce is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with LiquidBounce. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
package net.ccbluex.liquidbounce.features.module.modules.render.hats.modes
21+
22+
import net.ccbluex.liquidbounce.config.types.toTextureProperty
23+
import net.ccbluex.liquidbounce.features.module.modules.render.hats.HatsMode
24+
import net.ccbluex.liquidbounce.render.WorldRenderEnvironment
25+
import net.ccbluex.liquidbounce.render.drawCustomMeshTextured
26+
import net.ccbluex.liquidbounce.render.engine.type.Color4b
27+
import net.ccbluex.liquidbounce.render.withPush
28+
import net.minecraft.util.Mth
29+
import org.joml.Quaternionf
30+
import org.joml.Vector2f
31+
32+
internal object HatsImage : HatsMode("Image") {
33+
34+
private val image by file("Image").toTextureProperty(this, printErrorToChat = true)
35+
private val colorModulator by color("ColorModulator", Color4b.WHITE)
36+
private val scale by vec2f("Scale", Vector2f(1f, 1f))
37+
private val spinSpeed by float("SpinSpeed", 1f, -10f..10f)
38+
39+
private val ROTATION = Quaternionf()
40+
41+
override fun WorldRenderEnvironment.drawHat(isHurt: Boolean) {
42+
val texture = image ?: return
43+
44+
matrixStack.withPush {
45+
mulPose(
46+
ROTATION.scaling(1f)
47+
.rotateX(Mth.HALF_PI)
48+
.rotateZ(getRotationAngle(spinSpeed))
49+
)
50+
scale(scale.x(), scale.y(), 1f)
51+
52+
drawCustomMeshTextured(texture) { pose ->
53+
val color = colorModulator.argb
54+
addVertex(pose, -0.5f, -0.5f, 0f).setUv(0f, 0f).setColor(color)
55+
addVertex(pose, -0.5f, 0.5f, 0f).setUv(0f, 1f).setColor(color)
56+
addVertex(pose, 0.5f, 0.5f, 0f).setUv(1f, 1f).setColor(color)
57+
addVertex(pose, 0.5f, -0.5f, 0f).setUv(1f, 0f).setColor(color)
58+
}
59+
}
60+
}
61+
}

src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/hats/modes/HatsOrbs.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ internal object HatsOrbs : HatsMode("Orbs") {
5050
val waveSpeed by float("WaveSpeed", 2.0f, 0.1f..10f)
5151
}
5252

53-
val spinSpeed by float("SpinSpeed", 2f, 0f..10f)
53+
val spinSpeed by float("SpinSpeed", 2f, -10f..10f)
5454
}
5555

5656
init {

src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/hats/modes/HatsStar.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ internal object HatsStar : HatsMode("Star") {
4444
val innerRadius by float("Thickness", 0.05f, 0.01f..1f)
4545
val sharpness by float("Sharpness", 0.6f, 0.1f..0.7f)
4646
val pointsCount by int("PointsCount", 5, 5..15)
47-
val spinSpeed by float("SpinSpeed", 1f, 0f..10f)
47+
val spinSpeed by float("SpinSpeed", 1f, -10f..10f)
4848
}
4949

5050
init {

src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/data/Rotation.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ import net.ccbluex.liquidbounce.utils.aiming.utils.RotationUtil
2323
import net.ccbluex.liquidbounce.utils.aiming.utils.RotationUtil.angleDifference
2424
import net.ccbluex.liquidbounce.utils.client.player
2525
import net.ccbluex.liquidbounce.utils.client.toDegrees
26+
import net.ccbluex.liquidbounce.utils.client.toRadians
2627
import net.ccbluex.liquidbounce.utils.entity.rotation
2728
import net.minecraft.util.Mth
2829
import net.minecraft.world.phys.Vec3
30+
import org.joml.Quaternionf
2931
import kotlin.math.abs
3032
import kotlin.math.atan2
3133
import kotlin.math.hypot
@@ -66,6 +68,10 @@ data class Rotation @JvmOverloads constructor(
6668
val xRot: Float get() = pitch
6769
val yRot: Float get() = yaw
6870

71+
@JvmOverloads
72+
fun toQuaternion(dest: Quaternionf = Quaternionf()): Quaternionf =
73+
dest.rotationYXZ(Mth.PI - yRot.toRadians(), -xRot.toRadians(), 0f)
74+
6975
/**
7076
* Fixes GCD and Modulo 360° at yaw
7177
*

0 commit comments

Comments
 (0)