diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinLivingEntity.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinLivingEntity.java
index 5db01493a69..00a875ce789 100644
--- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinLivingEntity.java
+++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinLivingEntity.java
@@ -28,7 +28,7 @@
import net.ccbluex.liquidbounce.features.module.modules.combat.elytratarget.ModuleElytraTarget;
import net.ccbluex.liquidbounce.features.module.modules.movement.*;
import net.ccbluex.liquidbounce.features.module.modules.render.DoRender;
-import net.ccbluex.liquidbounce.features.module.modules.render.ModuleAnimations;
+import net.ccbluex.liquidbounce.features.module.modules.render.animations.ModuleAnimations;
import net.ccbluex.liquidbounce.features.module.modules.render.ModuleAntiBlind;
import net.ccbluex.liquidbounce.features.module.modules.render.hitfx.ModuleHitFX;
import net.ccbluex.liquidbounce.features.module.modules.world.scaffold.ModuleScaffold;
diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/item/MixinItemInHandRenderer.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/item/MixinItemInHandRenderer.java
index db88fce3fe8..78d5c9c0f84 100644
--- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/item/MixinItemInHandRenderer.java
+++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/item/MixinItemInHandRenderer.java
@@ -25,8 +25,9 @@
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.ccbluex.liquidbounce.features.module.modules.combat.ModuleSwordBlock;
-import net.ccbluex.liquidbounce.features.module.modules.render.ModuleAnimations;
+import net.ccbluex.liquidbounce.features.module.modules.render.animations.ModuleAnimations;
import net.ccbluex.liquidbounce.features.module.modules.render.ModuleSilentHotbar;
+import net.ccbluex.liquidbounce.features.module.modules.render.animations.SwingAnimations;
import net.ccbluex.liquidbounce.utils.client.SilentHotbar;
import net.ccbluex.liquidbounce.utils.item.ItemCategorizationsKt;
import net.ccbluex.liquidbounce.utils.render.FirstPersonShieldTint;
@@ -37,6 +38,7 @@
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.InteractionHand;
+import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
@@ -46,10 +48,7 @@
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.ModifyArg;
-import org.spongepowered.asm.mixin.injection.Slice;
+import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -82,6 +81,34 @@ private void hookFirstPersonShieldTint(
original.call(instance, poseStack, submitNodeCollector, lightCoords, overlayCoords, outlineColor);
}
+ @Inject(
+ method = "swingArm",
+ at = @At("HEAD"),
+ cancellable = true
+ )
+ private void cancelVanillaSwing(
+ float attack,
+ PoseStack poseStack,
+ int invert,
+ HumanoidArm arm,
+ CallbackInfo ci
+ ) {
+ AbstractClientPlayer player = Minecraft.getInstance().player;
+
+ if (player == null || !ModuleAnimations.INSTANCE.getRunning() || !SwingAnimations.INSTANCE.getEnabled() || ModuleSwordBlock.shouldAnimateSwordBlock(player)) {
+ return;
+ }
+
+ SwingAnimations.INSTANCE.onRenderItem(
+ player,
+ InteractionHand.MAIN_HAND,
+ attack,
+ poseStack
+ );
+
+ ci.cancel();
+ }
+
@Inject(method = "submitArmWithItem", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V", shift = At.Shift.AFTER))
private void hookRenderFirstPersonItem(
AbstractClientPlayer player, float frameInterp, float xRot, InteractionHand hand, float attack, ItemStack itemStack, float inverseArmHeight, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) {
@@ -246,7 +273,6 @@ private int hookItemUseItem(int original, @Local(argsOnly = true, name = "player
if (ModuleSwordBlock.shouldAnimateSwordBlock(player)) {
return 7200;
}
-
return original;
}
diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/ModuleManager.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/ModuleManager.kt
index 674df89241b..537bfeb6de0 100644
--- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/ModuleManager.kt
+++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/ModuleManager.kt
@@ -184,7 +184,7 @@ import net.ccbluex.liquidbounce.features.module.modules.player.cheststealer.Modu
import net.ccbluex.liquidbounce.features.module.modules.player.invcleaner.ModuleInventoryCleaner
import net.ccbluex.liquidbounce.features.module.modules.player.nofall.ModuleNoFall
import net.ccbluex.liquidbounce.features.module.modules.player.offhand.ModuleOffhand
-import net.ccbluex.liquidbounce.features.module.modules.render.ModuleAnimations
+import net.ccbluex.liquidbounce.features.module.modules.render.animations.ModuleAnimations
import net.ccbluex.liquidbounce.features.module.modules.render.ModuleAntiBlind
import net.ccbluex.liquidbounce.features.module.modules.render.ModuleAspect
import net.ccbluex.liquidbounce.features.module.modules.render.ModuleAutoF5
diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/ModuleAnimations.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/animations/ModuleAnimations.kt
similarity index 61%
rename from src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/ModuleAnimations.kt
rename to src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/animations/ModuleAnimations.kt
index 046ad5e59d8..fe8013a39ca 100644
--- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/ModuleAnimations.kt
+++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/animations/ModuleAnimations.kt
@@ -16,7 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with LiquidBounce. If not, see .
*/
-package net.ccbluex.liquidbounce.features.module.modules.render
+
+package net.ccbluex.liquidbounce.features.module.modules.render.animations
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.math.Axis
@@ -28,9 +29,10 @@ import net.ccbluex.liquidbounce.event.events.PlayerStrideEvent
import net.ccbluex.liquidbounce.event.handler
import net.ccbluex.liquidbounce.features.module.ClientModule
import net.ccbluex.liquidbounce.features.module.ModuleCategories
-import net.ccbluex.liquidbounce.features.module.modules.combat.ModuleSwordBlock
+import net.ccbluex.liquidbounce.utils.math.toRadians
import net.minecraft.util.Mth
import net.minecraft.world.entity.HumanoidArm
+import org.joml.Quaternionf
/**
* Animations module
@@ -48,6 +50,7 @@ object ModuleAnimations : ClientModule("Animations", ModuleCategories.RENDER, al
tree(MainHand)
tree(OffHand)
tree(EquipOffset)
+ tree(SwingAnimations)
}
object MainHand : ToggleableValueGroup(this, "MainHand", false) {
@@ -75,10 +78,16 @@ object ModuleAnimations : ClientModule("Animations", ModuleCategories.RENDER, al
* of a sword.
* This choice is only used when the [ModuleSwordBlock] module is enabled.
*/
+
+ val swingAnimation = SwingAnimations
val blockAnimationChoice = choices(
"BlockingAnimation", OneSevenAnimation, arrayOf(
OneSevenAnimation,
- PushdownAnimation
+ PushdownAnimation,
+ SigmaAnimation,
+ ExhibitionAnimation,
+ AvatarAnimation,
+ DortwareAnimation
)
)
@@ -116,6 +125,8 @@ object ModuleAnimations : ClientModule("Animations", ModuleCategories.RENDER, al
/**
* A choice that aims to transform the held item transformation during the swing progress.
*/
+
+
abstract class AnimationMode(name: String) : Mode(name) {
override val parent: ModeValueGroup<*>
@@ -176,4 +187,136 @@ object ModuleAnimations : ClientModule("Animations", ModuleCategories.RENDER, al
}
+ object SigmaAnimation : AnimationMode("Sigma") {
+
+ private val translateY by float("Y", 0.1f, 0.05f..0.3f)
+
+ override fun transform(matrices: PoseStack, arm: HumanoidArm, equipProgress: Float, swingProgress: Float) {
+
+ val sine = Mth.sin(Mth.sqrt(swingProgress) * Math.PI)
+ val sideM = if (arm == HumanoidArm.RIGHT) 1.0f else -1.0f
+
+ val rot = Quaternionf().rotationAxis(
+ (-sine * 27.5f * sideM).toRadians(),
+ -8.0f * sideM,
+ 0.0f,
+ 9.0f
+ ).rotateAxis(
+ (-sine * 45.0f * sideM).toRadians(),
+ 1.0f * sideM,
+ sine / 2.0f,
+ 0.0f
+ )
+ matrices.mulPose(rot)
+
+ matrices.translate(0.0f, translateY, 0.0f)
+ applySwingOffset(matrices, arm, 0f)
+ }
+ }
+
+ object ExhibitionAnimation : AnimationMode("Exhibition") {
+
+ private val translateY by float("Y", 0.1f, 0.05f..0.3f)
+
+ override fun transform(matrices: PoseStack, arm: HumanoidArm, equipProgress: Float, swingProgress: Float) {
+
+ val sine = Mth.sin(Mth.sqrt(swingProgress) * Math.PI)
+ val sideM = if (arm == HumanoidArm.RIGHT) 1.0f else -1.0f
+
+ matrices.translate(0.0, -0.1, 0.0)
+
+ applySwingOffset(matrices, arm, 0f)
+
+ matrices.translate(0.1F, 0.4F, -0.1F)
+
+ val rot = Quaternionf().rotationAxis(
+ (-sine * 30.0F * sideM).toRadians(),
+ sine.div(2F),
+ 0.0F,
+ 9.0F
+ ).rotateAxis(
+ (-sine * 50.0F * sideM).toRadians(),
+ 0.8F * sideM,
+ sine.div(2F),
+ 0F
+ )
+ matrices.mulPose(rot)
+
+ matrices.translate(0.0f, translateY - 0.2f, 0.0f)
+
+ }
+
+ }
+
+ object AvatarAnimation : AnimationMode("Avatar") {
+
+ private val translateY by float("Y", 0.1f, 0.05f..0.3f)
+
+ override fun transform(matrices: PoseStack, arm: HumanoidArm, equipProgress: Float, swingProgress: Float) {
+
+ val sine = Mth.sin(Mth.sqrt(swingProgress) * Math.PI)
+ val sine1 = Mth.sin(swingProgress * swingProgress * Math.PI)
+ val sideM = if (arm == HumanoidArm.RIGHT) 1.0f else -1.0f
+
+ matrices.translate(0.2F * sideM, translateY, 0F)
+
+ val rot = Quaternionf().rotationAxis(
+ (0.0F * sideM).toRadians(),
+ 0.0F,
+ 1.0F,
+ 0.0F
+ ).rotateY(
+ (sine1 * -20.0F * sideM).toRadians()
+ ).rotateZ(
+ (sine * -20.0F * sideM).toRadians()
+ ).rotateAxis(
+ (sine * -40.0F * sideM).toRadians(),
+ 1.0F * sideM,
+ 0.0F,
+ 0.0F
+ )
+ matrices.mulPose(rot)
+
+ applySwingOffset(matrices, arm, 0f)
+ }
+ }
+
+ object DortwareAnimation : AnimationMode("Dortware") {
+
+ private val translateY by float("Y", 0.1f, 0.05f..0.3f)
+
+ override fun transform(matrices: PoseStack, arm: HumanoidArm, equipProgress: Float, swingProgress: Float) {
+
+ val sine = Mth.sin(Mth.sqrt(swingProgress) * Math.PI)
+ val sqrtSwing = Mth.sqrt(swingProgress)
+ val altSine = Mth.sin(sqrtSwing * Math.PI - 3)
+
+ val rot = Quaternionf().rotationAxis(
+ (-sine * 10).toRadians(),
+ 0.0f,
+ 15.0f,
+ 200.0f
+ ).rotateAxis(
+ (-sine * 10f).toRadians(),
+ 300.0f,
+ sine.div(2f),
+ 1.0f
+ )
+ matrices.mulPose(rot)
+
+ matrices.translate(3.4, 0.3, -0.4)
+ matrices.translate(-2.10f, -0.2f, 0.1f)
+
+ val rot1 = Quaternionf().rotationAxis(
+ (altSine * 13.0f).toRadians(),
+ -10.0f,
+ -1.4f,
+ -10.0f
+ )
+ matrices.mulPose(rot1)
+
+ matrices.translate(if(arm == HumanoidArm.RIGHT) -1f else -2f, translateY, 0f)
+
+ }
+ }
}
diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/animations/SwingAnimations.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/animations/SwingAnimations.kt
new file mode 100644
index 00000000000..8db4cd4e705
--- /dev/null
+++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/animations/SwingAnimations.kt
@@ -0,0 +1,154 @@
+/*
+ * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
+ *
+ * Copyright (c) 2015 - 2026 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 .
+ */
+
+package net.ccbluex.liquidbounce.features.module.modules.render.animations
+
+import com.mojang.blaze3d.vertex.PoseStack
+import com.mojang.math.Axis
+import net.ccbluex.liquidbounce.config.types.group.ToggleableValueGroup
+import net.ccbluex.liquidbounce.config.types.list.Tagged
+import net.minecraft.client.player.AbstractClientPlayer
+import net.minecraft.util.Mth
+import net.minecraft.world.InteractionHand
+import net.minecraft.world.entity.HumanoidArm
+
+object SwingAnimations : ToggleableValueGroup(ModuleAnimations, "SwingAnimations", false) {
+
+ val mode by enumChoice("Mode", Mode.Spin)
+
+ enum class Mode(override val tag: String) : Tagged {
+ Swipe("Swipe"), Spin("Spin"), Hook("Hook"), Dash("Dash"),
+ Tap("Tap"), Inject("Inject"), Slap("Slap"), Akrien("Akrien"),
+ Smooth("Smooth"), Power("Power"), Feast("Feast")
+ }
+
+ private fun fSin(v: Float) = Mth.sin(v.toDouble())
+ private fun fSqrt(v: Float) = Mth.sqrt(v)
+ private const val PI = Math.PI.toFloat()
+
+ fun onRenderItem(player: AbstractClientPlayer,
+ hand: InteractionHand,
+ swingProgress: Float,
+ poseStack: PoseStack
+ ) {
+ val isMainHand = hand == InteractionHand.MAIN_HAND
+ val arm = if (isMainHand) player.mainArm else player.mainArm.opposite
+
+ applySwing(poseStack, swingProgress, arm)
+ }
+
+ @Suppress("LongMethod")
+ private fun applySwing(poseStack: PoseStack,
+ swing: Float,
+ arm: HumanoidArm
+ ) {
+ val i = if (arm == HumanoidArm.RIGHT) 1 else -1
+ val fSqrt = fSqrt(swing)
+ val g = fSin(fSqrt * PI)
+ val n = -0.4f * g
+ val sin1 = fSin(swing * swing * PI)
+ val sin2 = fSin(fSqrt(swing) * PI)
+ val sinSmooth = (fSin(swing * PI) * 0.5f)
+
+ when (mode) {
+ Mode.Swipe -> {
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * (45.0f + swing * -20.0f)))
+ poseStack.mulPose(Axis.ZP.rotationDegrees(i * g * -70.0f))
+ poseStack.mulPose(Axis.XP.rotationDegrees(-70f))
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * -45.0f))
+ }
+ Mode.Spin -> {
+ poseStack.mulPose(Axis.XP.rotationDegrees(swing * -360f))
+ }
+ Mode.Hook -> {
+ poseStack.mulPose(Axis.XP.rotationDegrees(50f))
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * (-30f * (1f - g) - 30f)))
+ poseStack.mulPose(Axis.ZP.rotationDegrees(i * 110f))
+ }
+ Mode.Dash -> {
+ poseStack.mulPose(Axis.XP.rotationDegrees(50f))
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * (-60f * g - 50f)))
+ poseStack.mulPose(Axis.ZP.rotationDegrees(i * 110f))
+ }
+ Mode.Tap -> {
+ poseStack.mulPose(Axis.XP.rotationDegrees(50f))
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * -60f))
+ poseStack.mulPose(Axis.ZP.rotationDegrees(i * (110f + 20f * g)))
+ }
+ Mode.Inject -> {
+ poseStack.translate(0.0, 0.0, (-g / 4.0))
+ poseStack.mulPose(Axis.XP.rotationDegrees(-120f))
+ }
+ Mode.Slap -> {
+ poseStack.mulPose(Axis.XP.rotationDegrees(-fSin(swing * 3f) * 60f))
+ poseStack.mulPose(Axis.ZP.rotationDegrees(i * -60f * g))
+ }
+ Mode.Akrien -> {
+ if (swing > 0) {
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * 45f))
+ poseStack.mulPose(Axis.XP.rotationDegrees(g * -85.0f))
+ poseStack.translate(i * -0.1, 0.28, 0.2)
+ poseStack.mulPose(Axis.XP.rotationDegrees(-85.0f))
+ } else {
+ val m = 0.2f * fSin(fSqrt * PI * 2f)
+ val f2 = -0.2f * fSin(swing * PI)
+ poseStack.translate(i * n.toDouble(), m.toDouble(), f2.toDouble())
+ applySwingOffset(poseStack, arm, swing)
+ }
+ }
+
+ Mode.Smooth -> {
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * (45.0f + sin1 * -20.0f)))
+ poseStack.mulPose(Axis.ZP.rotationDegrees(i * sin2 * -20.0f))
+ poseStack.mulPose(Axis.XP.rotationDegrees(sin2 * -80.0f))
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * -45.0f))
+ poseStack.translate(0.0, -0.1, 0.0)
+ }
+
+ Mode.Power -> {
+ poseStack.translate((-sinSmooth * sinSmooth * sin1 * i).toDouble(), 0.0, 0.0)
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * 61f))
+ poseStack.mulPose(Axis.ZP.rotationDegrees(sin2))
+ poseStack.mulPose(Axis.YP.rotationDegrees(sin2 * sin1 * -5.0f))
+ poseStack.mulPose(Axis.XP.rotationDegrees(sin2 * sin1 * -30.0f))
+ poseStack.mulPose(Axis.XP.rotationDegrees(-60.0f))
+ poseStack.mulPose(Axis.XP.rotationDegrees(sinSmooth * -60.0f))
+ }
+
+ Mode.Feast -> {
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * 30f))
+ poseStack.mulPose(Axis.YP.rotationDegrees(sin2 * 75.0f * i))
+ poseStack.mulPose(Axis.XP.rotationDegrees(sin2 * -45.0f))
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * 30f))
+ poseStack.mulPose(Axis.XP.rotationDegrees(-80.0f))
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * 35f))
+ }
+ }
+ }
+
+ private fun applySwingOffset(poseStack: PoseStack, arm: HumanoidArm, swing: Float) {
+ val i = if (arm == HumanoidArm.RIGHT) 1 else -1
+ val f1 = fSin(swing * swing * PI)
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * (45.0f + f1 * -20.0f)))
+ val g = fSin(fSqrt(swing) * PI)
+ poseStack.mulPose(Axis.ZP.rotationDegrees(i * g * -20.0f))
+ poseStack.mulPose(Axis.XP.rotationDegrees(g * -80.0f))
+ poseStack.mulPose(Axis.YP.rotationDegrees(i * -45.0f))
+ }
+}