Skip to content

Commit 5694840

Browse files
committed
Merge branch '1.21.5' into feature/mouse-button-binds
# Conflicts: # src/main/kotlin/com/lambda/module/Module.kt
2 parents da78f11 + e5d5fee commit 5694840

File tree

7 files changed

+229
-7
lines changed

7 files changed

+229
-7
lines changed

src/main/java/com/lambda/mixin/entity/EntityMixin.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@
2222
import com.lambda.event.events.EntityEvent;
2323
import com.lambda.event.events.PlayerEvent;
2424
import com.lambda.interaction.request.rotating.RotationManager;
25+
import com.lambda.interaction.request.rotating.RotationMode;
26+
import com.lambda.module.modules.player.RotationLock;
2527
import com.lambda.module.modules.render.NoRender;
2628
import com.lambda.util.math.Vec2d;
2729
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
30+
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
2831
import net.minecraft.entity.Entity;
2932
import net.minecraft.entity.MovementType;
3033
import net.minecraft.entity.data.TrackedData;
@@ -142,4 +145,20 @@ private boolean modifyGetFlagInvisible(boolean original) {
142145
private boolean modifyGetFlagGlowing(boolean original) {
143146
return (NoRender.INSTANCE.isDisabled() || !NoRender.getNoGlow()) && original;
144147
}
148+
149+
@WrapWithCondition(method = "changeLookDirection", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;setYaw(F)V"))
150+
private boolean wrapSetYaw(Entity instance, float yaw) {
151+
return (instance != Lambda.getMc().player ||
152+
RotationLock.INSTANCE.isDisabled() ||
153+
RotationLock.getRotationSettings().getRotationMode() != RotationMode.Lock ||
154+
RotationLock.getYawMode() == RotationLock.RotationMode.None);
155+
}
156+
157+
@WrapWithCondition(method = "changeLookDirection", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;setPitch(F)V"))
158+
private boolean wrapSetPitch(Entity instance, float yaw) {
159+
return (instance != Lambda.getMc().player ||
160+
RotationLock.INSTANCE.isDisabled() ||
161+
RotationLock.getRotationSettings().getRotationMode() != RotationMode.Lock ||
162+
RotationLock.getPitchMode() == RotationLock.RotationMode.None);
163+
}
145164
}

src/main/java/com/lambda/mixin/input/MouseMixin.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@
1919

2020
import com.lambda.event.EventFlow;
2121
import com.lambda.event.events.MouseEvent;
22+
import com.lambda.module.modules.render.Zoom;
2223
import com.lambda.util.math.Vec2d;
2324
import net.minecraft.client.Mouse;
25+
import net.minecraft.client.option.GameOptions;
26+
import net.minecraft.client.option.SimpleOption;
2427
import org.spongepowered.asm.mixin.Mixin;
2528
import org.spongepowered.asm.mixin.Shadow;
2629
import org.spongepowered.asm.mixin.injection.At;
2730
import org.spongepowered.asm.mixin.injection.Inject;
31+
import org.spongepowered.asm.mixin.injection.Redirect;
2832
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
2933

3034
@Mixin(Mouse.class)
@@ -61,4 +65,17 @@ private void onCursorPos(long window, double x, double y, CallbackInfo ci) {
6165
ci.cancel();
6266
}
6367
}
68+
69+
@Redirect(method = "updateMouse", at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/GameOptions;smoothCameraEnabled:Z"))
70+
private boolean redirectSmoothCameraEnabled(GameOptions instance) {
71+
if (Zoom.INSTANCE.isEnabled() && Zoom.getSmoothMovement()) return true;
72+
else return instance.smoothCameraEnabled;
73+
}
74+
75+
@SuppressWarnings("rawtypes")
76+
@Redirect(method = "updateMouse", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/SimpleOption;getValue()Ljava/lang/Object;", ordinal = 0))
77+
private Object redirectGetValue(SimpleOption instance) {
78+
if (Zoom.INSTANCE.isEnabled()) return ((Double) instance.getValue()) / Zoom.getTargetZoom();
79+
else return instance.getValue();
80+
}
6481
}

src/main/java/com/lambda/mixin/render/GameRendererMixin.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
import com.lambda.event.events.RenderEvent;
2222
import com.lambda.graphics.RenderMain;
2323
import com.lambda.module.modules.render.NoRender;
24+
import com.lambda.module.modules.render.Zoom;
2425
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
26+
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
2527
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
2628
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
2729
import net.minecraft.client.render.Camera;
@@ -73,4 +75,9 @@ private float modifyMax(float original) {
7375
private void injectShowFloatingItem(ItemStack floatingItem, CallbackInfo ci) {
7476
if (NoRender.INSTANCE.isEnabled() && NoRender.getNoFloatingItemAnimation()) ci.cancel();
7577
}
78+
79+
@ModifyReturnValue(method = "getFov", at = @At("RETURN"))
80+
private float modifyGetFov(float original) {
81+
return original / Zoom.getCurrentZoom();
82+
}
7683
}

src/main/kotlin/com/lambda/gui/components/SettingsWidget.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ object SettingsWidget {
3232
group {
3333
if (config is Module) {
3434
with(config.keybindSetting) { buildLayout() }
35+
with(config.disableOnReleaseSetting) { buildLayout() }
3536
}
3637
sameLine()
3738
smallButton("Reset") {
@@ -40,7 +41,7 @@ object SettingsWidget {
4041
lambdaTooltip("Resets all settings for this module to their default values")
4142
}
4243
separator()
43-
val toIgnoreSettings = if (config is Module) setOf(config.keybindSetting) else emptySet()
44+
val toIgnoreSettings = if (config is Module) setOf(config.keybindSetting, config.disableOnReleaseSetting) else emptySet()
4445
val visibleSettings = config.settings.filter { it.visibility() } - toIgnoreSettings
4546
val (grouped, ungrouped) = visibleSettings.partition { it.groups.isNotEmpty() }
4647
ungrouped.forEach { with(it) { buildLayout() } }

src/main/kotlin/com/lambda/module/Module.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package com.lambda.module
1919

2020
import com.lambda.Lambda.mc
21+
import com.lambda.Lambda
2122
import com.lambda.command.LambdaCommand
2223
import com.lambda.config.AbstractSetting
2324
import com.lambda.config.Configurable
@@ -40,6 +41,7 @@ import com.lambda.sound.SoundManager.play
4041
import com.lambda.util.KeyCode
4142
import com.lambda.util.Mouse
4243
import com.lambda.util.Nameable
44+
import javax.swing.ActionMap
4345

4446
/**
4547
* A [Module] is a feature or tool for the utility mod.
@@ -120,26 +122,28 @@ abstract class Module(
120122
) : Nameable, Muteable, Configurable(ModuleConfig) {
121123
private val isEnabledSetting = setting("Enabled", enabledByDefault) { false }
122124
val keybindSetting = setting("Keybind", defaultKeybind) { false }
125+
val disableOnReleaseSetting = setting("Disable On Release", false) { false }
123126

124127
open val isVisible: Boolean = true
125128

126129
var isEnabled by isEnabledSetting
127130
val isDisabled get() = !isEnabled
128131

129-
var keybind by keybindSetting
132+
val keybind by keybindSetting
133+
val disableOnRelease by disableOnReleaseSetting
130134

131135
override val isMuted: Boolean
132136
get() = !isEnabled && !alwaysListening
133137

134138
init {
135139
listen<KeyboardEvent.Press>(alwaysListen = true) { event ->
136-
if (event.isPressed)
137-
onButtonPress(event.keyCode)
140+
onButtonPress(event.keyCode, event.isPressed, event.isReleased)
138141
}
139142

140143
listen<MouseEvent.Click>(alwaysListen = true) { event ->
141-
if (event.action == Mouse.Action.Click.ordinal)
142-
onButtonPress(event.button)
144+
val pressed = event.action == Mouse.Action.Click.ordinal
145+
val released = event.action == Mouse.Action.Release.ordinal
146+
onButtonPress(event.button, pressed, released, mouseButton = true)
143147
}
144148

145149
onEnable { LambdaSound.MODULE_ON.play() }
@@ -153,7 +157,7 @@ abstract class Module(
153157
listen<ConnectionEvent.Disconnect> { if (autoDisable) disable() }
154158
}
155159

156-
private fun onButtonPress(code: Int, mouseButton: Boolean = false) {
160+
private fun onButtonPress(code: Int, pressed: Boolean, released: Boolean, mouseButton: Boolean = false) {
157161
if (mc.options.commandKey.isPressed) return
158162
if (mc.currentScreen != null) return
159163
if (keybind.code == KeyCode.UNBOUND.code) return
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.module.modules.player
19+
20+
import com.lambda.config.groups.RotationSettings
21+
import com.lambda.event.events.TickEvent
22+
import com.lambda.event.listener.SafeListener.Companion.listen
23+
import com.lambda.interaction.request.rotating.Rotation
24+
import com.lambda.interaction.request.rotating.RotationRequest
25+
import com.lambda.interaction.request.rotating.visibilty.lookAt
26+
import com.lambda.module.Module
27+
import com.lambda.module.tag.ModuleTag
28+
import com.lambda.util.NamedEnum
29+
import kotlin.math.roundToInt
30+
31+
object RotationLock : Module(
32+
name = "RotationLock",
33+
description = "Locks the player rotation to the given configuration",
34+
tag = ModuleTag.PLAYER,
35+
) {
36+
private enum class Group(override val displayName: String) : NamedEnum {
37+
General("General"),
38+
Rotation("Rotation")
39+
}
40+
41+
@JvmStatic val yawMode by setting("Yaw Mode", RotationMode.Snap).group(Group.General)
42+
private val yawStep by setting("Yaw Step", 45.0, 1.0..180.0, 1.0) { yawMode == RotationMode.Snap }.group(Group.General)
43+
private val customYaw by setting("Custom Yaw", 0.0, -179.0..180.0, 1.0) { yawMode == RotationMode.Custom }.group(Group.General)
44+
@JvmStatic val pitchMode by setting("Pitch Mode", RotationMode.Custom).group(Group.General)
45+
private val pitchStep by setting("Pitch Step", 45.0, 1.0..90.0, 1.0) { pitchMode == RotationMode.Snap }.group(Group.General)
46+
private val customPitch by setting("Custom Pitch", 0.0, -90.0..90.0, 1.0) { pitchMode == RotationMode.Custom }.group(Group.General)
47+
48+
@JvmStatic val rotationSettings = RotationSettings(this, Group.Rotation)
49+
private var rotationRequest: RotationRequest? = null
50+
51+
init {
52+
listen<TickEvent.Pre> {
53+
val yaw = when (yawMode) {
54+
RotationMode.Custom -> customYaw
55+
RotationMode.Snap -> {
56+
val normalizedYaw = (player.yaw % 360.0 + 360.0) % 360.0
57+
(normalizedYaw / yawStep).roundToInt() * yawStep
58+
}
59+
RotationMode.None -> player.yaw.toDouble()
60+
}
61+
val pitch = when (pitchMode) {
62+
RotationMode.Custom -> customPitch
63+
RotationMode.Snap -> {
64+
val clampedPitch = player.pitch.coerceIn(-90f, 90f)
65+
(clampedPitch / pitchStep).roundToInt() * pitchStep
66+
}
67+
RotationMode.None -> player.pitch.toDouble()
68+
}
69+
70+
RotationRequest(lookAt(Rotation(yaw, pitch), 0.001), rotationSettings).submit()
71+
}
72+
}
73+
74+
enum class RotationMode {
75+
Snap,
76+
Custom,
77+
None
78+
}
79+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.module.modules.render
19+
20+
import com.lambda.event.events.MouseEvent
21+
import com.lambda.event.events.RenderEvent
22+
import com.lambda.event.listener.SafeListener.Companion.listen
23+
import com.lambda.module.Module
24+
import com.lambda.module.tag.ModuleTag
25+
import com.lambda.util.NamedEnum
26+
import java.lang.Math.clamp
27+
28+
object Zoom : Module(
29+
name = "Zoom",
30+
description = "Zooms the current view",
31+
tag = ModuleTag.RENDER,
32+
) {
33+
private var zoom by setting("Zoom", 2f, 1f..10f, 0.1f)
34+
private val style by setting("Style", ZoomStyle.EaseOut)
35+
private val animationDuration by setting("Animation Duration", 1f, 0.1f..10f, 0.1f) { style != ZoomStyle.Instant }
36+
private val scroll by setting("Scroll", true)
37+
private val persistentScroll by setting("Persistent Scroll", false) { scroll }
38+
private val sensitivity by setting("Sensitivity", 0.2f, 0.1f..1f, 0.1f) { scroll }
39+
@JvmStatic val smoothMovement by setting("Smooth Movement", false)
40+
41+
private var extraZoom = 0f
42+
set(value) {
43+
field = value.coerceAtLeast(-zoom + 1)
44+
}
45+
@JvmStatic val targetZoom: Float
46+
get() = zoom + extraZoom
47+
48+
@JvmStatic var currentZoom = 1f; private set
49+
private var lastZoomTime = 1L
50+
private val zoomProgress
51+
get() = clamp((System.currentTimeMillis() - lastZoomTime) / (animationDuration * 1000).toDouble(), 0.0, 1.0).toFloat()
52+
53+
init {
54+
listen<MouseEvent.Scroll> { event ->
55+
val yDelta = event.delta.y.toFloat()
56+
val delta = (yDelta * sensitivity) + (((zoom + extraZoom) * sensitivity) * yDelta)
57+
if (persistentScroll) zoom += delta
58+
else extraZoom += delta
59+
updateZoomTime()
60+
event.cancel()
61+
}
62+
63+
listen<RenderEvent.Render>(alwaysListen = true) {
64+
updateCurrentZoom()
65+
}
66+
67+
onEnable {
68+
updateZoomTime()
69+
}
70+
71+
onDisable {
72+
extraZoom = 0f
73+
updateZoomTime()
74+
}
75+
}
76+
77+
private fun updateZoomTime() {
78+
lastZoomTime = System.currentTimeMillis()
79+
}
80+
81+
@JvmStatic
82+
fun updateCurrentZoom() {
83+
val target = if (isEnabled) targetZoom else 1f
84+
currentZoom = style.apply(currentZoom, target, zoomProgress)
85+
}
86+
87+
private enum class ZoomStyle(
88+
override val displayName: String,
89+
val apply: (Float, Float, Float) -> Float,
90+
) : NamedEnum {
91+
Instant("Instant", { _, v, _ -> v }),
92+
EaseOut("Ease Out", { start, end, progress -> start + ((end - start) * (1f - ((1f - progress) * (1f - progress)))) }),
93+
EaseIn("Ease In", { start, end, progress -> start + ((end - start) * (progress * progress)) })
94+
}
95+
}

0 commit comments

Comments
 (0)