From 7930b71121497a6a9d5d8dc9c019cbe989b6eb0e Mon Sep 17 00:00:00 2001 From: beanbag44 Date: Sun, 28 Sep 2025 11:51:38 +0100 Subject: [PATCH 1/4] zoom module --- .../com/lambda/mixin/input/MouseMixin.java | 17 +++ .../mixin/render/GameRendererMixin.java | 7 ++ src/main/kotlin/com/lambda/module/Module.kt | 12 +- .../com/lambda/module/modules/render/Zoom.kt | 107 ++++++++++++++++++ 4 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 src/main/kotlin/com/lambda/module/modules/render/Zoom.kt diff --git a/src/main/java/com/lambda/mixin/input/MouseMixin.java b/src/main/java/com/lambda/mixin/input/MouseMixin.java index b6b1df9b2..9802da2de 100644 --- a/src/main/java/com/lambda/mixin/input/MouseMixin.java +++ b/src/main/java/com/lambda/mixin/input/MouseMixin.java @@ -19,12 +19,16 @@ import com.lambda.event.EventFlow; import com.lambda.event.events.MouseEvent; +import com.lambda.module.modules.render.Zoom; import com.lambda.util.math.Vec2d; import net.minecraft.client.Mouse; +import net.minecraft.client.option.GameOptions; +import net.minecraft.client.option.SimpleOption; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Mouse.class) @@ -61,4 +65,17 @@ private void onCursorPos(long window, double x, double y, CallbackInfo ci) { ci.cancel(); } } + + @Redirect(method = "updateMouse", at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/GameOptions;smoothCameraEnabled:Z")) + private boolean redirectSmoothCameraEnabled(GameOptions instance) { + if (Zoom.INSTANCE.isEnabled() && Zoom.getSmoothMovement()) return true; + else return instance.smoothCameraEnabled; + } + + @SuppressWarnings("rawtypes") + @Redirect(method = "updateMouse", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/SimpleOption;getValue()Ljava/lang/Object;", ordinal = 0)) + private Object redirectGetValue(SimpleOption instance) { + if (Zoom.INSTANCE.isEnabled()) return ((Double) instance.getValue()) / Zoom.getTargetZoom(); + else return instance.getValue(); + } } diff --git a/src/main/java/com/lambda/mixin/render/GameRendererMixin.java b/src/main/java/com/lambda/mixin/render/GameRendererMixin.java index 48afd23af..8cf2205da 100644 --- a/src/main/java/com/lambda/mixin/render/GameRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/GameRendererMixin.java @@ -21,7 +21,9 @@ import com.lambda.event.events.RenderEvent; import com.lambda.graphics.RenderMain; import com.lambda.module.modules.render.NoRender; +import com.lambda.module.modules.render.Zoom; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import net.minecraft.client.render.Camera; @@ -73,4 +75,9 @@ private float modifyMax(float original) { private void injectShowFloatingItem(ItemStack floatingItem, CallbackInfo ci) { if (NoRender.INSTANCE.isEnabled() && NoRender.getNoFloatingItemAnimation()) ci.cancel(); } + + @ModifyReturnValue(method = "getFov", at = @At("RETURN")) + private float modifyGetFov(float original) { + return original / Zoom.getCurrentZoom(); + } } diff --git a/src/main/kotlin/com/lambda/module/Module.kt b/src/main/kotlin/com/lambda/module/Module.kt index fe69536df..73e01f6be 100644 --- a/src/main/kotlin/com/lambda/module/Module.kt +++ b/src/main/kotlin/com/lambda/module/Module.kt @@ -17,6 +17,7 @@ package com.lambda.module +import com.lambda.Lambda import com.lambda.command.LambdaCommand import com.lambda.config.AbstractSetting import com.lambda.config.Configurable @@ -112,7 +113,8 @@ abstract class Module( private val alwaysListening: Boolean = false, enabledByDefault: Boolean = false, defaultKeybind: KeyCode = KeyCode.UNBOUND, - autoDisable: Boolean = false + autoDisable: Boolean = false, + open val disableOnRelease: Boolean = false ) : Nameable, Muteable, Configurable(ModuleConfig) { private val isEnabledSetting = setting("Enabled", enabledByDefault) { false } val keybindSetting = setting("Keybind", defaultKeybind) { false } @@ -129,13 +131,13 @@ abstract class Module( init { listen(alwaysListen = true) { event -> - if (mc.options.commandKey.isPressed) return@listen - if (!event.isPressed) return@listen + if (Lambda.mc.options.commandKey.isPressed) return@listen if (keybind == KeyCode.UNBOUND) return@listen if (event.translated != keybind) return@listen - if (mc.currentScreen != null) return@listen + if (Lambda.mc.currentScreen != null) return@listen - toggle() + if (event.isPressed) toggle() + else if (event.isReleased && disableOnRelease) disable() } onEnable { LambdaSound.MODULE_ON.play() } diff --git a/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt new file mode 100644 index 000000000..47b0e48ac --- /dev/null +++ b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2025 Lambda + * + * 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 . + */ + +package com.lambda.module.modules.render + +import com.lambda.event.events.MouseEvent +import com.lambda.event.events.RenderEvent +import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag +import java.lang.Math.clamp + +object Zoom : Module( + "Zoom", + "Zooms the current view", + ModuleTag.RENDER +) { + override val disableOnRelease by setting("Disable On Release", true) + private var zoom by setting("Zoom", 2f, 1f..10f, 0.1f) + private val style by setting("Style", ZoomStyle.EaseOut) + private val animationDuration by setting("Animation Duration", 1f, 0.1f..10f, 0.1f) { style != ZoomStyle.Instant } + private val scroll by setting("Scroll", true) + private val persistentScroll by setting("Persistent Scroll", false) { scroll } + private val sensitivity by setting("Sensitivity", 0.4f, 0.1f..1f, 0.1f) { scroll } + @JvmStatic val smoothMovement by setting("Smooth Movement", false) + + private var extraZoom = 0f + set(value) { + field = value.coerceAtLeast(-zoom + 1) + } + @JvmStatic val targetZoom: Float + get() = zoom + extraZoom + + @JvmStatic var currentZoom = 1f; private set + private var lastZoomTime = 1L + private val zoomProgress + get() = + clamp((System.currentTimeMillis() - lastZoomTime) / (animationDuration * 1000).toDouble(), 0.0, 1.0).toFloat() + + init { + listen { event -> + val yDelta = event.delta.y.toFloat() + val delta = (yDelta * sensitivity) + (((zoom + extraZoom) * sensitivity) * yDelta) + if (persistentScroll) zoom += delta + else extraZoom += delta + updateZoomTime() + event.cancel() + } + + listen(alwaysListen = true) { + updateCurrentZoom() + } + + onEnable { + updateZoomTime() + } + onDisable { + extraZoom = 0f + updateZoomTime() + } + } + + private fun updateZoomTime() { + lastZoomTime = System.currentTimeMillis() + } + + @JvmStatic + fun updateCurrentZoom() { + val target = if (isEnabled) targetZoom else 1f + if (currentZoom == target) return + currentZoom = when (style) { + ZoomStyle.Instant -> target + ZoomStyle.EaseOut -> easeOut(currentZoom, target, zoomProgress) + ZoomStyle.EaseIn -> easeIn(currentZoom, target, zoomProgress) + } + } + + private fun easeOut(start: Float, end: Float, progress: Float): Float { + val easedT = 1f - (1f - progress) * (1f - progress) + return start + ((end - start) * easedT) + } + + private fun easeIn(start: Float, end: Float, progress: Float): Float { + val easedT = progress * progress + return start + ((end - start) * easedT) + } + + private enum class ZoomStyle { + Instant, + EaseOut, + EaseIn + } +} \ No newline at end of file From 817acbddf995311d834bbed6cd2f629a3365ef06 Mon Sep 17 00:00:00 2001 From: beanbag44 Date: Sun, 28 Sep 2025 11:54:12 +0100 Subject: [PATCH 2/4] default sensitivity to 2 --- src/main/kotlin/com/lambda/module/modules/render/Zoom.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt index 47b0e48ac..19c64c299 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt @@ -35,7 +35,7 @@ object Zoom : Module( private val animationDuration by setting("Animation Duration", 1f, 0.1f..10f, 0.1f) { style != ZoomStyle.Instant } private val scroll by setting("Scroll", true) private val persistentScroll by setting("Persistent Scroll", false) { scroll } - private val sensitivity by setting("Sensitivity", 0.4f, 0.1f..1f, 0.1f) { scroll } + private val sensitivity by setting("Sensitivity", 0.2f, 0.1f..1f, 0.1f) { scroll } @JvmStatic val smoothMovement by setting("Smooth Movement", false) private var extraZoom = 0f From 49b10bbac5b1a0e465ba578355328cdcb4ff384b Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:40:58 -0400 Subject: [PATCH 3/4] Nit and enum lambda --- .../com/lambda/module/modules/render/Zoom.kt | 41 +++++++------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt index 19c64c299..0bc27915d 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt @@ -22,12 +22,13 @@ import com.lambda.event.events.RenderEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag +import com.lambda.util.NamedEnum import java.lang.Math.clamp object Zoom : Module( - "Zoom", - "Zooms the current view", - ModuleTag.RENDER + name = "Zoom", + description = "Zooms the current view", + tag = ModuleTag.RENDER, ) { override val disableOnRelease by setting("Disable On Release", true) private var zoom by setting("Zoom", 2f, 1f..10f, 0.1f) @@ -48,8 +49,7 @@ object Zoom : Module( @JvmStatic var currentZoom = 1f; private set private var lastZoomTime = 1L private val zoomProgress - get() = - clamp((System.currentTimeMillis() - lastZoomTime) / (animationDuration * 1000).toDouble(), 0.0, 1.0).toFloat() + get() = clamp((System.currentTimeMillis() - lastZoomTime) / (animationDuration * 1000).toDouble(), 0.0, 1.0).toFloat() init { listen { event -> @@ -68,6 +68,7 @@ object Zoom : Module( onEnable { updateZoomTime() } + onDisable { extraZoom = 0f updateZoomTime() @@ -81,27 +82,15 @@ object Zoom : Module( @JvmStatic fun updateCurrentZoom() { val target = if (isEnabled) targetZoom else 1f - if (currentZoom == target) return - currentZoom = when (style) { - ZoomStyle.Instant -> target - ZoomStyle.EaseOut -> easeOut(currentZoom, target, zoomProgress) - ZoomStyle.EaseIn -> easeIn(currentZoom, target, zoomProgress) - } - } - - private fun easeOut(start: Float, end: Float, progress: Float): Float { - val easedT = 1f - (1f - progress) * (1f - progress) - return start + ((end - start) * easedT) - } - - private fun easeIn(start: Float, end: Float, progress: Float): Float { - val easedT = progress * progress - return start + ((end - start) * easedT) + currentZoom = style.apply(currentZoom, target, zoomProgress) } - private enum class ZoomStyle { - Instant, - EaseOut, - EaseIn + private enum class ZoomStyle( + override val displayName: String, + val apply: (Float, Float, Float) -> Float, + ) : NamedEnum { + Instant("Instant", { _, v, _ -> v }), + EaseOut("Ease Out", { start, end, progress -> start + ((end - start) * 1f - (1f - progress) * (1f - progress)) }), + EaseIn("Ease In", { start, end, progress -> start + ((end - start) * progress * progress) }) } -} \ No newline at end of file +} From 6a04076ef1ae93bfbfb3b8295e2205f00f360650 Mon Sep 17 00:00:00 2001 From: beanbag44 Date: Sun, 28 Sep 2025 15:55:27 +0100 Subject: [PATCH 4/4] merge fixes / enum fix --- src/main/kotlin/com/lambda/module/Module.kt | 3 +-- src/main/kotlin/com/lambda/module/modules/render/Zoom.kt | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/Module.kt b/src/main/kotlin/com/lambda/module/Module.kt index 26b526f43..276999dfe 100644 --- a/src/main/kotlin/com/lambda/module/Module.kt +++ b/src/main/kotlin/com/lambda/module/Module.kt @@ -113,8 +113,7 @@ abstract class Module( private val alwaysListening: Boolean = false, enabledByDefault: Boolean = false, defaultKeybind: KeyCode = KeyCode.UNBOUND, - autoDisable: Boolean = false, - open val disableOnRelease: Boolean = false + autoDisable: Boolean = false ) : Nameable, Muteable, Configurable(ModuleConfig) { private val isEnabledSetting = setting("Enabled", enabledByDefault) { false } val keybindSetting = setting("Keybind", defaultKeybind) { false } diff --git a/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt index 0bc27915d..f37520e9a 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt @@ -30,7 +30,6 @@ object Zoom : Module( description = "Zooms the current view", tag = ModuleTag.RENDER, ) { - override val disableOnRelease by setting("Disable On Release", true) private var zoom by setting("Zoom", 2f, 1f..10f, 0.1f) private val style by setting("Style", ZoomStyle.EaseOut) private val animationDuration by setting("Animation Duration", 1f, 0.1f..10f, 0.1f) { style != ZoomStyle.Instant } @@ -90,7 +89,7 @@ object Zoom : Module( val apply: (Float, Float, Float) -> Float, ) : NamedEnum { Instant("Instant", { _, v, _ -> v }), - EaseOut("Ease Out", { start, end, progress -> start + ((end - start) * 1f - (1f - progress) * (1f - progress)) }), - EaseIn("Ease In", { start, end, progress -> start + ((end - start) * progress * progress) }) + EaseOut("Ease Out", { start, end, progress -> start + ((end - start) * (1f - ((1f - progress) * (1f - progress)))) }), + EaseIn("Ease In", { start, end, progress -> start + ((end - start) * (progress * progress)) }) } }