diff --git a/src/main/java/com/lambda/mixin/render/CameraMixin.java b/src/main/java/com/lambda/mixin/render/CameraMixin.java index 93d2f1f19..a296ece06 100644 --- a/src/main/java/com/lambda/mixin/render/CameraMixin.java +++ b/src/main/java/com/lambda/mixin/render/CameraMixin.java @@ -17,8 +17,9 @@ package com.lambda.mixin.render; +import com.lambda.event.EventFlow; +import com.lambda.event.events.CameraEvent; import com.lambda.interaction.managers.rotating.RotationManager; -import com.lambda.module.modules.player.Freecam; import com.lambda.module.modules.render.CameraTweaks; import com.lambda.module.modules.render.FreeLook; import com.lambda.module.modules.render.NoRender; @@ -53,9 +54,11 @@ public abstract class CameraMixin { @Shadow private float pitch; - @Inject(method = "update", at = @At("TAIL")) + @Inject(method = "update", at = @At("TAIL"), cancellable = true) private void onUpdate(World area, Entity focusedEntity, boolean thirdPerson, boolean inverseView, float tickProgress, CallbackInfo ci) { - if (Freecam.INSTANCE.isEnabled()) Freecam.updateCam(); + if (EventFlow.post(CameraEvent.CameraPosition.INSTANCE).isCanceled()) { + ci.cancel(); + } } /** diff --git a/src/main/kotlin/com/lambda/event/events/CameraEvent.kt b/src/main/kotlin/com/lambda/event/events/CameraEvent.kt new file mode 100644 index 000000000..d37e48d90 --- /dev/null +++ b/src/main/kotlin/com/lambda/event/events/CameraEvent.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2026 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.event.events + +import com.lambda.event.Event +import com.lambda.event.callback.Cancellable +import com.lambda.event.callback.ICancellable + + +sealed class CameraEvent { + object CameraPosition : Event, ICancellable by Cancellable() +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/module/modules/movement/ElytraFly.kt b/src/main/kotlin/com/lambda/module/modules/movement/ElytraFly.kt index 576bb95c3..97bf5889a 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/ElytraFly.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/ElytraFly.kt @@ -17,15 +17,19 @@ package com.lambda.module.modules.movement +import com.lambda.Lambda +import com.lambda.Lambda.mc import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig import com.lambda.config.applyEdits import com.lambda.context.SafeContext +import com.lambda.event.events.CameraEvent import com.lambda.event.events.ClientEvent import com.lambda.event.events.MovementEvent import com.lambda.event.events.PacketEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest +import com.lambda.interaction.material.StackSelection.Companion.selectStack import com.lambda.module.Module import com.lambda.module.modules.movement.BetterFirework.canOpenElytra import com.lambda.module.modules.movement.BetterFirework.canTakeoff @@ -34,11 +38,11 @@ import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe import com.lambda.util.Timer import com.lambda.util.extension.isElytraFlying +import com.lambda.util.math.interpolate import com.lambda.util.player.MovementUtils.addSpeed import com.lambda.util.player.SlotUtils.hotbarAndInventoryStacks import com.lambda.util.player.SlotUtils.hotbarStacks import com.lambda.util.player.hasFirework -import com.lambda.interaction.material.StackSelection.Companion.selectStack import net.minecraft.component.DataComponentTypes import net.minecraft.entity.Entity import net.minecraft.item.ItemStack @@ -77,6 +81,16 @@ object ElytraFly : Module( private var lastDuration = 1.0 private val fireworkTimer = Timer() + private var stabilizeCamera = false + private var prevPosition: Vec3d = Vec3d.ZERO + private var position: Vec3d = Vec3d.ZERO + private val flipFlopLerpPos: Vec3d + get() { + var tickProgress = mc.gameRenderer.camera.lastTickProgress / 2 + if (!flipFlop) tickProgress += 0.5f + return prevPosition.interpolate(tickProgress, position) + } + init { setDefaultAutomationConfig { applyEdits { @@ -84,6 +98,18 @@ object ElytraFly : Module( } } + onEnable { + position = player.eyePos + prevPosition = position + } + + listen { + if (mode != FlyMode.GrimControl || !stabilizeCamera) return@listen + Lambda.mc.gameRenderer.apply { + camera.setPos(flipFlopLerpPos.x, flipFlopLerpPos.y, flipFlopLerpPos.z) + } + } + listen { if (mode == FlyMode.GrimControl) onTickGrimControl() else if (mode == FlyMode.Bounce) onTickBounce() @@ -132,22 +158,33 @@ object ElytraFly : Module( var vec = Vec3d.ZERO val yaw = player.yaw - if (mc.options.forwardKey.isPressed) vec = vec.add(Vec3d.fromPolar(0f, yaw)) - if (mc.options.backKey.isPressed) vec = vec.add(Vec3d.fromPolar(0f, yaw + 180f)) - if (mc.options.leftKey.isPressed) vec = vec.add(Vec3d.fromPolar(0f, yaw - 90f)) - if (mc.options.rightKey.isPressed) vec = vec.add(Vec3d.fromPolar(0f, yaw + 90f)) - if (mc.options.jumpKey.isPressed) vec = vec.add(Vec3d(0.0, 1.0, 0.0)) - if (mc.options.sneakKey.isPressed) vec = vec.add(Vec3d(0.0, -1.0, 0.0)) - if (vec.lengthSquared() < 1e-4 && player.hasFirework) { + if (flipFlop) { + if (mc.options.forwardKey.isPressed) vec = vec.add(Vec3d.fromPolar(0f, yaw)) + if (mc.options.backKey.isPressed) vec = vec.add(Vec3d.fromPolar(0f, yaw + 180f)) + if (mc.options.leftKey.isPressed) vec = vec.add(Vec3d.fromPolar(0f, yaw - 90f)) + if (mc.options.rightKey.isPressed) vec = vec.add(Vec3d.fromPolar(0f, yaw + 90f)) + if (mc.options.jumpKey.isPressed) vec = vec.add(Vec3d(0.0, 1.0, 0.0)) + if (mc.options.sneakKey.isPressed) vec = vec.add(Vec3d(0.0, -1.0, 0.0)) + } + if (vec.lengthSquared() < 1e-2 && player.hasFirework) { + if (!stabilizeCamera) { + stabilizeCamera = true + position = player.eyePos + prevPosition = position + flipFlop = true + } if (flipFlop) { flipFlop = false rotationRequest { rotation(0f, 0f) } } else { flipFlop = true + prevPosition = position + position = player.eyePos rotationRequest { rotation(180f, 0f) } } } else { val rot = vec.yawAndPitch + stabilizeCamera = false rotationRequest { rotation(rot.y, rot.x) } }.submit() } diff --git a/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt b/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt index 4c0558313..181703a7d 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt @@ -17,7 +17,9 @@ package com.lambda.module.modules.player +import com.lambda.Lambda import com.lambda.Lambda.mc +import com.lambda.event.events.CameraEvent import com.lambda.event.events.MovementEvent import com.lambda.event.events.PlayerEvent import com.lambda.event.events.RenderEvent @@ -84,14 +86,6 @@ object Freecam : Module( private var rotation: Rotation = Rotation.ZERO private var velocity: Vec3d = Vec3d.ZERO - @JvmStatic - fun updateCam() { - mc.gameRenderer.apply { - camera.setRotation(rotation.yawF, rotation.pitchF) - camera.setPos(lerpPos.x, lerpPos.y, lerpPos.z) - } - } - /** * @see net.minecraft.entity.Entity.changeLookDirection */ @@ -110,6 +104,13 @@ object Freecam : Module( mc.options.perspective = lastPerspective } + listen { + Lambda.mc.gameRenderer.apply { + camera.setRotation(rotation.yawF, rotation.pitchF) + camera.setPos(lerpPos.x, lerpPos.y, lerpPos.z) + } + } + listen { when (rotateMode) { FreecamRotationMode.None -> return@listen