From d3d5bfb2c2af8f1a48def0bc0bdcee59eb288209 Mon Sep 17 00:00:00 2001 From: Constructor Date: Tue, 19 Mar 2024 05:17:31 +0100 Subject: [PATCH 1/7] Movement hooks --- .../mixin/entity/ClientPlayerEntityMixin.java | 58 +++++++++++++++++++ .../com/lambda/mixin/entity/EntityMixin.java | 12 ++++ .../mixin/entity/LivingEntityMixin.java | 43 ++++++++++++++ .../com/lambda/event/events/MovementEvent.kt | 4 ++ .../main/resources/lambda.mixins.common.json | 7 ++- 5 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java create mode 100644 common/src/main/java/com/lambda/mixin/entity/EntityMixin.java create mode 100644 common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java diff --git a/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java b/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java new file mode 100644 index 000000000..582d09610 --- /dev/null +++ b/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java @@ -0,0 +1,58 @@ +package com.lambda.mixin.entity; + +import com.lambda.Lambda; +import com.lambda.event.EventFlow; +import com.lambda.event.events.MovementEvent; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.entity.MovementType; +import net.minecraft.util.math.Vec3d; +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(value = ClientPlayerEntity.class, priority = Integer.MAX_VALUE) +public abstract class ClientPlayerEntityMixin extends EntityMixin { + + @Shadow protected abstract void autoJump(float dx, float dz); + + @Shadow public abstract boolean isUsingItem(); + + @Shadow private boolean autoJumpEnabled; + + @Inject(method = "move", at = @At("HEAD"), cancellable = true) + void onMove(MovementType movementType, Vec3d movement, CallbackInfo ci) { + ClientPlayerEntity self = (ClientPlayerEntity) (Object) this; + if (self != Lambda.getMc().player) return; + + ci.cancel(); + + float prevX = (float) self.getX(); + float prevZ = (float) self.getZ(); + + EventFlow.post(new MovementEvent.Pre()); + super.move(movementType, self.getVelocity()); + EventFlow.post(new MovementEvent.Post()); + + float currX = (float) self.getX(); + float currZ = (float) self.getZ(); + + this.autoJump(currX - prevX, currZ - prevZ); + } + + @Redirect(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isUsingItem()Z")) + boolean onSlowDown(ClientPlayerEntity entity) { + if (EventFlow.post(new MovementEvent.SlowDown()).isCanceled()) return false; + return this.isUsingItem(); + } + + @Inject(method = "sendMovementPackets", at = @At(value = "HEAD"), cancellable = true) + void sendBegin(CallbackInfo ci) { + ci.cancel(); +// PlayerPacketManager.sendPlayerPackets(); + autoJumpEnabled = MinecraftClient.getInstance().options.getAutoJump().getValue(); + } +} diff --git a/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java b/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java new file mode 100644 index 000000000..70292d5b2 --- /dev/null +++ b/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java @@ -0,0 +1,12 @@ +package com.lambda.mixin.entity; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.MovementType; +import net.minecraft.util.math.Vec3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(Entity.class) +public abstract class EntityMixin { + @Shadow public void move(MovementType movementType, Vec3d movement) {} +} \ No newline at end of file diff --git a/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java b/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java new file mode 100644 index 000000000..dc1aee881 --- /dev/null +++ b/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java @@ -0,0 +1,43 @@ +package com.lambda.mixin.entity; + +import com.lambda.Lambda; +import com.lambda.event.EventFlow; +import com.lambda.event.events.MovementEvent; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.math.Vec3d; +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.callback.CallbackInfo; + +@Mixin(LivingEntity.class) +public abstract class LivingEntityMixin extends EntityMixin { + + @Shadow + protected abstract float getJumpVelocity(); + + @Inject(method = "jump", at = @At("HEAD"), cancellable = true) + void onJump(CallbackInfo ci) { + LivingEntity self = (LivingEntity) (Object) this; + if (self != Lambda.getMc().player) return; + ci.cancel(); + + float height = this.getJumpVelocity(); + MovementEvent.Jump event = EventFlow.post(new MovementEvent.Jump(height)); + + if (event.isCanceled()) return; + + if (!self.isSprinting()) { + Vec3d velocity = self.getVelocity(); + self.setVelocity(velocity.x, event.getHeight(), velocity.z); + } else { + // ToDo: Implement rotation system +// Float yaw = RotationManager.getMovementYaw(); +// float f = ((yaw != null) ? yaw : self.getYaw()) * ((float)Math.PI / 180); +// self.setVelocity(self.getVelocity().add(-MathHelper.sin(f) * 0.2f, 0.0, MathHelper.cos(f) * 0.2f)); + } + + self.velocityDirty = true; + } +} diff --git a/common/src/main/kotlin/com/lambda/event/events/MovementEvent.kt b/common/src/main/kotlin/com/lambda/event/events/MovementEvent.kt index c5397f07d..34d2df099 100644 --- a/common/src/main/kotlin/com/lambda/event/events/MovementEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/MovementEvent.kt @@ -5,5 +5,9 @@ import com.lambda.event.cancellable.Cancellable import com.lambda.event.cancellable.ICancellable abstract class MovementEvent : Event { + class Pre : MovementEvent() + class Post : MovementEvent() class ClipAtLedge : MovementEvent(), ICancellable by Cancellable() + class Jump(var height: Double) : MovementEvent(), ICancellable by Cancellable() + class SlowDown : Event, ICancellable by Cancellable() } \ No newline at end of file diff --git a/common/src/main/resources/lambda.mixins.common.json b/common/src/main/resources/lambda.mixins.common.json index d8d90833f..2fe2ee6a4 100644 --- a/common/src/main/resources/lambda.mixins.common.json +++ b/common/src/main/resources/lambda.mixins.common.json @@ -7,10 +7,13 @@ "ChatInputSuggestorMixin", "ChatScreenMixin", "ClientConnectionMixin", + "KeyBindingMixin", "KeyboardMixin", "MinecraftClientMixin", - "KeyBindingMixin", - "PlayerEntityMixin" + "PlayerEntityMixin", + "entity.ClientPlayerEntityMixin", + "entity.EntityMixin", + "entity.LivingEntityMixin" ], "injectors": { "defaultRequire": 1 From 680fc56cb2276869f8995b1f841de888e9bc41b3 Mon Sep 17 00:00:00 2001 From: Constructor Date: Wed, 20 Mar 2024 01:56:31 +0100 Subject: [PATCH 2/7] Connection events --- .../lambda/mixin/ClientConnectionMixin.java | 20 +++++++++++++++++++ .../lambda/event/events/ConnectionEvent.kt | 16 +++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 common/src/main/kotlin/com/lambda/event/events/ConnectionEvent.kt diff --git a/common/src/main/java/com/lambda/mixin/ClientConnectionMixin.java b/common/src/main/java/com/lambda/mixin/ClientConnectionMixin.java index 8552a272d..1c8daf224 100644 --- a/common/src/main/java/com/lambda/mixin/ClientConnectionMixin.java +++ b/common/src/main/java/com/lambda/mixin/ClientConnectionMixin.java @@ -1,11 +1,15 @@ package com.lambda.mixin; import com.lambda.event.EventFlow; +import com.lambda.event.events.ConnectionEvent; import com.lambda.event.events.PacketEvent; import io.netty.channel.ChannelHandlerContext; import net.minecraft.network.ClientConnection; import net.minecraft.network.NetworkSide; +import net.minecraft.network.listener.PacketListener; import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.c2s.handshake.ConnectionIntent; +import net.minecraft.text.Text; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -53,4 +57,20 @@ private void receivingPacketPost( EventFlow.post(new PacketEvent.Receive.Post(packet)); } + + @Inject(method = "connect(Ljava/lang/String;ILnet/minecraft/network/listener/PacketListener;Lnet/minecraft/network/packet/c2s/handshake/ConnectionIntent;)V", at = @At("HEAD")) + private void onConnect( + String address, + int port, + PacketListener listener, + ConnectionIntent intent, + CallbackInfo ci + ) { + EventFlow.post(new ConnectionEvent.Connect(address, port, listener, intent)); + } + + @Inject(method = "disconnect(Lnet/minecraft/text/Text;)V", at = @At("HEAD")) + private void onDisconnect(Text reason, CallbackInfo ci) { + EventFlow.post(new ConnectionEvent.Disconnect(reason)); + } } diff --git a/common/src/main/kotlin/com/lambda/event/events/ConnectionEvent.kt b/common/src/main/kotlin/com/lambda/event/events/ConnectionEvent.kt new file mode 100644 index 000000000..1be50ae82 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/event/events/ConnectionEvent.kt @@ -0,0 +1,16 @@ +package com.lambda.event.events + +import com.lambda.event.Event +import net.minecraft.network.listener.PacketListener +import net.minecraft.network.packet.c2s.handshake.ConnectionIntent +import net.minecraft.text.Text + +abstract class ConnectionEvent : Event { + class Connect( + val host: String, + port: Int, + listener: PacketListener, + intent: ConnectionIntent + ) : ConnectionEvent() + class Disconnect(val reason: Text) : ConnectionEvent() +} \ No newline at end of file From f3f3eafd6ca490429fba68bf9f9acb4d7de42286 Mon Sep 17 00:00:00 2001 From: Constructor Date: Wed, 20 Mar 2024 07:37:44 +0100 Subject: [PATCH 3/7] Rotation system and visibility checker --- .../java/com/lambda/mixin/DebugHudMixin.java | 39 +++ .../mixin/entity/ClientPlayerEntityMixin.java | 23 +- .../com/lambda/mixin/entity/EntityMixin.java | 49 ++++ .../mixin/entity/LivingEntityMixin.java | 56 ++++- common/src/main/kotlin/com/lambda/Loadable.kt | 2 +- common/src/main/kotlin/com/lambda/Loader.kt | 4 +- .../com/lambda/config/InteractionSettings.kt | 13 + .../com/lambda/config/RotationSettings.kt | 29 +++ .../lambda/config/settings/NumericSetting.kt | 17 +- .../main/kotlin/com/lambda/event/EventFlow.kt | 11 + .../lambda/event/events/PlayerPacketEvent.kt | 20 ++ .../com/lambda/event/events/RotationEvent.kt | 126 ++++++++++ .../com/lambda/manager/PlayerPacketManager.kt | 134 ++++++++++ .../com/lambda/manager/RotationManager.kt | 228 ++++++++++++++++++ .../manager/interaction/InteractionConfig.kt | 17 ++ .../manager/interaction/VisibilityChecker.kt | 71 ++++++ .../manager/rotation/IRotationConfig.kt | 25 ++ .../com/lambda/manager/rotation/Rotation.kt | 104 ++++++++ .../manager/rotation/RotationContext.kt | 6 + .../lambda/manager/rotation/RotationMode.kt | 12 + .../com/lambda/module/modules/BoringModule.kt | 2 - .../com/lambda/module/modules/RotationTest.kt | 28 +++ .../lambda/module/modules/client/Baritone.kt | 23 ++ .../kotlin/com/lambda/util/math/ColorUtils.kt | 16 ++ .../kotlin/com/lambda/util/math/MathUtils.kt | 142 +++++++++++ .../main/kotlin/com/lambda/util/math/Range.kt | 101 ++++++++ .../main/kotlin/com/lambda/util/math/Vec2d.kt | 47 ++++ .../kotlin/com/lambda/util/math/VecUtils.kt | 42 ++++ .../com/lambda/util/player/MovementUtils.kt | 78 ++++++ .../util/primitives/extension/Components.kt | 10 + .../util/primitives/extension/Entity.kt | 24 ++ .../lambda/util/primitives/extension/Mixin.kt | 6 + .../com/lambda/util/world/EntityUtils.kt | 2 +- .../lambda/util/world/raycast/RayCastMask.kt | 7 + .../lambda/util/world/raycast/RayCastUtils.kt | 67 +++++ .../src/main/resources/lambda.accesswidener | 2 + .../main/resources/lambda.mixins.common.json | 1 + 37 files changed, 1553 insertions(+), 31 deletions(-) create mode 100644 common/src/main/java/com/lambda/mixin/DebugHudMixin.java create mode 100644 common/src/main/kotlin/com/lambda/config/InteractionSettings.kt create mode 100644 common/src/main/kotlin/com/lambda/config/RotationSettings.kt create mode 100644 common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt create mode 100644 common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt create mode 100644 common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt create mode 100644 common/src/main/kotlin/com/lambda/manager/RotationManager.kt create mode 100644 common/src/main/kotlin/com/lambda/manager/interaction/InteractionConfig.kt create mode 100644 common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt create mode 100644 common/src/main/kotlin/com/lambda/manager/rotation/IRotationConfig.kt create mode 100644 common/src/main/kotlin/com/lambda/manager/rotation/Rotation.kt create mode 100644 common/src/main/kotlin/com/lambda/manager/rotation/RotationContext.kt create mode 100644 common/src/main/kotlin/com/lambda/manager/rotation/RotationMode.kt create mode 100644 common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt create mode 100644 common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt create mode 100644 common/src/main/kotlin/com/lambda/util/math/ColorUtils.kt create mode 100644 common/src/main/kotlin/com/lambda/util/math/MathUtils.kt create mode 100644 common/src/main/kotlin/com/lambda/util/math/Range.kt create mode 100644 common/src/main/kotlin/com/lambda/util/math/Vec2d.kt create mode 100644 common/src/main/kotlin/com/lambda/util/math/VecUtils.kt create mode 100644 common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt create mode 100644 common/src/main/kotlin/com/lambda/util/primitives/extension/Components.kt create mode 100644 common/src/main/kotlin/com/lambda/util/primitives/extension/Entity.kt create mode 100644 common/src/main/kotlin/com/lambda/util/primitives/extension/Mixin.kt create mode 100644 common/src/main/kotlin/com/lambda/util/world/raycast/RayCastMask.kt create mode 100644 common/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt diff --git a/common/src/main/java/com/lambda/mixin/DebugHudMixin.java b/common/src/main/java/com/lambda/mixin/DebugHudMixin.java new file mode 100644 index 000000000..e541234a2 --- /dev/null +++ b/common/src/main/java/com/lambda/mixin/DebugHudMixin.java @@ -0,0 +1,39 @@ +package com.lambda.mixin; + +import com.lambda.Lambda; +import net.minecraft.client.gui.hud.DebugHud; +import net.minecraft.util.Formatting; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; + +@Mixin(DebugHud.class) +public class DebugHudMixin { + @Inject(method = "getRightText", at = @At(value = "TAIL")) + private void onGetRightText(CallbackInfoReturnable> cir) { + + if (Lambda.getMc().crosshairTarget == null) return; + HitResult hitResult = Lambda.getMc().crosshairTarget; + List list = cir.getReturnValue(); + + list.add(""); + list.add(Formatting.UNDERLINE + "Lambda"); + list.add("Hitpos: " + hitResult.getPos()); + list.add("Type: " + hitResult.getType()); + + if (hitResult instanceof BlockHitResult blockHitResult) { + list.add("Side: " + blockHitResult.getSide()); + list.add("Blockpos: " + blockHitResult.getBlockPos()); + } + + if (hitResult instanceof EntityHitResult entityHitResult) { + list.add("Entity: " + entityHitResult.getEntity().getName().getString()); + } + } +} diff --git a/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java b/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java index 582d09610..7c5942e0f 100644 --- a/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java +++ b/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java @@ -3,6 +3,8 @@ import com.lambda.Lambda; import com.lambda.event.EventFlow; import com.lambda.event.events.MovementEvent; +import com.lambda.manager.PlayerPacketManager; +import com.lambda.manager.RotationManager; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.entity.MovementType; @@ -14,6 +16,8 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.Objects; + @Mixin(value = ClientPlayerEntity.class, priority = Integer.MAX_VALUE) public abstract class ClientPlayerEntityMixin extends EntityMixin { @@ -49,10 +53,25 @@ boolean onSlowDown(ClientPlayerEntity entity) { return this.isUsingItem(); } + @Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/input/Input;tick(ZF)V", shift = At.Shift.AFTER)) + void processMovement(CallbackInfo ci) { + RotationManager.BaritoneProcessor.processPlayerMovement(); + } + @Inject(method = "sendMovementPackets", at = @At(value = "HEAD"), cancellable = true) void sendBegin(CallbackInfo ci) { ci.cancel(); -// PlayerPacketManager.sendPlayerPackets(); - autoJumpEnabled = MinecraftClient.getInstance().options.getAutoJump().getValue(); + PlayerPacketManager.sendPlayerPackets(); + autoJumpEnabled = Lambda.getMc().options.getAutoJump().getValue(); + } + + @Redirect(method = "tickNewAi", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;getYaw()F")) + float fixHeldItemYaw(ClientPlayerEntity instance) { + return Objects.requireNonNullElse(RotationManager.getHandYaw(), instance.getYaw()); + } + + @Redirect(method = "tickNewAi", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;getPitch()F")) + float fixHeldItemPitch(ClientPlayerEntity instance) { + return Objects.requireNonNullElse(RotationManager.getHandPitch(), instance.getPitch()); } } diff --git a/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java b/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java index 70292d5b2..1aa3224b3 100644 --- a/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java +++ b/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java @@ -1,12 +1,61 @@ package com.lambda.mixin.entity; +import com.lambda.Lambda; +import com.lambda.manager.RotationManager; +import com.lambda.util.math.Vec2d; import net.minecraft.entity.Entity; import net.minecraft.entity.MovementType; import net.minecraft.util.math.Vec3d; 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.Redirect; @Mixin(Entity.class) public abstract class EntityMixin { @Shadow public void move(MovementType movementType, Vec3d movement) {} + + @Shadow public abstract float getYaw(); + + @Redirect(method = "updateVelocity", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getYaw()F")) + public float velocityYaw(Entity entity) { + if ((Object) this != Lambda.getMc().player) return getYaw(); + + Float y = RotationManager.getMovementYaw(); + if (y == null) return getYaw(); + + return y; + } + + @Redirect(method = "getRotationVec", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getYaw(F)F")) + float fixDirectionYaw(Entity entity, float tickDelta) { + Vec2d rot = RotationManager.getRotationForVector(tickDelta); + if (entity != Lambda.getMc().player || rot == null) return entity.getYaw(tickDelta); + + return (float) rot.getX(); + } + + @Redirect(method = "getRotationVec", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getPitch(F)F")) + float fixDirectionPitch(Entity entity, float tickDelta) { + Vec2d rot = RotationManager.getRotationForVector(tickDelta); + if (entity != Lambda.getMc().player || rot == null) return entity.getPitch(tickDelta); + + return (float) rot.getY(); + } + + @Redirect(method = "getRotationVector()Lnet/minecraft/util/math/Vec3d;", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getYaw()F")) + float fixDirectionYaw2(Entity entity) { + Vec2d rot = RotationManager.getRotationForVector(1.0); + if (entity != Lambda.getMc().player || rot == null) return entity.getYaw(); + + return (float) rot.getX(); + } + + @Redirect(method = "getRotationVector()Lnet/minecraft/util/math/Vec3d;", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getPitch()F")) + float fixDirectionPitch2(Entity entity) { + Vec2d rot = RotationManager.getRotationForVector(1.0); + if (entity != Lambda.getMc().player || rot == null) return entity.getPitch(); + + return (float) rot.getY(); + } } \ No newline at end of file diff --git a/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java b/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java index dc1aee881..cf333e5fd 100644 --- a/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java +++ b/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java @@ -3,12 +3,17 @@ import com.lambda.Lambda; import com.lambda.event.EventFlow; import com.lambda.event.events.MovementEvent; +import com.lambda.manager.RotationManager; +import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; 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.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(LivingEntity.class) @@ -28,16 +33,51 @@ void onJump(CallbackInfo ci) { if (event.isCanceled()) return; - if (!self.isSprinting()) { - Vec3d velocity = self.getVelocity(); - self.setVelocity(velocity.x, event.getHeight(), velocity.z); - } else { - // ToDo: Implement rotation system -// Float yaw = RotationManager.getMovementYaw(); -// float f = ((yaw != null) ? yaw : self.getYaw()) * ((float)Math.PI / 180); -// self.setVelocity(self.getVelocity().add(-MathHelper.sin(f) * 0.2f, 0.0, MathHelper.cos(f) * 0.2f)); + Vec3d vec3d = self.getVelocity(); + self.setVelocity(vec3d.x, event.getHeight(), vec3d.z); + + if (self.isSprinting()) { + Float yaw = RotationManager.getMovementYaw(); + float f = ((yaw != null) ? yaw : self.getYaw()) * ((float)Math.PI / 180); + self.setVelocity(self.getVelocity().add(-MathHelper.sin(f) * 0.2f, 0.0, MathHelper.cos(f) * 0.2f)); } self.velocityDirty = true; } + + @Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;isImmobile()Z")) + void onTravelH(CallbackInfo ci) { + Entity self = (Entity) (Object) this; + if (self != Lambda.getMc().player) return; + + RotationManager.update(); + } + + @Redirect(method = "travel", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;getPitch()F")) + private float hookModifyFallFlyingPitch(LivingEntity entity) { + Float pitch = RotationManager.getMovementPitch(); + if (entity != Lambda.getMc().player || pitch == null) return entity.getPitch(); + + return pitch; + } + + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;getYaw()F"), slice = @Slice(to = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;getYaw()F", ordinal = 1))) + private float rotBody(LivingEntity entity) { + if ((Object) this != Lambda.getMc().player) { + return entity.getYaw(); + } + + Float yaw = RotationManager.getRenderYaw(); + return (yaw == null) ? entity.getYaw() : yaw; + } + + @Redirect(method = "turnHead", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;getYaw()F")) + private float rotHead(LivingEntity entity) { + if ((Object) this != Lambda.getMc().player) { + return entity.getYaw(); + } + + Float yaw = RotationManager.getRenderYaw(); + return (yaw == null) ? entity.getYaw() : yaw; + } } diff --git a/common/src/main/kotlin/com/lambda/Loadable.kt b/common/src/main/kotlin/com/lambda/Loadable.kt index f18bd8bba..23218fd0c 100644 --- a/common/src/main/kotlin/com/lambda/Loadable.kt +++ b/common/src/main/kotlin/com/lambda/Loadable.kt @@ -1,5 +1,5 @@ package com.lambda interface Loadable { - fun load(): String + fun load() = this::class.simpleName?.let { "Loaded $it" } ?: "Loaded" } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/Loader.kt b/common/src/main/kotlin/com/lambda/Loader.kt index fb804ca99..ef4b2aab9 100644 --- a/common/src/main/kotlin/com/lambda/Loader.kt +++ b/common/src/main/kotlin/com/lambda/Loader.kt @@ -2,13 +2,15 @@ package com.lambda import com.lambda.Lambda.LOG import com.lambda.command.CommandManager +import com.lambda.manager.RotationManager import com.lambda.module.ModuleRegistry import kotlin.system.measureTimeMillis object Loader { private val loadables = listOf( ModuleRegistry, - CommandManager + CommandManager, + RotationManager ) fun initialize() { diff --git a/common/src/main/kotlin/com/lambda/config/InteractionSettings.kt b/common/src/main/kotlin/com/lambda/config/InteractionSettings.kt new file mode 100644 index 000000000..5ba20d004 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/config/InteractionSettings.kt @@ -0,0 +1,13 @@ +package com.lambda.config + +import com.lambda.manager.interaction.InteractionConfig +import com.lambda.util.world.raycast.RayCastMask + +class InteractionSettings( + c: Configurable, + vis: () -> Boolean = { true } +) : InteractionConfig { + override val reach by c.setting("Reach", 5.0, 0.1..10.0, 0.1, "Players reach / range", vis) + override val resolution by c.setting("Resolution", 10, 1..100, 1, "Raycast resolution", vis) + override val rayCastMask by c.setting("Raycast Mask", RayCastMask.BOTH, "What to raycast against", vis) +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/config/RotationSettings.kt b/common/src/main/kotlin/com/lambda/config/RotationSettings.kt new file mode 100644 index 000000000..bfa0c2ea4 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/config/RotationSettings.kt @@ -0,0 +1,29 @@ +package com.lambda.config + +import com.lambda.manager.rotation.IRotationConfig +import com.lambda.manager.rotation.RotationMode +import kotlin.random.Random + +class RotationSettings( + c: Configurable, + vis: () -> Boolean = { true } +) : IRotationConfig { + override val rotationMode by c.setting("Mode", RotationMode.LOCK, "SILENT - server-side rotation, SYNC - server-side rotation; client-side movement, LOCK - Lock camera", vis) + override val keepTicks by c.setting("Keep Rotation", 3, 1..10, 1, "Ticks to keep rotation", vis) + override val resetTicks by c.setting("Reset Rotation", 3, 1..10, 1, "Ticks before rotation is reset", vis) + + private val r1 by c.setting("Turn Speed 1", 70.0, 1.0..180.0, 0.1, "Rotation Speed 1", vis) + private val r2 by c.setting("Turn Speed 2", 110.0, 1.0..180.0, 0.1, "Rotation Speed 2", vis) + + override val turnSpeed get() = Random.nextDouble(r1, r2) + + var speedMultiplier = 1.0 + + fun slowdownIf(flag: Boolean) { + speedMultiplier = (if (flag) 0.0 else 1.0) + .coerceIn( + speedMultiplier - 0.3, // slowdown faster + speedMultiplier + 0.15 // accelerate slower + ) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt b/common/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt index 710388a4e..50553e401 100644 --- a/common/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt +++ b/common/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt @@ -1,7 +1,7 @@ package com.lambda.config.settings import com.lambda.config.AbstractSetting -import kotlin.math.round +import com.lambda.util.math.MathUtils.roundToStep import kotlin.reflect.KProperty /** @@ -33,19 +33,4 @@ abstract class NumericSetting( override operator fun setValue(thisRef: Any?, property: KProperty<*>, valueIn: T) { value = valueIn.coerceIn(range).roundToStep(step) } - - private fun T.roundToStep(step: T): T { - val doubleValue = this.toDouble() - val doubleStep = step.toDouble() - val result = round(doubleValue / doubleStep) * doubleStep - return when (this) { - is Byte -> result.toInt().toByte() - is Short -> result.toInt().toShort() - is Int -> result.toInt() - is Long -> result.toLong() - is Float -> result.toFloat() - is Double -> result - else -> throw IllegalArgumentException("Unsupported number type") - } as T - } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/event/EventFlow.kt b/common/src/main/kotlin/com/lambda/event/EventFlow.kt index f4de48cc5..ca7640eda 100644 --- a/common/src/main/kotlin/com/lambda/event/EventFlow.kt +++ b/common/src/main/kotlin/com/lambda/event/EventFlow.kt @@ -1,6 +1,7 @@ package com.lambda.event import com.lambda.Lambda.LOG +import com.lambda.event.cancellable.Cancellable import com.lambda.event.cancellable.ICancellable import com.lambda.event.listener.Listener import com.lambda.threading.runConcurrent @@ -85,6 +86,16 @@ object EventFlow { return cancellable } + fun post(cancellable: T, process: T.() -> Unit) where T : Event, T : ICancellable { + val event = post(cancellable) + process(event) + } + + fun postChecked(cancellable: T, process: T.() -> Unit) where T : Event, T : ICancellable { + val event = post(cancellable) + if (!event.isCanceled()) process(event) + } + /** * Unsubscribes from both synchronous and concurrent event flows for a specific [Event] type [T]. * diff --git a/common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt b/common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt new file mode 100644 index 000000000..5fc90eba7 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt @@ -0,0 +1,20 @@ +package com.lambda.event.events + +import com.lambda.event.Event +import com.lambda.event.cancellable.Cancellable +import com.lambda.event.cancellable.ICancellable +import com.lambda.manager.rotation.Rotation +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket +import net.minecraft.util.math.Vec3d + +abstract class PlayerPacketEvent : Event { + class Pre( + var position: Vec3d, + var rotation: Rotation, + var onGround: Boolean, + var isSprinting: Boolean + ) : PlayerPacketEvent(), ICancellable by Cancellable() + class Post( + val packet: PlayerMoveC2SPacket + ) : PlayerPacketEvent(), ICancellable by Cancellable() +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt b/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt new file mode 100644 index 000000000..0600a2491 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt @@ -0,0 +1,126 @@ +package com.lambda.event.events + +import com.lambda.config.RotationSettings +import com.lambda.event.Event +import com.lambda.event.cancellable.Cancellable +import com.lambda.event.cancellable.ICancellable +import com.lambda.manager.RotationManager +import com.lambda.manager.interaction.InteractionConfig +import com.lambda.manager.rotation.IRotationConfig +import com.lambda.manager.rotation.Rotation +import com.lambda.manager.rotation.Rotation.Companion.distance +import com.lambda.manager.rotation.Rotation.Companion.rotationTo +import com.lambda.manager.interaction.VisibilityChecker.scanVisibleSurfaces +import com.lambda.threading.runSafe +import com.lambda.util.math.VecUtils.distSq +import com.lambda.util.world.raycast.RayCastUtils.entityResult +import net.minecraft.entity.LivingEntity +import net.minecraft.util.hit.HitResult +import net.minecraft.util.math.Box +import java.util.* + +abstract class RotationEvent : Event { + class Pre : RotationEvent(), ICancellable by Cancellable() { + // Only one rotation can "win" each tick + val requests = TreeSet(Comparator.reverseOrder()) + + init { + // Always check if baritone wants to rotate as well + RotationManager.BaritoneProcessor.baritoneContext?.let { context -> + requests.add(RotationRequest(-1, context.config, context.rotation)) + } + } + + fun rotateTo( + config: IRotationConfig, + rotation: Rotation, + priority: Int = 0, + ) { + requests.add(RotationRequest(priority, config, rotation)) + } + + fun lookAt( + rotationConfig: IRotationConfig, + interact: InteractionConfig, + box: Box, + priority: Int = 0, + hitCheck: HitResult.() -> Boolean, + ) { + runSafe { + if (box.contains(player.eyePos)) { + stay(priority, rotationConfig) + return@runSafe + } + + val currentRotation = RotationManager.currentRotation + val currentCast = currentRotation.rayCast( + interact.reach, + interact.rayCastMask, + player.eyePos + ) + val check = currentCast?.let { it.hitCheck() } ?: false + +// Slowdown or freeze if looking correct + (rotationConfig as? RotationSettings)?.slowdownIf(check) ?: run { + if (check) stay(priority, rotationConfig) + return@runSafe + } + + val reachSq = interact.reach * interact.reach + + var closestRotation: Rotation? = null + var rotationDist = 0.0 + + scanVisibleSurfaces(box, interact.resolution) { vec -> + if (player.eyePos distSq vec > reachSq) return@scanVisibleSurfaces + + val newRotation = player.eyePos.rotationTo(vec) + + val cast = newRotation.rayCast( + interact.reach, + interact.rayCastMask, + player.eyePos + ) ?: return@scanVisibleSurfaces + if (!cast.hitCheck()) return@scanVisibleSurfaces + + val dist = newRotation.distance(currentRotation) + if (dist >= rotationDist && closestRotation != null) return@scanVisibleSurfaces + + rotationDist = dist + closestRotation = newRotation + } + + // Rotate to selected point + closestRotation?.let { rotation -> + requests.add(RotationRequest(priority, rotationConfig, rotation)) + } + } + + } + + fun lookAt( + rotationConfig: IRotationConfig, + interactionConfig: InteractionConfig, + entity: LivingEntity, + priority: Int = 0, + ) { + lookAt(rotationConfig, interactionConfig, entity.boundingBox, priority) { + entityResult?.entity == entity + } + } + + private fun stay(priority: Int = 0, config: IRotationConfig) { + requests.add(RotationRequest(priority, config, RotationManager.currentRotation)) + } + + data class RotationRequest( + val priority: Int, + val config: IRotationConfig, + val rotation: Rotation, + ) : Comparable { + override fun compareTo(other: RotationRequest) = + priority.compareTo(other.priority) + } + } + class Post : RotationEvent() +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt b/common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt new file mode 100644 index 000000000..870f659d7 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt @@ -0,0 +1,134 @@ +package com.lambda.manager + +import com.lambda.Loadable +import com.lambda.context.SafeContext +import com.lambda.event.EventFlow +import com.lambda.event.events.PlayerPacketEvent +import com.lambda.manager.rotation.Rotation +import com.lambda.threading.runSafe +import com.lambda.util.math.VecUtils.distSq +import com.lambda.util.player.MovementUtils.motionX +import com.lambda.util.player.MovementUtils.motionZ +import com.lambda.util.primitives.extension.component1 +import com.lambda.util.primitives.extension.component2 +import com.lambda.util.primitives.extension.component3 +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.* +import net.minecraft.util.math.MathHelper.square +import net.minecraft.util.math.Vec3d + +object PlayerPacketManager : Loadable { + private var prevPosition: Vec3d = Vec3d.ZERO + private var lastPosition = Vec3d(0.0, -1000.0, 0.0) + private var lastRotation = Rotation(0.0, -10000.0) + private var lastOnGround: Boolean? = null + private var lastSprinting: Boolean? = null + private var lastSneaking: Boolean? = null + private var sendTicks = 0 + + @JvmStatic + fun sendPlayerPackets() { + runSafe { + EventFlow.post(PlayerPacketEvent.Pre( + player.pos, + RotationManager.currentRotation, + player.isOnGround, + player.isSprinting + )) { + updatePlayerPackets(this) + } + } + } + + private fun SafeContext.updatePlayerPackets(event: PlayerPacketEvent.Pre) { + reportSprint(event.isSprinting) + reportSneak(player.isSneaking) + + if (mc.cameraEntity != player) return + + val position = event.position + val rotation = event.rotation + val ground = event.onGround + + RotationManager.currentRotation = rotation + + if (player.hasVehicle()) { + connection.sendPacket(Full( + player.motionX, + -999.0, + player.motionZ, + rotation.yaw.toFloat(), + rotation.pitch.toFloat(), + ground + )) + lastRotation = rotation + return + } + + val updatePosition = (position.subtract(lastPosition) distSq Vec3d.ZERO) > square(2.0E-4) || ++sendTicks >= 20 + val updateRotation = rotation != lastRotation + + val (x, y, z) = position + + val (yawD, pitchD) = rotation + val (yaw, pitch) = yawD.toFloat() to pitchD.toFloat() + + val packet = when { + updatePosition && updateRotation -> { + Full(x, y, z, yaw, pitch, ground) + } + updatePosition -> { + PositionAndOnGround(x, y, z, ground) + } + updateRotation -> { + LookAndOnGround(yaw, pitch, ground) + } + lastOnGround != ground -> { + OnGroundOnly(ground) + } + else -> null + } + + if (updatePosition) { + prevPosition = lastPosition + lastPosition = position + sendTicks = 0 + } + if (updateRotation) { + lastRotation = rotation + } + + lastOnGround = ground + + packet?.let { + EventFlow.postChecked(PlayerPacketEvent.Post(it)) { + connection.sendPacket(this.packet) + } + } + } + + private fun SafeContext.reportSprint(isSprinting: Boolean) { + if (lastSprinting == isSprinting) return + lastSprinting = isSprinting + + val state = if (isSprinting) { + ClientCommandC2SPacket.Mode.START_SPRINTING + } else { + ClientCommandC2SPacket.Mode.STOP_SPRINTING + } + + connection.sendPacket(ClientCommandC2SPacket(player, state)) + } + + private fun SafeContext.reportSneak(flag: Boolean) { + if (lastSneaking == flag) return + lastSneaking = flag + + val state = if (flag) ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY + else ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY + + connection.sendPacket(ClientCommandC2SPacket(player, state)) + } +} + + diff --git a/common/src/main/kotlin/com/lambda/manager/RotationManager.kt b/common/src/main/kotlin/com/lambda/manager/RotationManager.kt new file mode 100644 index 000000000..e7e3785f5 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/manager/RotationManager.kt @@ -0,0 +1,228 @@ +package com.lambda.manager + +import com.lambda.Lambda.mc +import com.lambda.Loadable +import com.lambda.config.RotationSettings +import com.lambda.event.EventFlow +import com.lambda.event.events.ConnectionEvent +import com.lambda.event.events.PacketEvent +import com.lambda.event.events.RotationEvent +import com.lambda.event.events.TickEvent +import com.lambda.event.listener.SafeListener.Companion.listener +import com.lambda.event.listener.UnsafeListener.Companion.unsafeListener +import com.lambda.manager.rotation.Rotation +import com.lambda.manager.rotation.Rotation.Companion.angleDifference +import com.lambda.manager.rotation.Rotation.Companion.fixSensitivity +import com.lambda.manager.rotation.Rotation.Companion.interpolate +import com.lambda.manager.rotation.RotationContext +import com.lambda.manager.rotation.RotationMode +import com.lambda.module.modules.client.Baritone +import com.lambda.threading.runOnGameThread +import com.lambda.threading.runSafe +import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.MathUtils.toRadian +import com.lambda.util.math.Vec2d +import com.lambda.util.primitives.extension.partialTicks +import net.minecraft.client.input.KeyboardInput +import net.minecraft.enchantment.EnchantmentHelper +import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket +import net.minecraft.util.math.MathHelper +import kotlin.math.* + +object RotationManager : Loadable { + var currentRotation = Rotation.ZERO + private var prevRotation = Rotation.ZERO + + @JvmStatic + fun update() = + runSafe { + EventFlow.post(RotationEvent.Pre()) { + rotate() + } + EventFlow.post(RotationEvent.Post()) + } + + var currentContext: RotationContext? = null + + private var keepTicks = 0 + private var pauseTicks = 0 + + private val smoothRotation get() = + lerp(prevRotation, currentRotation, mc.partialTicks) + + @JvmStatic val lockRotation get() = + if (currentContext?.config?.rotationMode == RotationMode.LOCK) smoothRotation else null + + @JvmStatic val renderYaw get() = + if (currentContext?.config == null) null else smoothRotation.yaw.toFloat() + + @JvmStatic val renderPitch get() = + if (currentContext?.config == null) null else smoothRotation.pitch.toFloat() + + @JvmStatic val handYaw get() = + if (currentContext?.config?.rotationMode == RotationMode.LOCK) currentRotation.yaw.toFloat() else null + + @JvmStatic val handPitch get() = + if (currentContext?.config?.rotationMode == RotationMode.LOCK) currentRotation.pitch.toFloat() else null + + @JvmStatic val movementYaw: Float? get() { + val config = currentContext?.config ?: return null + if (config.rotationMode == RotationMode.SILENT) return null + return currentRotation.yaw.toFloat() + } + + @JvmStatic val movementPitch: Float? get() { + val config = currentContext?.config ?: return null + if (config.rotationMode == RotationMode.SILENT) return null + return currentRotation.pitch.toFloat() + } + + @JvmStatic fun getRotationForVector(deltaTime: Double): Vec2d? { + val config = currentContext?.config ?: return null + if (config.rotationMode == RotationMode.SILENT) return null + + val rot = lerp(prevRotation, currentRotation, deltaTime) + return Vec2d(rot.yaw, rot.pitch) + } + + init { + listener { event -> + val packet = event.packet + if (packet !is PlayerPositionLookS2CPacket) return@listener + + runOnGameThread { + reset(Rotation(packet.yaw, packet.pitch)) + } + } + + unsafeListener { + reset(Rotation.ZERO) + } + } + + private fun RotationEvent.Pre.rotate() = runSafe { + prevRotation = currentRotation + + (keepTicks--).coerceAtLeast(0) + (pauseTicks--).coerceAtLeast(0) + + val resetTicks = currentContext?.config?.resetTicks ?: 0 + if (keepTicks + resetTicks < 0 || pauseTicks >= 0) { + currentContext = null + } + + requests.firstOrNull()?.let { + currentContext = RotationContext(it.config, it.rotation) + keepTicks = it.config.keepTicks + } + + currentRotation = Rotation(player.yaw, player.pitch) + + val data = currentContext ?: return@runSafe + val settings = data.config + + val rotationTo = if (keepTicks >= 0) data.rotation else currentRotation + + var speedMultiplier = (settings as? RotationSettings)?.speedMultiplier ?: 1.0 + if (keepTicks < 0) speedMultiplier = 1.0 + + val turnSpeed = settings.turnSpeed * speedMultiplier + + currentRotation = interpolate(prevRotation, rotationTo, turnSpeed) + .fixSensitivity(prevRotation) + + if (settings.rotationMode == RotationMode.LOCK) { + player.yaw = currentRotation.yaw.toFloat() + player.pitch = currentRotation.pitch.toFloat() + } + } + + private fun reset(rotation: Rotation) { + prevRotation = rotation + currentRotation = rotation + + currentContext = null + pauseTicks = 3 + } + + object BaritoneProcessor { + var baritoneContext: RotationContext? = null; private set + + private val movementYawList = arrayOf( + 0.0, 45.0, + 90.0, 135.0, + 180.0, 225.0, + 270.0, 315.0, + ) + + init { + listener { + baritoneContext = null + } + } + + @JvmStatic + fun handleBaritoneRotation(yaw: Float, pitch: Float) = runSafe { + baritoneContext = RotationContext(Baritone.rotation, Rotation(yaw, pitch)) + } + + @JvmStatic + fun processPlayerMovement() = runSafe { + val config = currentContext?.config ?: return@runSafe + + val input = player.input + val handledByBaritone = input !is KeyboardInput + + // Sign it to remove previous speed modifier + val signForward = sign(input.movementForward) + val signStrafe = sign(input.movementSideways) + + // No changes are needed when no inputs are pressed + if (signForward == 0f && signStrafe == 0f) return@runSafe + + // Movement speed modifier + val multiplier = if (!player.shouldSlowDown()) 1f else + (0.3f + EnchantmentHelper.getSwiftSneakSpeedBoost(player)).coerceIn(0f, 1f) + + // No changes are needed, when we don't modify the yaw used to move the player + if (config.rotationMode == RotationMode.SILENT) return@runSafe + + val modifyMovement = config.rotationMode == RotationMode.SYNC || handledByBaritone + if (!modifyMovement) return@runSafe + + val playerYaw = player.yaw.toDouble() + val baritoneYaw = if (handledByBaritone) baritoneContext?.rotation?.yaw else null + + // The yaw relative to which the movement was constructed + val movementYaw = baritoneYaw ?: playerYaw + + // Actual yaw used to move the player + val actualYaw = currentRotation.yaw + + val yawRad = (movementYaw - actualYaw).toRadian().toFloat() + + val cosDelta = MathHelper.cos(yawRad) + val sinDelta = MathHelper.sin(yawRad) + + val newX = signStrafe * cosDelta - signForward * sinDelta + val newZ = signForward * cosDelta + signStrafe * sinDelta + + // Apply new movement + input.movementSideways = newX.roundToInt().toFloat() * multiplier + input.movementForward = newZ.roundToInt().toFloat() * multiplier + + baritoneYaw ?: return@runSafe + + // Makes baritone movement safe + // when yaw difference is too big to compensate it by modifying keyboard input + val minYawDist = movementYawList + .map { currentRotation.yaw + it } // all possible movement directions (including diagonals) + .minOf { angleDifference(it, baritoneYaw) } + + if (minYawDist > 5.0) { + input.movementSideways = 0f + input.movementForward = 0f + } + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/manager/interaction/InteractionConfig.kt b/common/src/main/kotlin/com/lambda/manager/interaction/InteractionConfig.kt new file mode 100644 index 000000000..ee7a3ebbb --- /dev/null +++ b/common/src/main/kotlin/com/lambda/manager/interaction/InteractionConfig.kt @@ -0,0 +1,17 @@ +package com.lambda.manager.interaction + +import com.lambda.util.world.raycast.RayCastMask + +interface InteractionConfig { + /** + * Maximum distance to interact. + */ + val reach: Double + + /** + * Will check `resolution squared` many points on a grid on each visible surface of the hit box. + */ + val resolution: Int + + val rayCastMask: RayCastMask +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt b/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt new file mode 100644 index 000000000..16e0c68fc --- /dev/null +++ b/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt @@ -0,0 +1,71 @@ +package com.lambda.manager.interaction + +import com.lambda.context.SafeContext +import net.minecraft.util.math.* +import java.util.* + +object VisibilityChecker { + operator fun DoubleArray.component6() = this[5] + + inline fun SafeContext.scanVisibleSurfaces(box: Box, resolution: Int, check: (Vec3d) -> Unit) { + getVisibleSides(box).forEach { side -> + val shrunk = box.expand(-0.025) + val (minX, minY, minZ, maxX, maxY, maxZ) = shrunk.bounds(side) + val stepX = (maxX - minX) / resolution + val stepY = (maxY - minY) / resolution + val stepZ = (maxZ - minZ) / resolution + for (i in 0 .. resolution) { + for (j in 0 .. resolution) { + val x = if (stepX != 0.0) minX + stepX * i else minX + val y = if (stepY != 0.0) minY + stepY * j else minY + val z = if (stepZ != 0.0) minZ + stepZ * ((if (stepX != 0.0) j else i)) else minZ + check(Vec3d(x, y, z)) + } + } + } + } + + fun Box.bounds(side: Direction) = + when (side) { + Direction.DOWN -> doubleArrayOf(minX, minY, minZ, maxX, minY, maxZ) + Direction.UP -> doubleArrayOf(minX, maxY, minZ, maxX, maxY, maxZ) + Direction.NORTH -> doubleArrayOf(minX, minY, minZ, maxX, maxY, minZ) + Direction.SOUTH -> doubleArrayOf(minX, minY, maxZ, maxX, maxY, maxZ) + Direction.WEST -> doubleArrayOf(minX, minY, minZ, minX, maxY, maxZ) + Direction.EAST -> doubleArrayOf(maxX, minY, minZ, maxX, maxY, maxZ) + } + + fun SafeContext.getVisibleSides(box: Box): List { + val visibleSides = EnumSet.noneOf(Direction::class.java) + + val eyePos = player.eyePos + val center = box.center + + val halfX = box.lengthX / 2 + val halfY = box.lengthY / 2 + val halfZ = box.lengthZ / 2 + + return visibleSides + .checkAxis(eyePos.x - center.x, halfX, Direction.WEST, Direction.EAST) + .checkAxis(eyePos.y - center.y, halfY, Direction.DOWN, Direction.UP) + .checkAxis(eyePos.z - center.z, halfZ, Direction.NORTH, Direction.SOUTH) + .map { it } + } + + private fun EnumSet.checkAxis( + diff: Double, + limit: Double, + negativeSide: Direction, + positiveSide: Direction + ) = apply { + when { + diff < -limit -> { + add(negativeSide) + } + diff > limit -> { + add(positiveSide) + } + else -> {} + } + } +} diff --git a/common/src/main/kotlin/com/lambda/manager/rotation/IRotationConfig.kt b/common/src/main/kotlin/com/lambda/manager/rotation/IRotationConfig.kt new file mode 100644 index 000000000..a4e1cd921 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/manager/rotation/IRotationConfig.kt @@ -0,0 +1,25 @@ +package com.lambda.manager.rotation + +interface IRotationConfig { + /** + * - [RotationMode.SILENT] Spoofing server-side rotation. + * - [RotationMode.SYNC] Spoofing server-side rotation and adjusting client-side movement based on reported rotation (for Grim). + * - [RotationMode.LOCK] Locks the camera client-side. + */ + val rotationMode: RotationMode + + /** + * The rotation speed (in degrees). + */ + val turnSpeed: Double + + /** + * Ticks the rotation should not be changed. + */ + val keepTicks: Int + + /** + * Ticks to rotate back to the actual rotation. + */ + val resetTicks: Int +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/manager/rotation/Rotation.kt b/common/src/main/kotlin/com/lambda/manager/rotation/Rotation.kt new file mode 100644 index 000000000..a41ab23f5 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/manager/rotation/Rotation.kt @@ -0,0 +1,104 @@ +package com.lambda.manager.rotation + +import com.lambda.threading.runSafe +import com.lambda.util.math.MathUtils.toDegree +import com.lambda.util.math.MathUtils.toRadian +import com.lambda.util.world.raycast.RayCastMask +import com.lambda.util.world.raycast.RayCastUtils.rayCast +import net.minecraft.client.MinecraftClient +import net.minecraft.util.math.Direction +import net.minecraft.util.math.MathHelper +import net.minecraft.util.math.Vec3d +import kotlin.math.* + +data class Rotation(val yaw: Double, val pitch: Double) { + constructor(yaw: Float, pitch: Float) : this(yaw.toDouble(), pitch.toDouble()) + + private val rotationVector: Vec3d get() { + val yawRad = -yaw.toRadian() + val pitchRad = pitch.toRadian() + + return Vec3d(sin(yawRad), -1.0, cos(yawRad)) + .multiply(Vec3d(cos(pitchRad), sin(pitchRad), cos(pitchRad))) + } + + fun rayCast( + reach: Double, + mask: RayCastMask = RayCastMask.BOTH, + eye: Vec3d? = null, + fluids: Boolean = false + ) = runSafe { + rayCast(eye ?: player.eyePos, rotationVector, reach, mask, fluids) + } + + val Direction.yaw: Float + get() = when (this) { + Direction.NORTH -> -180.0f + Direction.SOUTH -> 0.0f + Direction.EAST -> -90.0f + Direction.WEST -> 90.0f + else -> 0.0f + } + + companion object { + val ZERO = Rotation(0.0, 0.0) + val DOWN = Rotation(0.0, 90.0) + + private fun wrap(deg: Double) = MathHelper.wrapDegrees(deg) + + fun interpolate(a: Rotation, b: Rotation, speed: Double): Rotation { + val yawDiff = wrap(b.yaw - a.yaw) + val pitchDiff = wrap(b.pitch - a.pitch) + + val diff = hypot(yawDiff, pitchDiff) + + val yawSpeed = abs(yawDiff / diff) * speed + val pitchSpeed = abs(pitchDiff / diff) * speed + + val yaw = a.yaw + yawDiff.coerceIn(-yawSpeed, yawSpeed) + val pitch = a.pitch + pitchDiff.coerceIn(-pitchSpeed, pitchSpeed) + + return Rotation(yaw, pitch) + } + + fun Rotation.fixSensitivity(last: Rotation): Rotation { + val mc = MinecraftClient.getInstance() + val f = mc.options.mouseSensitivity.value * 0.6 + 0.2 + val step = f * f * f * 8.0 * 0.15F + + val deltaYaw = yaw - last.yaw + var fixedYaw = (deltaYaw / step).roundToInt() * step + fixedYaw += last.yaw + + val deltaPitch = pitch - last.pitch + var fixedPitch = (deltaPitch / step).roundToInt() * step + fixedPitch += last.pitch + fixedPitch = fixedPitch.coerceIn(-90.0, 90.0) + + return Rotation(fixedYaw, fixedPitch) + } + + fun Vec3d.rotationTo(vec: Vec3d): Rotation { + val diffX = vec.x - x + val diffY = vec.y - y + val diffZ = vec.z - z + + val yawRad = atan2(diffZ, diffX) + val pitchRad = -atan2(diffY, hypot(diffX, diffZ)) + + val yaw = wrap(yawRad.toDegree() - 90.0) + val pitch = wrap(pitchRad.toDegree()) + + return Rotation(yaw, pitch) + } + + fun Rotation.distance(b: Rotation) = + hypot( + wrap(yaw - b.yaw), + wrap(pitch - b.pitch) + ) + + fun angleDifference(a: Double, b: Double) = + abs(wrap(a - b)) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/manager/rotation/RotationContext.kt b/common/src/main/kotlin/com/lambda/manager/rotation/RotationContext.kt new file mode 100644 index 000000000..cd35b74e2 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/manager/rotation/RotationContext.kt @@ -0,0 +1,6 @@ +package com.lambda.manager.rotation + +data class RotationContext( + val config: IRotationConfig, + val rotation: Rotation +) \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/manager/rotation/RotationMode.kt b/common/src/main/kotlin/com/lambda/manager/rotation/RotationMode.kt new file mode 100644 index 000000000..4b2f74f2c --- /dev/null +++ b/common/src/main/kotlin/com/lambda/manager/rotation/RotationMode.kt @@ -0,0 +1,12 @@ +package com.lambda.manager.rotation + +/** + * @property SILENT Spoofing server-side rotation. + * @property SYNC Spoofing server-side rotation and adjusting client-side movement based on reported rotation (for Grim). + * @property LOCK Locks the camera client-side. + */ +enum class RotationMode { + SILENT, + SYNC, + LOCK +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/BoringModule.kt b/common/src/main/kotlin/com/lambda/module/modules/BoringModule.kt index 2bd6b90fe..12261ffbf 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/BoringModule.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/BoringModule.kt @@ -5,8 +5,6 @@ import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.info -import com.lambda.util.Communication.toast import com.lambda.util.KeyCode import net.minecraft.util.math.BlockPos import java.awt.Color diff --git a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt b/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt new file mode 100644 index 000000000..cc53e7ca0 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt @@ -0,0 +1,28 @@ +package com.lambda.module.modules + +import com.lambda.config.InteractionSettings +import com.lambda.config.RotationSettings +import com.lambda.event.events.RotationEvent +import com.lambda.event.listener.SafeListener.Companion.listener +import com.lambda.module.Module +import com.lambda.util.world.EntityUtils.getClosestEntity +import net.minecraft.entity.passive.VillagerEntity + +object RotationTest : Module( + name = "RotationTest", + description = "Test rotation", + defaultTags = setOf() +) { + private val rotationConfig = RotationSettings(this) + private val interactionConfig = InteractionSettings(this) + + init { + listener { + val target = getClosestEntity( + player.eyePos, interaction.reachDistance.toDouble() + ) ?: return@listener + + it.lookAt(rotationConfig, interactionConfig, target) + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt b/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt new file mode 100644 index 000000000..81846a2d1 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt @@ -0,0 +1,23 @@ +package com.lambda.module.modules.client + +import com.lambda.manager.rotation.IRotationConfig +import com.lambda.manager.rotation.RotationMode +import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag +import com.lambda.util.math.MathUtils.random + +object Baritone : Module( + name = "Baritone", + description = "Baritone configuration", + defaultTags = setOf(ModuleTag.CLIENT) +) { + private val r1 by setting("Turn Speed 1", 70.0, 1.0..180.0, 0.1) + private val r2 by setting("Turn Speed 2", 110.0, 1.0..180.0, 0.1) + + val rotation = object : IRotationConfig { + override val rotationMode = RotationMode.SYNC + override val turnSpeed get() = random(r1, r2) + override val keepTicks = 3 + override val resetTicks = 3 + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/math/ColorUtils.kt b/common/src/main/kotlin/com/lambda/util/math/ColorUtils.kt new file mode 100644 index 000000000..4e8b10f1e --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/math/ColorUtils.kt @@ -0,0 +1,16 @@ +package com.lambda.util.math + +import java.awt.Color + +object ColorUtils { + fun Color.setAlpha(value: Double) = + Color(red, green, blue, (value * 255.0).coerceIn(0.0, 255.0).toInt()) + + fun Color.multAlpha(value: Double) = + Color(red, green, blue, (value * alpha).coerceIn(0.0, 255.0).toInt()) + + val Color.r get() = red.toDouble() / 255.0 + val Color.g get() = green.toDouble() / 255.0 + val Color.b get() = blue.toDouble() / 255.0 + val Color.a get() = alpha.toDouble() / 255.0 +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt b/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt new file mode 100644 index 000000000..9be0dd030 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt @@ -0,0 +1,142 @@ +package com.lambda.util.math + +import com.lambda.manager.rotation.Rotation +import com.lambda.util.math.ColorUtils.a +import com.lambda.util.math.ColorUtils.b +import com.lambda.util.math.ColorUtils.g +import com.lambda.util.math.ColorUtils.r +import net.minecraft.util.math.Vec3d +import java.awt.Color +import java.math.BigDecimal +import java.math.RoundingMode +import kotlin.math.* +import kotlin.random.Random.Default.nextDouble + +object MathUtils { + private const val PI_FLOAT = 3.141593f + + fun Float.toRadian() = this / 180.0f * PI_FLOAT + + fun Double.toRadian() = this / 180.0 * PI + + fun Float.toDegree() = this * 180.0f / PI_FLOAT + + fun Double.toDegree() = this * 180.0 / PI + + fun Boolean.toInt() = if (this) 1 else 0 + + fun Boolean.toIntSign() = if (this) 1 else -1 + + fun Double.floorToInt() = floor(this).toInt() + + fun Double.ceilToInt() = ceil(this).toInt() + + fun T.roundToStep(step: T): T { + val stepD = step.toDouble() + var value = round(toDouble() / stepD) * stepD + value = value.roundToPlaces(decimalPlaces(stepD)) + if (abs(value) == 0.0) value = 0.0 + + return typeConvert(value) + } + + fun Double.roundToPlaces(places: Int) = + BigDecimal(this).setScale(places, RoundingMode.HALF_EVEN).toDouble() + + fun T.typeConvert(valueIn: Double): T { + @Suppress("UNCHECKED_CAST") + return when(this) { + is Byte -> valueIn.toInt().toByte() + is Short -> valueIn.toInt().toShort() + is Double -> valueIn + is Float -> valueIn.toFloat() + is Int -> valueIn.toInt() + is Long -> valueIn.toLong() + else -> throw IllegalArgumentException("Unsupported number type") + } as T + } + + private fun decimalPlaces(value: Double) = BigDecimal.valueOf(value).scale() + + fun random(v1: Double, v2: Double): Double { + val min = min(v1, v2) + val max = max(v1, v2) + return nextDouble(min, max) + } + + /** + * @return The smallest power of two that is greater than or equal to the input integer. + */ + fun Int.ceilToPOT(): Int { + var i = this + i-- + i = i or (i shr 1) + i = i or (i shr 2) + i = i or (i shr 4) + i = i or (i shr 8) + i = i or (i shr 16) + return ++i + } + + inline val Int.sq: Int get() = this * this + + /** + * Performs linear interpolation between two Float values. + * + * This function calculates the value at a specific point + * between [start] and [end] based on the interpolation factor [factor]. + * The interpolation factor [factor] is clamped between zero + * and one to ensure the result stays within the range of [start] and [end]. + * + * @param start The start value. + * @param end The end value. + * @param factor The interpolation factor, typically between 0 (representing [start]) and 1 (representing [end]). + * @return The interpolated value between [start] and [end]. + */ + fun lerp(start: Float, end: Float, factor: Float) = + start + ((end - start) * factor.coerceIn(0f, 1f)) + + /** + * Performs linear interpolation between two Double values. + * + * This function calculates the value at a specific point + * between [start] and [end] based on the interpolation factor [factor]. + * The interpolation factor [factor] is clamped between zero + * and one to ensure the result stays within the range of [start] and [end]. + * + * @param start The start value. + * @param end The end value. + * @param factor The interpolation factor, typically between 0 (representing [start]) and 1 (representing [end]). + * @return The interpolated value between [start] and [end]. + */ + fun lerp(start: Double, end: Double, factor: Double) = + start + ((end - start) * factor.coerceIn(0.0, 1.0)) + + fun lerp(start: Vec3d, end: Vec3d, factor: Double) = + Vec3d( + lerp(start.x, end.x, factor), + lerp(start.y, end.y, factor), + lerp(start.z, end.z, factor) + ) + + fun lerp(start: Vec2d, end: Vec2d, factor: Double) = + Vec2d( + lerp(start.x, end.x, factor), + lerp(start.y, end.y, factor) + ) + + + fun lerp(start: Rotation, end: Rotation, factor: Double) = + Rotation( + lerp(start.yaw, end.yaw, factor), + lerp(start.pitch, end.pitch, factor) + ) + + fun lerp(c1: Color, c2: Color, p: Double) = + Color( + lerp(c1.r, c2.r, p).toFloat(), + lerp(c1.g, c2.g, p).toFloat(), + lerp(c1.b, c2.b, p).toFloat(), + lerp(c1.a, c2.a, p).toFloat() + ) +} diff --git a/common/src/main/kotlin/com/lambda/util/math/Range.kt b/common/src/main/kotlin/com/lambda/util/math/Range.kt new file mode 100644 index 000000000..3e11ab6ea --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/math/Range.kt @@ -0,0 +1,101 @@ +package com.lambda.util.math + +import net.minecraft.util.math.Box +import java.util.Random +import java.util.concurrent.ThreadLocalRandom +import kotlin.random.Random.Default.nextDouble + +class DoubleRange( + override val start: Double, + override val endInclusive: Double +) : ClosedRange { + infix fun step(step: Double): DoubleIterator { + return object : DoubleIterator() { + private var next = start + override fun hasNext() = next <= endInclusive + override fun nextDouble() = next.also { next += step } + } + } + + /** + * Returns a random value within the range. + */ + fun random() = nextDouble(start, endInclusive) + + /** + * Returns a bounding box from two additional ranges. + * @param y The second range. + * @param z The third range. + * @return The bounding box. + */ + fun box(y: DoubleRange, z: DoubleRange) = + Box(this.start, y.start, z.start, this.endInclusive, y.endInclusive, z.endInclusive) +} + +infix fun Double.to(that: Double) = DoubleRange(this, that) + +/** + * Converts a value from one range to a normalized value between 0 and 1. + */ +fun ClosedRange.normalized(value: T): T where T : Comparable, T : Number = scale(value, 0.0 as T, 1.0 as T) // hacky + +/** + * Inverts the range. + */ +fun ClosedRange.inverted(): ClosedRange where T : Comparable, T : Number = endInclusive..start + +/** + * Converts a value from one range to another while keeping the ratio using exponential interpolation. + * @param value The value to convert. + * @param minIn The minimum of the new range. + * @param maxIn The maximum of the new range. + * @return The converted value. + */ +fun ClosedRange.scale(value: T, minIn: T, maxIn: T): T where T : Comparable, T : Number = + transform(value, start, endInclusive, minIn, maxIn) + +/** + * Converts a value from one range to another while keeping the ratio using exponential interpolation. + * @param value The value to convert. + * @param x1 The minimum of the old range. + * @param y1 The maximum of the old range. + * @param x2 The minimum of the new range. + * @param y2 The maximum of the new range. + * @return The converted value. + * @see Linear Interpolation + */ +fun transform(value: T, x1: T, y1: T, x2: T, y2: T): T where T : Comparable, T : Number = + x2 + (value - x1) * ((y2 - x2) / (y1 - x1)) + + +/** + * Clamps a value to the range. + * @param value The value to clamp. + * @return The clamped value. + */ +fun > ClosedRange.coerceIn(value: T) = value.coerceIn(start, endInclusive) +fun > T.coerceIn(range: ClosedRange) = range.coerceIn(this) + +private operator fun T.minus(oldMin: T): T where T : Comparable, T : Number { + return (this.toDouble() - oldMin.toDouble()) as T +} + +private operator fun T.div(other: T): T where T : Comparable, T : Number { + return (this.toDouble() / other.toDouble()) as T +} + +private operator fun T.times(other: T): T where T : Comparable, T : Number { + return (this.toDouble() * other.toDouble()) as T +} + +private operator fun T.plus(other: T): T where T : Comparable, T : Number { + return (this.toDouble() + other.toDouble()) as T +} + +fun min(newMin: T, newMax: T): T where T : Comparable, T : Number { + return if (newMin < newMax) newMin else newMax +} + +fun max(newMin: T, newMax: T): T where T : Comparable, T : Number { + return if (newMin > newMax) newMin else newMax +} diff --git a/common/src/main/kotlin/com/lambda/util/math/Vec2d.kt b/common/src/main/kotlin/com/lambda/util/math/Vec2d.kt new file mode 100644 index 000000000..a88e90ea0 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/math/Vec2d.kt @@ -0,0 +1,47 @@ +package com.lambda.util.math + +import net.minecraft.util.math.Vec2f +import kotlin.math.roundToInt + +data class Vec2d(val x: Double, val y: Double) { + constructor(x: Int, y: Int) : this(x.toDouble(), y.toDouble()) + constructor(x: Float, y: Float) : this(x.toDouble(), y.toDouble()) + constructor(x: Short, y: Short) : this(x.toDouble(), y.toDouble()) + + operator fun plus(vec2d: Vec2d) = plus(vec2d.x, vec2d.y) + + operator fun plus(add: Double) = plus(add, add) + + fun plus(x: Double, y: Double) = Vec2d(this.x + x, this.y + y) + + operator fun minus(vec2d: Vec2d) = minus(vec2d.x, vec2d.y) + + operator fun minus(sub: Double) = minus(sub, sub) + + fun minus(x: Double, y: Double) = plus(-x, -y) + + operator fun times(vec2d: Vec2d) = times(vec2d.x, vec2d.y) + + operator fun times(multiplier: Double) = times(multiplier, multiplier) + + fun times(x: Double, y: Double) = Vec2d(this.x * x, this.y * y) + + operator fun div(vec2d: Vec2d) = div(vec2d.x, vec2d.y) + + operator fun div(divider: Double) = div(divider, divider) + + fun div(x: Double, y: Double) = Vec2d(this.x / x, this.y / y) + + val vec2f = Vec2f(x.toFloat(), y.toFloat()) + val rounded get() = Vec2d(x.roundToInt(), y.roundToInt()) + + companion object { + val ZERO: Vec2d = Vec2d(0.0, 0.0) + val ONE: Vec2d = Vec2d(1.0, 1.0) + + val RIGHT: Vec2d = Vec2d(1.0, 0.0) + val LEFT: Vec2d = Vec2d(-1.0, 0.0) + val TOP: Vec2d = Vec2d(0.0, 1.0) + val BOTTOM: Vec2d = Vec2d(0.0, -1.0) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/math/VecUtils.kt b/common/src/main/kotlin/com/lambda/util/math/VecUtils.kt new file mode 100644 index 000000000..9f320d1a0 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/math/VecUtils.kt @@ -0,0 +1,42 @@ +package com.lambda.util.math + +import com.lambda.context.SafeContext +import com.lambda.util.math.MathUtils.sq +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Box +import net.minecraft.util.math.Direction +import net.minecraft.util.math.Vec3d +import net.minecraft.util.math.Vec3i +import java.util.* + +object VecUtils { + infix fun Vec3d.dist(other: Vec3d) = + this.distanceTo(other) + + infix fun Vec3d.distSq(other: Vec3d) = + this.squaredDistanceTo(other) + + infix fun Vec3i.distSq(other: Vec3d) = + Vec3d.of(this) distSq other + + infix fun Vec3i.distSq(other: Vec3i) = + (this.x - other.x).sq + (this.y - other.y).sq + (this.z - other.z).sq + + infix operator fun Vec3d.plus(other: Vec3d) = + this.add(other) + + infix operator fun Vec3d.minus(other: Vec3d) = + this.subtract(other) + + infix operator fun Vec3d.times(other: Vec3d) = + this.multiply(other) + + infix operator fun Vec3d.div(other: Vec3d) = + this.multiply(1.0 / other.x, 1.0 / other.y, 1.0 / other.z) + + infix operator fun Vec3d.times(other: Double) = + this.multiply(other) + + infix operator fun Vec3d.div(other: Double) = + this.multiply(1.0 / other) +} diff --git a/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt new file mode 100644 index 000000000..2cad65113 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt @@ -0,0 +1,78 @@ +package com.lambda.util.player + +import com.lambda.context.SafeContext +import com.lambda.manager.RotationManager +import com.lambda.util.math.MathUtils.random +import com.lambda.util.math.MathUtils.toInt +import com.lambda.util.math.MathUtils.toRadian +import net.minecraft.client.input.Input +import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.entity.Entity +import net.minecraft.util.math.Vec3d +import kotlin.math.cos +import kotlin.math.hypot +import kotlin.math.sign +import kotlin.math.sin + +object MovementUtils { + private val SafeContext.roundedForward get() = sign(player.input.movementForward) + private val SafeContext.roundedStrafing get() = sign(player.input.movementSideways) + + fun Input.cancel() { + movementForward = 0f + movementSideways = 0f + + pressingForward = false + pressingBack = false + pressingLeft = false + pressingRight = false + } + + val SafeContext.isInputting: Boolean get() = + roundedForward != 0f || roundedStrafing != 0f + + val SafeContext.verticalMovement get() = + player.input.jumping.toInt() - player.input.sneaking.toInt() + + fun SafeContext.calcMoveYaw(yawIn: Float = player.moveYaw, moveForward: Float = roundedForward, moveStrafe: Float = roundedStrafing): Double { + var strafe = 90 * moveStrafe + strafe *= if (moveForward != 0F) moveForward * 0.5F else 1F + + var yaw = yawIn - strafe + yaw -= if (moveForward < 0F) 180 else 0 + + return yaw.toDouble() + } + + fun SafeContext.calcMoveRad() = calcMoveYaw().toRadian() + + fun randomDirection() = random(-180.0, 180.0).toRadian() + + fun SafeContext.movementDirection(radDir: Double = calcMoveRad()) = + Vec3d(-sin(radDir), 0.0, cos(radDir)) + + var Entity.motionX get() = velocity.x; set(value) = setVelocity(value, velocity.y, velocity.z) + var Entity.motionY get() = velocity.y; set(value) = setVelocity(velocity.x, value, velocity.z) + var Entity.motionZ get() = velocity.z; set(value) = setVelocity(velocity.x, velocity.y, value) + + fun SafeContext.setSpeed(speed: Double, direction: Double = calcMoveRad()) { + player.motionX = -sin(direction) * speed + player.motionZ = cos(direction) * speed + } + + fun SafeContext.addSpeed(speed: Double, direction: Double = calcMoveRad()) { + player.motionX -= sin(direction) * speed + player.motionZ += cos(direction) * speed + } + + fun SafeContext.mulSpeed(modifier: Double) { + player.motionX *= modifier + player.motionZ *= modifier + } + + val ClientPlayerEntity.moveYaw get() = RotationManager.movementYaw ?: yaw + + val Entity.moveDiff get() = Vec3d(this.pos.x - this.prevX, this.pos.y - this.prevY, this.pos.z - this.prevZ) + val Entity.moveDelta get() = moveDiff.let { hypot(it.x, it.z) } + val Entity.motionDelta get() = hypot(this.velocity.x, this.velocity.z) +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/primitives/extension/Components.kt b/common/src/main/kotlin/com/lambda/util/primitives/extension/Components.kt new file mode 100644 index 000000000..ea0b36f5f --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/primitives/extension/Components.kt @@ -0,0 +1,10 @@ +package com.lambda.util.primitives.extension + +import net.minecraft.util.math.Vec2f +import net.minecraft.util.math.Vec3d + +operator fun Vec2f.component1() = this.x +operator fun Vec2f.component2() = this.y +operator fun Vec3d.component1() = this.x +operator fun Vec3d.component2() = this.y +operator fun Vec3d.component3() = this.z \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/primitives/extension/Entity.kt b/common/src/main/kotlin/com/lambda/util/primitives/extension/Entity.kt new file mode 100644 index 000000000..32fd32bfb --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/primitives/extension/Entity.kt @@ -0,0 +1,24 @@ +package com.lambda.util.primitives.extension + +import com.lambda.util.math.MathUtils.lerp +import net.minecraft.client.MinecraftClient +import net.minecraft.entity.Entity +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d + +val Entity.prevPos + get() = Vec3d(prevX, prevY, prevZ) + +val Entity.interpolatedPos + get() = lerp(prevPos, pos, MinecraftClient.getInstance().partialTicks) + +val Entity.interpolatedBox: Box + get() { + val box = boundingBox + val xw = (box.maxX - box.minX) * 0.5 + val yw = box.maxY - box.minY + val zw = (box.maxZ - box.minZ) * 0.5 + + val pos = interpolatedPos + return Box(pos.x - xw, pos.y, pos.z - zw, pos.x + xw, pos.y + yw, pos.z + zw) + } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/primitives/extension/Mixin.kt b/common/src/main/kotlin/com/lambda/util/primitives/extension/Mixin.kt new file mode 100644 index 000000000..7bf7e675d --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/primitives/extension/Mixin.kt @@ -0,0 +1,6 @@ +package com.lambda.util.primitives.extension + +import net.minecraft.client.MinecraftClient + +val MinecraftClient.partialTicks + get() = (if (paused) pausedTickDelta else tickDelta).toDouble() \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/world/EntityUtils.kt b/common/src/main/kotlin/com/lambda/util/world/EntityUtils.kt index 2732b1787..aba0bc729 100644 --- a/common/src/main/kotlin/com/lambda/util/world/EntityUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/world/EntityUtils.kt @@ -44,7 +44,7 @@ object EntityUtils { // Here we iterate over all sections within the specified distance and add all entities of type [T] to the list. // We do not have to worry about performance here, as the number of sections is very limited. - // For example if the player is on the edge of a section and the distance is 16, we only have to iterate over 9 sections. + // For example, if the player is on the edge of a section and the distance is 16, we only have to iterate over 9 sections. for (x in sectionX - chunks..sectionX + chunks) { for (y in sectionY - chunks..sectionY + chunks) { for (z in sectionZ - chunks..sectionZ + chunks) { diff --git a/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastMask.kt b/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastMask.kt new file mode 100644 index 000000000..2f5ea39df --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastMask.kt @@ -0,0 +1,7 @@ +package com.lambda.util.world.raycast + +enum class RayCastMask(val block: Boolean, val entity: Boolean) { + BOTH(true, true), + BLOCK(true, false), + ENTITY(false, true) +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt b/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt new file mode 100644 index 000000000..29f0c34d6 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt @@ -0,0 +1,67 @@ +package com.lambda.util.world.raycast + +import com.lambda.context.SafeContext +import com.lambda.manager.rotation.Rotation +import com.lambda.threading.runSafe +import com.lambda.util.math.VecUtils.distSq +import net.minecraft.entity.Entity +import net.minecraft.entity.projectile.ProjectileUtil.raycast +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.hit.EntityHitResult +import net.minecraft.util.hit.HitResult +import net.minecraft.util.math.Vec3d +import net.minecraft.world.RaycastContext +import kotlin.math.max + +object RayCastUtils { + private val entityPredicate = { entity: Entity -> !entity.isSpectator && entity.canHit() } + + fun SafeContext.rayCast( + pos: Vec3d, + dir: Vec3d, + reach: Double, + mask: RayCastMask, + fluids: Boolean = false + ): HitResult? { + val vec = dir.multiply(reach) + val point = pos.add(vec) + + val block = run { + if (!mask.block) return@run null + + val fluidHandling = if (fluids) RaycastContext.FluidHandling.ANY else RaycastContext.FluidHandling.NONE + val context = RaycastContext(pos, point, RaycastContext.ShapeType.OUTLINE, fluidHandling, player) + val block = world.raycast(context) + + block?.blockResult + } + + val entity = run { + if (!mask.entity) return@run null + + val box = player.boundingBox.stretch(vec).expand(1.0) + val entity = raycast(player, pos, point, box, entityPredicate, reach * reach) + + entity?.entityResult + } + + return listOfNotNull(block, entity).minByOrNull { pos distSq it.pos } + } + + fun distanceToGround(maxDist: Double = 100.0) = runSafe { + val pos = player.pos.add(0.0, 0.1, 0.0) + val cast = Rotation.DOWN.rayCast(maxDist, RayCastMask.BLOCK, pos, false) ?: return@runSafe maxDist + + return@runSafe max(0.0, pos.y - cast.pos.y) + } + + val HitResult.entityResult: EntityHitResult? get() { + if (type == HitResult.Type.MISS) return null + return this as? EntityHitResult + } + + val HitResult.blockResult: BlockHitResult? get() { + if (type == HitResult.Type.MISS) return null + return this as? BlockHitResult + } +} \ No newline at end of file diff --git a/common/src/main/resources/lambda.accesswidener b/common/src/main/resources/lambda.accesswidener index e224d5616..dc5a5cd89 100644 --- a/common/src/main/resources/lambda.accesswidener +++ b/common/src/main/resources/lambda.accesswidener @@ -2,6 +2,8 @@ accessWidener v2 named # MC accessible field net/minecraft/client/MinecraftClient itemUseCooldown I accessible field net/minecraft/client/MinecraftClient attackCooldown I +accessible field net/minecraft/client/MinecraftClient paused Z +accessible field net/minecraft/client/MinecraftClient pausedTickDelta F # World accessible field net/minecraft/client/world/ClientWorld entityManager Lnet/minecraft/client/world/ClientEntityManager; diff --git a/common/src/main/resources/lambda.mixins.common.json b/common/src/main/resources/lambda.mixins.common.json index 2fe2ee6a4..eafbb76a9 100644 --- a/common/src/main/resources/lambda.mixins.common.json +++ b/common/src/main/resources/lambda.mixins.common.json @@ -7,6 +7,7 @@ "ChatInputSuggestorMixin", "ChatScreenMixin", "ClientConnectionMixin", + "DebugHudMixin", "KeyBindingMixin", "KeyboardMixin", "MinecraftClientMixin", From 1b75d99fbce998f709f9e01854feeebf7fa99563 Mon Sep 17 00:00:00 2001 From: Constructor Date: Wed, 20 Mar 2024 18:29:13 +0100 Subject: [PATCH 4/7] Runtime optimizations --- .../java/com/lambda/mixin/DebugHudMixin.java | 1 - .../main/kotlin/com/lambda/event/EventFlow.kt | 2 ++ .../manager/interaction/VisibilityChecker.kt | 17 ++++++----------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/com/lambda/mixin/DebugHudMixin.java b/common/src/main/java/com/lambda/mixin/DebugHudMixin.java index e541234a2..fe5827a1e 100644 --- a/common/src/main/java/com/lambda/mixin/DebugHudMixin.java +++ b/common/src/main/java/com/lambda/mixin/DebugHudMixin.java @@ -17,7 +17,6 @@ public class DebugHudMixin { @Inject(method = "getRightText", at = @At(value = "TAIL")) private void onGetRightText(CallbackInfoReturnable> cir) { - if (Lambda.getMc().crosshairTarget == null) return; HitResult hitResult = Lambda.getMc().crosshairTarget; List list = cir.getReturnValue(); diff --git a/common/src/main/kotlin/com/lambda/event/EventFlow.kt b/common/src/main/kotlin/com/lambda/event/EventFlow.kt index ca7640eda..9e6f8705b 100644 --- a/common/src/main/kotlin/com/lambda/event/EventFlow.kt +++ b/common/src/main/kotlin/com/lambda/event/EventFlow.kt @@ -86,11 +86,13 @@ object EventFlow { return cancellable } + @JvmStatic fun post(cancellable: T, process: T.() -> Unit) where T : Event, T : ICancellable { val event = post(cancellable) process(event) } + @JvmStatic fun postChecked(cancellable: T, process: T.() -> Unit) where T : Event, T : ICancellable { val event = post(cancellable) if (!event.isCanceled()) process(event) diff --git a/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt b/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt index 16e0c68fc..38958e337 100644 --- a/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt +++ b/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt @@ -8,15 +8,15 @@ object VisibilityChecker { operator fun DoubleArray.component6() = this[5] inline fun SafeContext.scanVisibleSurfaces(box: Box, resolution: Int, check: (Vec3d) -> Unit) { + val shrunk = box.expand(-0.025) getVisibleSides(box).forEach { side -> - val shrunk = box.expand(-0.025) val (minX, minY, minZ, maxX, maxY, maxZ) = shrunk.bounds(side) val stepX = (maxX - minX) / resolution val stepY = (maxY - minY) / resolution val stepZ = (maxZ - minZ) / resolution for (i in 0 .. resolution) { + val x = if (stepX != 0.0) minX + stepX * i else minX for (j in 0 .. resolution) { - val x = if (stepX != 0.0) minX + stepX * i else minX val y = if (stepY != 0.0) minY + stepY * j else minY val z = if (stepZ != 0.0) minZ + stepZ * ((if (stepX != 0.0) j else i)) else minZ check(Vec3d(x, y, z)) @@ -35,21 +35,16 @@ object VisibilityChecker { Direction.EAST -> doubleArrayOf(maxX, minY, minZ, maxX, maxY, maxZ) } - fun SafeContext.getVisibleSides(box: Box): List { + fun SafeContext.getVisibleSides(box: Box): Set { val visibleSides = EnumSet.noneOf(Direction::class.java) val eyePos = player.eyePos val center = box.center - val halfX = box.lengthX / 2 - val halfY = box.lengthY / 2 - val halfZ = box.lengthZ / 2 - return visibleSides - .checkAxis(eyePos.x - center.x, halfX, Direction.WEST, Direction.EAST) - .checkAxis(eyePos.y - center.y, halfY, Direction.DOWN, Direction.UP) - .checkAxis(eyePos.z - center.z, halfZ, Direction.NORTH, Direction.SOUTH) - .map { it } + .checkAxis(eyePos.x - center.x, box.lengthX / 2, Direction.WEST, Direction.EAST) + .checkAxis(eyePos.y - center.y, box.lengthY / 2, Direction.DOWN, Direction.UP) + .checkAxis(eyePos.z - center.z, box.lengthZ / 2, Direction.NORTH, Direction.SOUTH) } private fun EnumSet.checkAxis( From 1f7e881a774a431a24a17b5006a065fcbf8cccc1 Mon Sep 17 00:00:00 2001 From: Constructor Date: Wed, 20 Mar 2024 23:33:16 +0100 Subject: [PATCH 5/7] Shape compound rotation finder --- .../com/lambda/event/events/RotationEvent.kt | 90 +++++++++++-------- .../com/lambda/manager/RotationManager.kt | 86 +++++++++--------- .../manager/interaction/VisibilityChecker.kt | 5 +- .../main/kotlin/com/lambda/module/Module.kt | 7 +- .../com/lambda/module/modules/RotationTest.kt | 20 ++++- .../module/modules/movement/RocketExtend.kt | 4 +- .../util/primitives/extension/Components.kt | 3 +- 7 files changed, 122 insertions(+), 93 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt b/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt index 0600a2491..171c8ac46 100644 --- a/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt @@ -1,6 +1,7 @@ package com.lambda.event.events import com.lambda.config.RotationSettings +import com.lambda.context.SafeContext import com.lambda.event.Event import com.lambda.event.cancellable.Cancellable import com.lambda.event.cancellable.ICancellable @@ -13,10 +14,13 @@ import com.lambda.manager.rotation.Rotation.Companion.rotationTo import com.lambda.manager.interaction.VisibilityChecker.scanVisibleSurfaces import com.lambda.threading.runSafe import com.lambda.util.math.VecUtils.distSq +import com.lambda.util.world.raycast.RayCastUtils.blockResult import com.lambda.util.world.raycast.RayCastUtils.entityResult import net.minecraft.entity.LivingEntity import net.minecraft.util.hit.HitResult +import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Box +import net.minecraft.util.math.Direction import java.util.* abstract class RotationEvent : Event { @@ -31,46 +35,38 @@ abstract class RotationEvent : Event { } } - fun rotateTo( - config: IRotationConfig, - rotation: Rotation, - priority: Int = 0, - ) { - requests.add(RotationRequest(priority, config, rotation)) - } - - fun lookAt( + fun SafeContext.lookAt( rotationConfig: IRotationConfig, interact: InteractionConfig, - box: Box, + boxes: List, priority: Int = 0, hitCheck: HitResult.() -> Boolean, ) { - runSafe { - if (box.contains(player.eyePos)) { - stay(priority, rotationConfig) - return@runSafe - } + if (boxes.any { it.contains(player.eyePos) }) { + stay(priority, rotationConfig) + return + } - val currentRotation = RotationManager.currentRotation - val currentCast = currentRotation.rayCast( - interact.reach, - interact.rayCastMask, - player.eyePos - ) - val check = currentCast?.let { it.hitCheck() } ?: false - -// Slowdown or freeze if looking correct - (rotationConfig as? RotationSettings)?.slowdownIf(check) ?: run { - if (check) stay(priority, rotationConfig) - return@runSafe - } + val currentRotation = RotationManager.currentRotation + val currentCast = currentRotation.rayCast( + interact.reach, + interact.rayCastMask, + player.eyePos + ) + val check = currentCast?.let { it.hitCheck() } ?: false + + // Slowdown or freeze if looking correct + (rotationConfig as? RotationSettings)?.slowdownIf(check) ?: run { + if (check) stay(priority, rotationConfig) + return + } - val reachSq = interact.reach * interact.reach + val reachSq = interact.reach * interact.reach - var closestRotation: Rotation? = null - var rotationDist = 0.0 + var closestRotation: Rotation? = null + var rotationDist = 0.0 + boxes.forEach { box -> scanVisibleSurfaces(box, interact.resolution) { vec -> if (player.eyePos distSq vec > reachSq) return@scanVisibleSurfaces @@ -89,13 +85,12 @@ abstract class RotationEvent : Event { rotationDist = dist closestRotation = newRotation } - - // Rotate to selected point - closestRotation?.let { rotation -> - requests.add(RotationRequest(priority, rotationConfig, rotation)) - } } + // Rotate to selected point + closestRotation?.let { rotation -> + requests.add(RotationRequest(priority, rotationConfig, rotation)) + } } fun lookAt( @@ -104,8 +99,27 @@ abstract class RotationEvent : Event { entity: LivingEntity, priority: Int = 0, ) { - lookAt(rotationConfig, interactionConfig, entity.boundingBox, priority) { - entityResult?.entity == entity + runSafe { + lookAt(rotationConfig, interactionConfig, listOf(entity.boundingBox), priority) { + entityResult?.entity == entity + } + } + } + + fun lookAt( + rotationConfig: IRotationConfig, + interactionConfig: InteractionConfig, + blockPos: BlockPos, + side: Direction, + priority: Int = 0, + ) { + runSafe { + val state = world.getBlockState(blockPos) + val voxelShape = state.getOutlineShape(world, blockPos) + val boundingBoxes = voxelShape.boundingBoxes.map { it.offset(blockPos) } + lookAt(rotationConfig, interactionConfig, boundingBoxes, priority) { + blockResult?.blockPos == blockPos && blockResult?.side == side + } } } diff --git a/common/src/main/kotlin/com/lambda/manager/RotationManager.kt b/common/src/main/kotlin/com/lambda/manager/RotationManager.kt index e7e3785f5..6c73e4250 100644 --- a/common/src/main/kotlin/com/lambda/manager/RotationManager.kt +++ b/common/src/main/kotlin/com/lambda/manager/RotationManager.kt @@ -33,6 +33,11 @@ object RotationManager : Loadable { var currentRotation = Rotation.ZERO private var prevRotation = Rotation.ZERO + var currentContext: RotationContext? = null + + private var keepTicks = 0 + private var pauseTicks = 0 + @JvmStatic fun update() = runSafe { @@ -42,49 +47,6 @@ object RotationManager : Loadable { EventFlow.post(RotationEvent.Post()) } - var currentContext: RotationContext? = null - - private var keepTicks = 0 - private var pauseTicks = 0 - - private val smoothRotation get() = - lerp(prevRotation, currentRotation, mc.partialTicks) - - @JvmStatic val lockRotation get() = - if (currentContext?.config?.rotationMode == RotationMode.LOCK) smoothRotation else null - - @JvmStatic val renderYaw get() = - if (currentContext?.config == null) null else smoothRotation.yaw.toFloat() - - @JvmStatic val renderPitch get() = - if (currentContext?.config == null) null else smoothRotation.pitch.toFloat() - - @JvmStatic val handYaw get() = - if (currentContext?.config?.rotationMode == RotationMode.LOCK) currentRotation.yaw.toFloat() else null - - @JvmStatic val handPitch get() = - if (currentContext?.config?.rotationMode == RotationMode.LOCK) currentRotation.pitch.toFloat() else null - - @JvmStatic val movementYaw: Float? get() { - val config = currentContext?.config ?: return null - if (config.rotationMode == RotationMode.SILENT) return null - return currentRotation.yaw.toFloat() - } - - @JvmStatic val movementPitch: Float? get() { - val config = currentContext?.config ?: return null - if (config.rotationMode == RotationMode.SILENT) return null - return currentRotation.pitch.toFloat() - } - - @JvmStatic fun getRotationForVector(deltaTime: Double): Vec2d? { - val config = currentContext?.config ?: return null - if (config.rotationMode == RotationMode.SILENT) return null - - val rot = lerp(prevRotation, currentRotation, deltaTime) - return Vec2d(rot.yaw, rot.pitch) - } - init { listener { event -> val packet = event.packet @@ -145,6 +107,44 @@ object RotationManager : Loadable { pauseTicks = 3 } + private val smoothRotation get() = + lerp(prevRotation, currentRotation, mc.partialTicks) + + @JvmStatic val lockRotation get() = + if (currentContext?.config?.rotationMode == RotationMode.LOCK) smoothRotation else null + + @JvmStatic val renderYaw get() = + if (currentContext?.config == null) null else smoothRotation.yaw.toFloat() + + @JvmStatic val renderPitch get() = + if (currentContext?.config == null) null else smoothRotation.pitch.toFloat() + + @JvmStatic val handYaw get() = + if (currentContext?.config?.rotationMode == RotationMode.LOCK) currentRotation.yaw.toFloat() else null + + @JvmStatic val handPitch get() = + if (currentContext?.config?.rotationMode == RotationMode.LOCK) currentRotation.pitch.toFloat() else null + + @JvmStatic val movementYaw: Float? get() { + val config = currentContext?.config ?: return null + if (config.rotationMode == RotationMode.SILENT) return null + return currentRotation.yaw.toFloat() + } + + @JvmStatic val movementPitch: Float? get() { + val config = currentContext?.config ?: return null + if (config.rotationMode == RotationMode.SILENT) return null + return currentRotation.pitch.toFloat() + } + + @JvmStatic fun getRotationForVector(deltaTime: Double): Vec2d? { + val config = currentContext?.config ?: return null + if (config.rotationMode == RotationMode.SILENT) return null + + val rot = lerp(prevRotation, currentRotation, deltaTime) + return Vec2d(rot.yaw, rot.pitch) + } + object BaritoneProcessor { var baritoneContext: RotationContext? = null; private set diff --git a/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt b/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt index 38958e337..371377340 100644 --- a/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt +++ b/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt @@ -1,14 +1,13 @@ package com.lambda.manager.interaction import com.lambda.context.SafeContext +import com.lambda.util.primitives.extension.component6 import net.minecraft.util.math.* import java.util.* object VisibilityChecker { - operator fun DoubleArray.component6() = this[5] - inline fun SafeContext.scanVisibleSurfaces(box: Box, resolution: Int, check: (Vec3d) -> Unit) { - val shrunk = box.expand(-0.025) + val shrunk = box.expand(-0.05) getVisibleSides(box).forEach { side -> val (minX, minY, minZ, maxX, maxY, maxZ) = shrunk.bounds(side) val stepX = (maxX - minX) / resolution diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 33eb8d60f..c26364ada 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -6,6 +6,7 @@ import com.lambda.config.Configuration import com.lambda.config.configurations.ModuleConfig import com.lambda.config.settings.comparable.BooleanSetting import com.lambda.config.settings.numeric.DoubleSetting +import com.lambda.context.SafeContext import com.lambda.event.Muteable import com.lambda.event.events.KeyPressEvent import com.lambda.event.listener.Listener @@ -123,19 +124,19 @@ abstract class Module( isEnabled = !isEnabled } - protected fun onEnable(block: () -> Unit) { + protected fun onEnable(block: SafeContext.() -> Unit) { isEnabledSetting.listener { from, to -> if (!from && to) block() } } - protected fun onDisable(block: () -> Unit) { + protected fun onDisable(block: SafeContext.() -> Unit) { isEnabledSetting.listener { from, to -> if (from && !to) block() } } - protected fun onToggle(block: (to: Boolean) -> Unit) { + protected fun onToggle(block: SafeContext.(to: Boolean) -> Unit) { isEnabledSetting.listener { from, to -> if (from != to) block(to) } diff --git a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt b/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt index cc53e7ca0..5589eb551 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt @@ -7,6 +7,9 @@ import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.module.Module import com.lambda.util.world.EntityUtils.getClosestEntity import net.minecraft.entity.passive.VillagerEntity +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction object RotationTest : Module( name = "RotationTest", @@ -16,13 +19,22 @@ object RotationTest : Module( private val rotationConfig = RotationSettings(this) private val interactionConfig = InteractionSettings(this) + private var pos: BlockPos = BlockPos.ORIGIN + private var side = Direction.UP + init { + onEnable { + val hit = mc.crosshairTarget as? BlockHitResult ?: return@onEnable + pos = hit.blockPos + side = hit.side + } + listener { - val target = getClosestEntity( - player.eyePos, interaction.reachDistance.toDouble() - ) ?: return@listener +// val target = getClosestEntity( +// player.eyePos, interaction.reachDistance.toDouble() +// ) ?: return@listener - it.lookAt(rotationConfig, interactionConfig, target) + it.lookAt(rotationConfig, interactionConfig, pos, side) } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt index 281e63ac6..95feef00d 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt @@ -39,7 +39,9 @@ object RocketExtend : Module( event.cancel() } - onDisable(::reset) + onDisable { + reset() + } } private fun reset() = runSafe { diff --git a/common/src/main/kotlin/com/lambda/util/primitives/extension/Components.kt b/common/src/main/kotlin/com/lambda/util/primitives/extension/Components.kt index ea0b36f5f..c0bfea405 100644 --- a/common/src/main/kotlin/com/lambda/util/primitives/extension/Components.kt +++ b/common/src/main/kotlin/com/lambda/util/primitives/extension/Components.kt @@ -7,4 +7,5 @@ operator fun Vec2f.component1() = this.x operator fun Vec2f.component2() = this.y operator fun Vec3d.component1() = this.x operator fun Vec3d.component2() = this.y -operator fun Vec3d.component3() = this.z \ No newline at end of file +operator fun Vec3d.component3() = this.z +operator fun DoubleArray.component6() = this[5] \ No newline at end of file From a69e0c9c848353c3992cccbfec21d7144dd0074b Mon Sep 17 00:00:00 2001 From: Constructor Date: Fri, 22 Mar 2024 02:58:17 +0100 Subject: [PATCH 6/7] F3 Debug info and rotation improvements --- .../java/com/lambda/mixin/DebugHudMixin.java | 24 +---------- .../lambda/mixin/MinecraftClientMixin.java | 2 +- .../com/lambda/command/CommandManager.kt | 2 +- .../com/lambda/config/InteractionSettings.kt | 2 +- .../com/lambda/config/RotationSettings.kt | 4 +- .../config/serializer/KeyCodeSerializer.kt | 1 + .../lambda/event/events/PlayerPacketEvent.kt | 2 +- .../com/lambda/event/events/RotationEvent.kt | 37 +++++++++-------- .../interaction/InteractionConfig.kt | 2 +- .../interaction/VisibilityChecker.kt | 35 ++++++++-------- .../rotation/IRotationConfig.kt | 2 +- .../rotation/Rotation.kt | 5 +-- .../rotation/RotationContext.kt | 2 +- .../rotation/RotationMode.kt | 2 +- .../com/lambda/manager/PlayerPacketManager.kt | 2 +- .../com/lambda/manager/RotationManager.kt | 25 ++++++----- .../com/lambda/module/modules/RotationTest.kt | 4 +- .../lambda/module/modules/client/Baritone.kt | 4 +- .../kotlin/com/lambda/util/DebugInfoHud.kt | 41 +++++++++++++++++++ .../kotlin/com/lambda/util/math/MathUtils.kt | 2 +- .../lambda/util/world/raycast/RayCastUtils.kt | 6 +-- .../main/resources/lambda.mixins.common.json | 1 + 22 files changed, 119 insertions(+), 88 deletions(-) rename common/src/main/kotlin/com/lambda/{manager => }/interaction/InteractionConfig.kt (89%) rename common/src/main/kotlin/com/lambda/{manager => }/interaction/VisibilityChecker.kt (61%) rename common/src/main/kotlin/com/lambda/{manager => interaction}/rotation/IRotationConfig.kt (93%) rename common/src/main/kotlin/com/lambda/{manager => interaction}/rotation/Rotation.kt (96%) rename common/src/main/kotlin/com/lambda/{manager => interaction}/rotation/RotationContext.kt (69%) rename common/src/main/kotlin/com/lambda/{manager => interaction}/rotation/RotationMode.kt (87%) create mode 100644 common/src/main/kotlin/com/lambda/util/DebugInfoHud.kt diff --git a/common/src/main/java/com/lambda/mixin/DebugHudMixin.java b/common/src/main/java/com/lambda/mixin/DebugHudMixin.java index fe5827a1e..c41410e6f 100644 --- a/common/src/main/java/com/lambda/mixin/DebugHudMixin.java +++ b/common/src/main/java/com/lambda/mixin/DebugHudMixin.java @@ -1,11 +1,7 @@ package com.lambda.mixin; -import com.lambda.Lambda; +import com.lambda.util.DebugInfoHud; import net.minecraft.client.gui.hud.DebugHud; -import net.minecraft.util.Formatting; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.EntityHitResult; -import net.minecraft.util.hit.HitResult; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -17,22 +13,6 @@ public class DebugHudMixin { @Inject(method = "getRightText", at = @At(value = "TAIL")) private void onGetRightText(CallbackInfoReturnable> cir) { - if (Lambda.getMc().crosshairTarget == null) return; - HitResult hitResult = Lambda.getMc().crosshairTarget; - List list = cir.getReturnValue(); - - list.add(""); - list.add(Formatting.UNDERLINE + "Lambda"); - list.add("Hitpos: " + hitResult.getPos()); - list.add("Type: " + hitResult.getType()); - - if (hitResult instanceof BlockHitResult blockHitResult) { - list.add("Side: " + blockHitResult.getSide()); - list.add("Blockpos: " + blockHitResult.getBlockPos()); - } - - if (hitResult instanceof EntityHitResult entityHitResult) { - list.add("Entity: " + entityHitResult.getEntity().getName().getString()); - } + DebugInfoHud.addDebugInfo(cir.getReturnValue()); } } diff --git a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index 37300aff9..464834014 100644 --- a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -51,6 +51,6 @@ boolean injectMultiActon(ClientPlayerInteractionManager instance) { void injectFastPlace(CallbackInfo ci) { if (!Interact.INSTANCE.isEnabled()) return; - Lambda.INSTANCE.getMc().itemUseCooldown = Interact.getPlaceDelay(); + Lambda.getMc().itemUseCooldown = Interact.getPlaceDelay(); } } diff --git a/common/src/main/kotlin/com/lambda/command/CommandManager.kt b/common/src/main/kotlin/com/lambda/command/CommandManager.kt index 6c8fd8233..75730d610 100644 --- a/common/src/main/kotlin/com/lambda/command/CommandManager.kt +++ b/common/src/main/kotlin/com/lambda/command/CommandManager.kt @@ -29,7 +29,7 @@ object CommandManager : Configurable(LambdaConfig), Loadable { val prefix by setting("prefix", ';') - private val commands = mutableSetOf() + val commands = mutableSetOf() private val dispatcher by lazy { CommandDispatcher() } private const val ERROR_PADDING = 10 diff --git a/common/src/main/kotlin/com/lambda/config/InteractionSettings.kt b/common/src/main/kotlin/com/lambda/config/InteractionSettings.kt index 5ba20d004..0c7aa5e71 100644 --- a/common/src/main/kotlin/com/lambda/config/InteractionSettings.kt +++ b/common/src/main/kotlin/com/lambda/config/InteractionSettings.kt @@ -1,6 +1,6 @@ package com.lambda.config -import com.lambda.manager.interaction.InteractionConfig +import com.lambda.interaction.InteractionConfig import com.lambda.util.world.raycast.RayCastMask class InteractionSettings( diff --git a/common/src/main/kotlin/com/lambda/config/RotationSettings.kt b/common/src/main/kotlin/com/lambda/config/RotationSettings.kt index bfa0c2ea4..b76deb647 100644 --- a/common/src/main/kotlin/com/lambda/config/RotationSettings.kt +++ b/common/src/main/kotlin/com/lambda/config/RotationSettings.kt @@ -1,7 +1,7 @@ package com.lambda.config -import com.lambda.manager.rotation.IRotationConfig -import com.lambda.manager.rotation.RotationMode +import com.lambda.interaction.rotation.IRotationConfig +import com.lambda.interaction.rotation.RotationMode import kotlin.random.Random class RotationSettings( diff --git a/common/src/main/kotlin/com/lambda/config/serializer/KeyCodeSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/KeyCodeSerializer.kt index 01454940c..9cee9ff17 100644 --- a/common/src/main/kotlin/com/lambda/config/serializer/KeyCodeSerializer.kt +++ b/common/src/main/kotlin/com/lambda/config/serializer/KeyCodeSerializer.kt @@ -4,6 +4,7 @@ import com.google.gson.* import com.lambda.util.KeyCode import java.lang.reflect.Type +// ToDo: Use key lookup table to store actual key names object KeyCodeSerializer : JsonSerializer, JsonDeserializer { override fun serialize( src: KeyCode?, diff --git a/common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt b/common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt index 5fc90eba7..eaa1172f5 100644 --- a/common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt @@ -3,7 +3,7 @@ package com.lambda.event.events import com.lambda.event.Event import com.lambda.event.cancellable.Cancellable import com.lambda.event.cancellable.ICancellable -import com.lambda.manager.rotation.Rotation +import com.lambda.interaction.rotation.Rotation import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket import net.minecraft.util.math.Vec3d diff --git a/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt b/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt index 171c8ac46..b8db136c5 100644 --- a/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt @@ -6,17 +6,19 @@ import com.lambda.event.Event import com.lambda.event.cancellable.Cancellable import com.lambda.event.cancellable.ICancellable import com.lambda.manager.RotationManager -import com.lambda.manager.interaction.InteractionConfig -import com.lambda.manager.rotation.IRotationConfig -import com.lambda.manager.rotation.Rotation -import com.lambda.manager.rotation.Rotation.Companion.distance -import com.lambda.manager.rotation.Rotation.Companion.rotationTo -import com.lambda.manager.interaction.VisibilityChecker.scanVisibleSurfaces +import com.lambda.interaction.InteractionConfig +import com.lambda.interaction.rotation.IRotationConfig +import com.lambda.interaction.rotation.Rotation +import com.lambda.interaction.rotation.Rotation.Companion.distance +import com.lambda.interaction.rotation.Rotation.Companion.rotationTo +import com.lambda.interaction.VisibilityChecker.scanVisibleSurfaces +import com.lambda.module.modules.RotationTest import com.lambda.threading.runSafe import com.lambda.util.math.VecUtils.distSq import com.lambda.util.world.raycast.RayCastUtils.blockResult import com.lambda.util.world.raycast.RayCastUtils.entityResult import net.minecraft.entity.LivingEntity +import net.minecraft.util.Hand import net.minecraft.util.hit.HitResult import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Box @@ -35,14 +37,17 @@ abstract class RotationEvent : Event { } } - fun SafeContext.lookAt( + private fun SafeContext.lookAt( rotationConfig: IRotationConfig, interact: InteractionConfig, boxes: List, priority: Int = 0, + sides: Set = emptySet(), hitCheck: HitResult.() -> Boolean, ) { - if (boxes.any { it.contains(player.eyePos) }) { + val eye = player.getCameraPosVec(mc.tickDelta) + + if (boxes.any { it.contains(eye) }) { stay(priority, rotationConfig) return } @@ -51,7 +56,7 @@ abstract class RotationEvent : Event { val currentCast = currentRotation.rayCast( interact.reach, interact.rayCastMask, - player.eyePos + eye ) val check = currentCast?.let { it.hitCheck() } ?: false @@ -67,15 +72,15 @@ abstract class RotationEvent : Event { var rotationDist = 0.0 boxes.forEach { box -> - scanVisibleSurfaces(box, interact.resolution) { vec -> - if (player.eyePos distSq vec > reachSq) return@scanVisibleSurfaces + scanVisibleSurfaces(box, sides, interact.resolution) { vec -> + if (eye distSq vec > reachSq) return@scanVisibleSurfaces - val newRotation = player.eyePos.rotationTo(vec) + val newRotation = eye.rotationTo(vec) val cast = newRotation.rayCast( interact.reach, interact.rayCastMask, - player.eyePos + eye ) ?: return@scanVisibleSurfaces if (!cast.hitCheck()) return@scanVisibleSurfaces @@ -110,15 +115,15 @@ abstract class RotationEvent : Event { rotationConfig: IRotationConfig, interactionConfig: InteractionConfig, blockPos: BlockPos, - side: Direction, + sides: Set, priority: Int = 0, ) { runSafe { val state = world.getBlockState(blockPos) val voxelShape = state.getOutlineShape(world, blockPos) val boundingBoxes = voxelShape.boundingBoxes.map { it.offset(blockPos) } - lookAt(rotationConfig, interactionConfig, boundingBoxes, priority) { - blockResult?.blockPos == blockPos && blockResult?.side == side + lookAt(rotationConfig, interactionConfig, boundingBoxes, priority, sides) { + blockResult?.blockPos == blockPos && blockResult?.side in sides } } } diff --git a/common/src/main/kotlin/com/lambda/manager/interaction/InteractionConfig.kt b/common/src/main/kotlin/com/lambda/interaction/InteractionConfig.kt similarity index 89% rename from common/src/main/kotlin/com/lambda/manager/interaction/InteractionConfig.kt rename to common/src/main/kotlin/com/lambda/interaction/InteractionConfig.kt index ee7a3ebbb..3eb58020f 100644 --- a/common/src/main/kotlin/com/lambda/manager/interaction/InteractionConfig.kt +++ b/common/src/main/kotlin/com/lambda/interaction/InteractionConfig.kt @@ -1,4 +1,4 @@ -package com.lambda.manager.interaction +package com.lambda.interaction import com.lambda.util.world.raycast.RayCastMask diff --git a/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt b/common/src/main/kotlin/com/lambda/interaction/VisibilityChecker.kt similarity index 61% rename from common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt rename to common/src/main/kotlin/com/lambda/interaction/VisibilityChecker.kt index 371377340..bf397e923 100644 --- a/common/src/main/kotlin/com/lambda/manager/interaction/VisibilityChecker.kt +++ b/common/src/main/kotlin/com/lambda/interaction/VisibilityChecker.kt @@ -1,4 +1,4 @@ -package com.lambda.manager.interaction +package com.lambda.interaction import com.lambda.context.SafeContext import com.lambda.util.primitives.extension.component6 @@ -6,22 +6,26 @@ import net.minecraft.util.math.* import java.util.* object VisibilityChecker { - inline fun SafeContext.scanVisibleSurfaces(box: Box, resolution: Int, check: (Vec3d) -> Unit) { - val shrunk = box.expand(-0.05) - getVisibleSides(box).forEach { side -> - val (minX, minY, minZ, maxX, maxY, maxZ) = shrunk.bounds(side) - val stepX = (maxX - minX) / resolution - val stepY = (maxY - minY) / resolution - val stepZ = (maxZ - minZ) / resolution - for (i in 0 .. resolution) { - val x = if (stepX != 0.0) minX + stepX * i else minX - for (j in 0 .. resolution) { - val y = if (stepY != 0.0) minY + stepY * j else minY - val z = if (stepZ != 0.0) minZ + stepZ * ((if (stepX != 0.0) j else i)) else minZ - check(Vec3d(x, y, z)) + inline fun SafeContext.scanVisibleSurfaces(box: Box, sides: Set, resolution: Int, check: (Vec3d) -> Unit) { + val shrunk = box.expand(-0.005) + getVisibleSides(box) + .forEach { side -> + if (sides.isNotEmpty() && side !in sides) { + return@forEach + } + val (minX, minY, minZ, maxX, maxY, maxZ) = shrunk.bounds(side) + val stepX = (maxX - minX) / resolution + val stepY = (maxY - minY) / resolution + val stepZ = (maxZ - minZ) / resolution + for (i in 0 .. resolution) { + val x = if (stepX != 0.0) minX + stepX * i else minX + for (j in 0 .. resolution) { + val y = if (stepY != 0.0) minY + stepY * j else minY + val z = if (stepZ != 0.0) minZ + stepZ * ((if (stepX != 0.0) j else i)) else minZ + check(Vec3d(x, y, z)) + } } } - } } fun Box.bounds(side: Direction) = @@ -59,7 +63,6 @@ object VisibilityChecker { diff > limit -> { add(positiveSide) } - else -> {} } } } diff --git a/common/src/main/kotlin/com/lambda/manager/rotation/IRotationConfig.kt b/common/src/main/kotlin/com/lambda/interaction/rotation/IRotationConfig.kt similarity index 93% rename from common/src/main/kotlin/com/lambda/manager/rotation/IRotationConfig.kt rename to common/src/main/kotlin/com/lambda/interaction/rotation/IRotationConfig.kt index a4e1cd921..c3593654d 100644 --- a/common/src/main/kotlin/com/lambda/manager/rotation/IRotationConfig.kt +++ b/common/src/main/kotlin/com/lambda/interaction/rotation/IRotationConfig.kt @@ -1,4 +1,4 @@ -package com.lambda.manager.rotation +package com.lambda.interaction.rotation interface IRotationConfig { /** diff --git a/common/src/main/kotlin/com/lambda/manager/rotation/Rotation.kt b/common/src/main/kotlin/com/lambda/interaction/rotation/Rotation.kt similarity index 96% rename from common/src/main/kotlin/com/lambda/manager/rotation/Rotation.kt rename to common/src/main/kotlin/com/lambda/interaction/rotation/Rotation.kt index a41ab23f5..dbb459d73 100644 --- a/common/src/main/kotlin/com/lambda/manager/rotation/Rotation.kt +++ b/common/src/main/kotlin/com/lambda/interaction/rotation/Rotation.kt @@ -1,11 +1,11 @@ -package com.lambda.manager.rotation +package com.lambda.interaction.rotation +import com.lambda.Lambda.mc import com.lambda.threading.runSafe import com.lambda.util.math.MathUtils.toDegree import com.lambda.util.math.MathUtils.toRadian import com.lambda.util.world.raycast.RayCastMask import com.lambda.util.world.raycast.RayCastUtils.rayCast -import net.minecraft.client.MinecraftClient import net.minecraft.util.math.Direction import net.minecraft.util.math.MathHelper import net.minecraft.util.math.Vec3d @@ -62,7 +62,6 @@ data class Rotation(val yaw: Double, val pitch: Double) { } fun Rotation.fixSensitivity(last: Rotation): Rotation { - val mc = MinecraftClient.getInstance() val f = mc.options.mouseSensitivity.value * 0.6 + 0.2 val step = f * f * f * 8.0 * 0.15F diff --git a/common/src/main/kotlin/com/lambda/manager/rotation/RotationContext.kt b/common/src/main/kotlin/com/lambda/interaction/rotation/RotationContext.kt similarity index 69% rename from common/src/main/kotlin/com/lambda/manager/rotation/RotationContext.kt rename to common/src/main/kotlin/com/lambda/interaction/rotation/RotationContext.kt index cd35b74e2..b9cd04cc6 100644 --- a/common/src/main/kotlin/com/lambda/manager/rotation/RotationContext.kt +++ b/common/src/main/kotlin/com/lambda/interaction/rotation/RotationContext.kt @@ -1,4 +1,4 @@ -package com.lambda.manager.rotation +package com.lambda.interaction.rotation data class RotationContext( val config: IRotationConfig, diff --git a/common/src/main/kotlin/com/lambda/manager/rotation/RotationMode.kt b/common/src/main/kotlin/com/lambda/interaction/rotation/RotationMode.kt similarity index 87% rename from common/src/main/kotlin/com/lambda/manager/rotation/RotationMode.kt rename to common/src/main/kotlin/com/lambda/interaction/rotation/RotationMode.kt index 4b2f74f2c..9fb5a7900 100644 --- a/common/src/main/kotlin/com/lambda/manager/rotation/RotationMode.kt +++ b/common/src/main/kotlin/com/lambda/interaction/rotation/RotationMode.kt @@ -1,4 +1,4 @@ -package com.lambda.manager.rotation +package com.lambda.interaction.rotation /** * @property SILENT Spoofing server-side rotation. diff --git a/common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt b/common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt index 870f659d7..b40b8521f 100644 --- a/common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt +++ b/common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt @@ -4,7 +4,7 @@ import com.lambda.Loadable import com.lambda.context.SafeContext import com.lambda.event.EventFlow import com.lambda.event.events.PlayerPacketEvent -import com.lambda.manager.rotation.Rotation +import com.lambda.interaction.rotation.Rotation import com.lambda.threading.runSafe import com.lambda.util.math.VecUtils.distSq import com.lambda.util.player.MovementUtils.motionX diff --git a/common/src/main/kotlin/com/lambda/manager/RotationManager.kt b/common/src/main/kotlin/com/lambda/manager/RotationManager.kt index 6c73e4250..58a871ccf 100644 --- a/common/src/main/kotlin/com/lambda/manager/RotationManager.kt +++ b/common/src/main/kotlin/com/lambda/manager/RotationManager.kt @@ -1,5 +1,6 @@ package com.lambda.manager +import com.lambda.Lambda.LOG import com.lambda.Lambda.mc import com.lambda.Loadable import com.lambda.config.RotationSettings @@ -10,12 +11,12 @@ import com.lambda.event.events.RotationEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.event.listener.UnsafeListener.Companion.unsafeListener -import com.lambda.manager.rotation.Rotation -import com.lambda.manager.rotation.Rotation.Companion.angleDifference -import com.lambda.manager.rotation.Rotation.Companion.fixSensitivity -import com.lambda.manager.rotation.Rotation.Companion.interpolate -import com.lambda.manager.rotation.RotationContext -import com.lambda.manager.rotation.RotationMode +import com.lambda.interaction.rotation.Rotation +import com.lambda.interaction.rotation.Rotation.Companion.angleDifference +import com.lambda.interaction.rotation.Rotation.Companion.fixSensitivity +import com.lambda.interaction.rotation.Rotation.Companion.interpolate +import com.lambda.interaction.rotation.RotationContext +import com.lambda.interaction.rotation.RotationMode import com.lambda.module.modules.client.Baritone import com.lambda.threading.runOnGameThread import com.lambda.threading.runSafe @@ -80,20 +81,18 @@ object RotationManager : Loadable { currentRotation = Rotation(player.yaw, player.pitch) - val data = currentContext ?: return@runSafe - val settings = data.config + val context = currentContext ?: return@runSafe + val rotationTo = if (keepTicks >= 0) context.rotation else currentRotation - val rotationTo = if (keepTicks >= 0) data.rotation else currentRotation - - var speedMultiplier = (settings as? RotationSettings)?.speedMultiplier ?: 1.0 + var speedMultiplier = (context.config as? RotationSettings)?.speedMultiplier ?: 1.0 if (keepTicks < 0) speedMultiplier = 1.0 - val turnSpeed = settings.turnSpeed * speedMultiplier + val turnSpeed = context.config.turnSpeed * speedMultiplier currentRotation = interpolate(prevRotation, rotationTo, turnSpeed) .fixSensitivity(prevRotation) - if (settings.rotationMode == RotationMode.LOCK) { + if (context.config.rotationMode == RotationMode.LOCK) { player.yaw = currentRotation.yaw.toFloat() player.pitch = currentRotation.pitch.toFloat() } diff --git a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt b/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt index 5589eb551..2277ca6b5 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt @@ -7,6 +7,7 @@ import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.module.Module import com.lambda.util.world.EntityUtils.getClosestEntity import net.minecraft.entity.passive.VillagerEntity +import net.minecraft.util.Hand import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction @@ -34,7 +35,8 @@ object RotationTest : Module( // player.eyePos, interaction.reachDistance.toDouble() // ) ?: return@listener - it.lookAt(rotationConfig, interactionConfig, pos, side) + it.lookAt(rotationConfig, interactionConfig, pos, setOf(side)) + } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt b/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt index 81846a2d1..892478d99 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt @@ -1,7 +1,7 @@ package com.lambda.module.modules.client -import com.lambda.manager.rotation.IRotationConfig -import com.lambda.manager.rotation.RotationMode +import com.lambda.interaction.rotation.IRotationConfig +import com.lambda.interaction.rotation.RotationMode import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.math.MathUtils.random diff --git a/common/src/main/kotlin/com/lambda/util/DebugInfoHud.kt b/common/src/main/kotlin/com/lambda/util/DebugInfoHud.kt new file mode 100644 index 000000000..1de451594 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/DebugInfoHud.kt @@ -0,0 +1,41 @@ +package com.lambda.util + +import com.lambda.Lambda +import com.lambda.Lambda.mc +import com.lambda.command.CommandManager +import com.lambda.event.EventFlow +import com.lambda.module.ModuleRegistry +import net.minecraft.util.Formatting +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.hit.EntityHitResult + +object DebugInfoHud { + @JvmStatic + fun MutableList.addDebugInfo() { + add("") + add("" + Formatting.UNDERLINE + "Lambda ${Lambda.VERSION}+${mc.versionType}") + add("Modules: ${ModuleRegistry.modules.size} with ${ModuleRegistry.modules.sumOf { it.settings.size }} settings") + add("Commands: ${CommandManager.commands.size}") + add("Synchronous Listeners: ${EventFlow.syncListeners.size}") + add("Concurrent Listeners: ${EventFlow.concurrentListeners.size}") + + when (val hit = mc.crosshairTarget) { + is BlockHitResult -> { + add("Crosshair Target: Block") + add(" Vec3d: %.5f, %.5f, %.5f".format(hit.pos.x, hit.pos.y, hit.pos.z)) + add(" BlockPos: ${hit.blockPos.toShortString()}") + add(" Side: ${hit.side}") + } + + is EntityHitResult -> { + add("Crosshair Target: Entity") + add(" Vec3d: ${hit.pos}") + add(" Entity: ${hit.entity}") + } + + null -> add("Crosshair Target: None") + } + + return + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt b/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt index 9be0dd030..f1e15087c 100644 --- a/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt @@ -1,6 +1,6 @@ package com.lambda.util.math -import com.lambda.manager.rotation.Rotation +import com.lambda.interaction.rotation.Rotation import com.lambda.util.math.ColorUtils.a import com.lambda.util.math.ColorUtils.b import com.lambda.util.math.ColorUtils.g diff --git a/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt b/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt index 29f0c34d6..e4f3d61c8 100644 --- a/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt @@ -1,11 +1,11 @@ package com.lambda.util.world.raycast import com.lambda.context.SafeContext -import com.lambda.manager.rotation.Rotation +import com.lambda.interaction.rotation.Rotation import com.lambda.threading.runSafe import com.lambda.util.math.VecUtils.distSq import net.minecraft.entity.Entity -import net.minecraft.entity.projectile.ProjectileUtil.raycast +import net.minecraft.entity.projectile.ProjectileUtil import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.hit.EntityHitResult import net.minecraft.util.hit.HitResult @@ -40,7 +40,7 @@ object RayCastUtils { if (!mask.entity) return@run null val box = player.boundingBox.stretch(vec).expand(1.0) - val entity = raycast(player, pos, point, box, entityPredicate, reach * reach) + val entity = ProjectileUtil.raycast(player, pos, point, box, entityPredicate, reach * reach) entity?.entityResult } diff --git a/common/src/main/resources/lambda.mixins.common.json b/common/src/main/resources/lambda.mixins.common.json index eafbb76a9..29732afc6 100644 --- a/common/src/main/resources/lambda.mixins.common.json +++ b/common/src/main/resources/lambda.mixins.common.json @@ -8,6 +8,7 @@ "ChatScreenMixin", "ClientConnectionMixin", "DebugHudMixin", + "GameRendererMixin", "KeyBindingMixin", "KeyboardMixin", "MinecraftClientMixin", From 9800466b3424eebf97cb88fa5bcb123ba70add19 Mon Sep 17 00:00:00 2001 From: Constructor Date: Sat, 23 Mar 2024 00:06:43 +0100 Subject: [PATCH 7/7] Block interaction tests --- .../com/lambda/mixin/GameRendererMixin.java | 16 ++ .../mixin/entity/ClientPlayerEntityMixin.java | 5 +- .../com/lambda/mixin/entity/EntityMixin.java | 2 +- .../mixin/entity/LivingEntityMixin.java | 2 +- common/src/main/kotlin/com/lambda/Loader.kt | 2 +- .../com/lambda/event/events/RotationEvent.kt | 107 ++----------- .../PlayerPacketManager.kt | 2 +- .../RotationManager.kt | 75 ++++++--- .../lambda/interaction/VisibilityChecker.kt | 68 --------- .../interaction/rotation/RotationRequest.kt | 11 ++ .../visibilty/EntityInteraction.kt | 4 + .../visibilty/VisibilityChecker.kt | 144 ++++++++++++++++++ .../com/lambda/module/modules/RotationTest.kt | 20 ++- .../com/lambda/util/player/MovementUtils.kt | 2 +- 14 files changed, 262 insertions(+), 198 deletions(-) create mode 100644 common/src/main/java/com/lambda/mixin/GameRendererMixin.java rename common/src/main/kotlin/com/lambda/{manager => interaction}/PlayerPacketManager.kt (99%) rename common/src/main/kotlin/com/lambda/{manager => interaction}/RotationManager.kt (76%) delete mode 100644 common/src/main/kotlin/com/lambda/interaction/VisibilityChecker.kt create mode 100644 common/src/main/kotlin/com/lambda/interaction/rotation/RotationRequest.kt create mode 100644 common/src/main/kotlin/com/lambda/interaction/visibilty/EntityInteraction.kt create mode 100644 common/src/main/kotlin/com/lambda/interaction/visibilty/VisibilityChecker.kt diff --git a/common/src/main/java/com/lambda/mixin/GameRendererMixin.java b/common/src/main/java/com/lambda/mixin/GameRendererMixin.java new file mode 100644 index 000000000..6b54c3945 --- /dev/null +++ b/common/src/main/java/com/lambda/mixin/GameRendererMixin.java @@ -0,0 +1,16 @@ +package com.lambda.mixin; + +import com.lambda.interaction.RotationManager; +import net.minecraft.client.render.GameRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GameRenderer.class) +public class GameRendererMixin { + @Inject(method = "updateTargetedEntity", at = @At("HEAD")) + private void onUpdateTargetedEntity(CallbackInfo ci) { + RotationManager.updateInterpolated(); + } +} diff --git a/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java b/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java index 7c5942e0f..e4883ad8e 100644 --- a/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java +++ b/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java @@ -3,9 +3,8 @@ import com.lambda.Lambda; import com.lambda.event.EventFlow; import com.lambda.event.events.MovementEvent; -import com.lambda.manager.PlayerPacketManager; -import com.lambda.manager.RotationManager; -import net.minecraft.client.MinecraftClient; +import com.lambda.interaction.PlayerPacketManager; +import com.lambda.interaction.RotationManager; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.entity.MovementType; import net.minecraft.util.math.Vec3d; diff --git a/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java b/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java index 1aa3224b3..d81219cf9 100644 --- a/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java +++ b/common/src/main/java/com/lambda/mixin/entity/EntityMixin.java @@ -1,7 +1,7 @@ package com.lambda.mixin.entity; import com.lambda.Lambda; -import com.lambda.manager.RotationManager; +import com.lambda.interaction.RotationManager; import com.lambda.util.math.Vec2d; import net.minecraft.entity.Entity; import net.minecraft.entity.MovementType; diff --git a/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java b/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java index cf333e5fd..b84c9e8d2 100644 --- a/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java +++ b/common/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java @@ -3,7 +3,7 @@ import com.lambda.Lambda; import com.lambda.event.EventFlow; import com.lambda.event.events.MovementEvent; -import com.lambda.manager.RotationManager; +import com.lambda.interaction.RotationManager; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.util.math.MathHelper; diff --git a/common/src/main/kotlin/com/lambda/Loader.kt b/common/src/main/kotlin/com/lambda/Loader.kt index ef4b2aab9..4784f7428 100644 --- a/common/src/main/kotlin/com/lambda/Loader.kt +++ b/common/src/main/kotlin/com/lambda/Loader.kt @@ -2,7 +2,7 @@ package com.lambda import com.lambda.Lambda.LOG import com.lambda.command.CommandManager -import com.lambda.manager.RotationManager +import com.lambda.interaction.RotationManager import com.lambda.module.ModuleRegistry import kotlin.system.measureTimeMillis diff --git a/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt b/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt index b8db136c5..b83e3e7bc 100644 --- a/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/RotationEvent.kt @@ -1,27 +1,18 @@ package com.lambda.event.events -import com.lambda.config.RotationSettings -import com.lambda.context.SafeContext import com.lambda.event.Event import com.lambda.event.cancellable.Cancellable import com.lambda.event.cancellable.ICancellable -import com.lambda.manager.RotationManager import com.lambda.interaction.InteractionConfig +import com.lambda.interaction.RotationManager import com.lambda.interaction.rotation.IRotationConfig -import com.lambda.interaction.rotation.Rotation -import com.lambda.interaction.rotation.Rotation.Companion.distance -import com.lambda.interaction.rotation.Rotation.Companion.rotationTo -import com.lambda.interaction.VisibilityChecker.scanVisibleSurfaces -import com.lambda.module.modules.RotationTest +import com.lambda.interaction.rotation.RotationRequest +import com.lambda.interaction.visibilty.VisibilityChecker.findRotation import com.lambda.threading.runSafe -import com.lambda.util.math.VecUtils.distSq import com.lambda.util.world.raycast.RayCastUtils.blockResult import com.lambda.util.world.raycast.RayCastUtils.entityResult import net.minecraft.entity.LivingEntity -import net.minecraft.util.Hand -import net.minecraft.util.hit.HitResult import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Box import net.minecraft.util.math.Direction import java.util.* @@ -37,109 +28,39 @@ abstract class RotationEvent : Event { } } - private fun SafeContext.lookAt( - rotationConfig: IRotationConfig, - interact: InteractionConfig, - boxes: List, - priority: Int = 0, - sides: Set = emptySet(), - hitCheck: HitResult.() -> Boolean, - ) { - val eye = player.getCameraPosVec(mc.tickDelta) - - if (boxes.any { it.contains(eye) }) { - stay(priority, rotationConfig) - return - } - - val currentRotation = RotationManager.currentRotation - val currentCast = currentRotation.rayCast( - interact.reach, - interact.rayCastMask, - eye - ) - val check = currentCast?.let { it.hitCheck() } ?: false - - // Slowdown or freeze if looking correct - (rotationConfig as? RotationSettings)?.slowdownIf(check) ?: run { - if (check) stay(priority, rotationConfig) - return - } - - val reachSq = interact.reach * interact.reach - - var closestRotation: Rotation? = null - var rotationDist = 0.0 - - boxes.forEach { box -> - scanVisibleSurfaces(box, sides, interact.resolution) { vec -> - if (eye distSq vec > reachSq) return@scanVisibleSurfaces - - val newRotation = eye.rotationTo(vec) - - val cast = newRotation.rayCast( - interact.reach, - interact.rayCastMask, - eye - ) ?: return@scanVisibleSurfaces - if (!cast.hitCheck()) return@scanVisibleSurfaces - - val dist = newRotation.distance(currentRotation) - if (dist >= rotationDist && closestRotation != null) return@scanVisibleSurfaces - - rotationDist = dist - closestRotation = newRotation - } - } - - // Rotate to selected point - closestRotation?.let { rotation -> - requests.add(RotationRequest(priority, rotationConfig, rotation)) - } - } - - fun lookAt( + fun lookAtEntity( rotationConfig: IRotationConfig, interactionConfig: InteractionConfig, entity: LivingEntity, priority: Int = 0, ) { runSafe { - lookAt(rotationConfig, interactionConfig, listOf(entity.boundingBox), priority) { + findRotation(rotationConfig, interactionConfig, listOf(entity.boundingBox), priority) { entityResult?.entity == entity + }?.let { + requests.add(it) } } } - fun lookAt( + fun lookAtBlock( rotationConfig: IRotationConfig, interactionConfig: InteractionConfig, blockPos: BlockPos, - sides: Set, + sides: Set = emptySet(), priority: Int = 0, ) { runSafe { val state = world.getBlockState(blockPos) val voxelShape = state.getOutlineShape(world, blockPos) val boundingBoxes = voxelShape.boundingBoxes.map { it.offset(blockPos) } - lookAt(rotationConfig, interactionConfig, boundingBoxes, priority, sides) { - blockResult?.blockPos == blockPos && blockResult?.side in sides + findRotation(rotationConfig, interactionConfig, boundingBoxes, priority, sides) { + blockResult?.blockPos == blockPos && (blockResult?.side in sides || sides.isEmpty()) + }?.let { + requests.add(it) } } } - - private fun stay(priority: Int = 0, config: IRotationConfig) { - requests.add(RotationRequest(priority, config, RotationManager.currentRotation)) - } - - data class RotationRequest( - val priority: Int, - val config: IRotationConfig, - val rotation: Rotation, - ) : Comparable { - override fun compareTo(other: RotationRequest) = - priority.compareTo(other.priority) - } } - class Post : RotationEvent() + class Post(val request: RotationRequest) : RotationEvent() } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt b/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt similarity index 99% rename from common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt rename to common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt index b40b8521f..57f284a00 100644 --- a/common/src/main/kotlin/com/lambda/manager/PlayerPacketManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt @@ -1,4 +1,4 @@ -package com.lambda.manager +package com.lambda.interaction import com.lambda.Loadable import com.lambda.context.SafeContext diff --git a/common/src/main/kotlin/com/lambda/manager/RotationManager.kt b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt similarity index 76% rename from common/src/main/kotlin/com/lambda/manager/RotationManager.kt rename to common/src/main/kotlin/com/lambda/interaction/RotationManager.kt index 58a871ccf..3aebab7a6 100644 --- a/common/src/main/kotlin/com/lambda/manager/RotationManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt @@ -1,4 +1,4 @@ -package com.lambda.manager +package com.lambda.interaction import com.lambda.Lambda.LOG import com.lambda.Lambda.mc @@ -11,15 +11,14 @@ import com.lambda.event.events.RotationEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.event.listener.UnsafeListener.Companion.unsafeListener -import com.lambda.interaction.rotation.Rotation +import com.lambda.interaction.rotation.* import com.lambda.interaction.rotation.Rotation.Companion.angleDifference import com.lambda.interaction.rotation.Rotation.Companion.fixSensitivity import com.lambda.interaction.rotation.Rotation.Companion.interpolate -import com.lambda.interaction.rotation.RotationContext -import com.lambda.interaction.rotation.RotationMode import com.lambda.module.modules.client.Baritone import com.lambda.threading.runOnGameThread import com.lambda.threading.runSafe +import com.lambda.util.Communication.info import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.toRadian import com.lambda.util.math.Vec2d @@ -34,7 +33,7 @@ object RotationManager : Loadable { var currentRotation = Rotation.ZERO private var prevRotation = Rotation.ZERO - var currentContext: RotationContext? = null + var currentRequest: RotationRequest? = null private var keepTicks = 0 private var pauseTicks = 0 @@ -43,11 +42,25 @@ object RotationManager : Loadable { fun update() = runSafe { EventFlow.post(RotationEvent.Pre()) { - rotate() + rotate()?.let { + EventFlow.post(RotationEvent.Post(it)) + } } - EventFlow.post(RotationEvent.Post()) } + @JvmStatic + fun updateInterpolated() = runSafe { +// if (currentRequest == null) return@runSafe +// val interpolation = interpolate(prevRotation, currentRotation, mc.tickDelta.toDouble()) +// +// val rot = interpolation.fixSensitivity(prevRotation) +// +// if (currentRequest?.config?.rotationMode == RotationMode.LOCK) { +// player.yaw = rot.yaw.toFloat() +// player.pitch = rot.pitch.toFloat() +// } + } + init { listener { event -> val packet = event.packet @@ -69,19 +82,22 @@ object RotationManager : Loadable { (keepTicks--).coerceAtLeast(0) (pauseTicks--).coerceAtLeast(0) - val resetTicks = currentContext?.config?.resetTicks ?: 0 + val resetTicks = currentRequest?.config?.resetTicks ?: 0 if (keepTicks + resetTicks < 0 || pauseTicks >= 0) { - currentContext = null + currentRequest = null } - requests.firstOrNull()?.let { - currentContext = RotationContext(it.config, it.rotation) - keepTicks = it.config.keepTicks + var chosenRequest: RotationRequest? = null + + requests.firstOrNull()?.let { request -> + chosenRequest = request + currentRequest = request + keepTicks = request.config.keepTicks } currentRotation = Rotation(player.yaw, player.pitch) - val context = currentContext ?: return@runSafe + val context = currentRequest ?: return@runSafe chosenRequest val rotationTo = if (keepTicks >= 0) context.rotation else currentRotation var speedMultiplier = (context.config as? RotationSettings)?.speedMultiplier ?: 1.0 @@ -89,20 +105,29 @@ object RotationManager : Loadable { val turnSpeed = context.config.turnSpeed * speedMultiplier - currentRotation = interpolate(prevRotation, rotationTo, turnSpeed) - .fixSensitivity(prevRotation) + val interpolation = interpolate(prevRotation, rotationTo, turnSpeed) + + currentRotation = interpolation.fixSensitivity(prevRotation) if (context.config.rotationMode == RotationMode.LOCK) { player.yaw = currentRotation.yaw.toFloat() player.pitch = currentRotation.pitch.toFloat() } + + chosenRequest?.let { request -> + if (request.rotation.fixSensitivity(prevRotation) == currentRotation) { + request.isPending = false + } + } + + return@runSafe chosenRequest } private fun reset(rotation: Rotation) { prevRotation = rotation currentRotation = rotation - currentContext = null + currentRequest = null pauseTicks = 3 } @@ -110,34 +135,34 @@ object RotationManager : Loadable { lerp(prevRotation, currentRotation, mc.partialTicks) @JvmStatic val lockRotation get() = - if (currentContext?.config?.rotationMode == RotationMode.LOCK) smoothRotation else null + if (currentRequest?.config?.rotationMode == RotationMode.LOCK) smoothRotation else null @JvmStatic val renderYaw get() = - if (currentContext?.config == null) null else smoothRotation.yaw.toFloat() + if (currentRequest?.config == null) null else smoothRotation.yaw.toFloat() @JvmStatic val renderPitch get() = - if (currentContext?.config == null) null else smoothRotation.pitch.toFloat() + if (currentRequest?.config == null) null else smoothRotation.pitch.toFloat() @JvmStatic val handYaw get() = - if (currentContext?.config?.rotationMode == RotationMode.LOCK) currentRotation.yaw.toFloat() else null + if (currentRequest?.config?.rotationMode == RotationMode.LOCK) currentRotation.yaw.toFloat() else null @JvmStatic val handPitch get() = - if (currentContext?.config?.rotationMode == RotationMode.LOCK) currentRotation.pitch.toFloat() else null + if (currentRequest?.config?.rotationMode == RotationMode.LOCK) currentRotation.pitch.toFloat() else null @JvmStatic val movementYaw: Float? get() { - val config = currentContext?.config ?: return null + val config = currentRequest?.config ?: return null if (config.rotationMode == RotationMode.SILENT) return null return currentRotation.yaw.toFloat() } @JvmStatic val movementPitch: Float? get() { - val config = currentContext?.config ?: return null + val config = currentRequest?.config ?: return null if (config.rotationMode == RotationMode.SILENT) return null return currentRotation.pitch.toFloat() } @JvmStatic fun getRotationForVector(deltaTime: Double): Vec2d? { - val config = currentContext?.config ?: return null + val config = currentRequest?.config ?: return null if (config.rotationMode == RotationMode.SILENT) return null val rot = lerp(prevRotation, currentRotation, deltaTime) @@ -167,7 +192,7 @@ object RotationManager : Loadable { @JvmStatic fun processPlayerMovement() = runSafe { - val config = currentContext?.config ?: return@runSafe + val config = currentRequest?.config ?: return@runSafe val input = player.input val handledByBaritone = input !is KeyboardInput diff --git a/common/src/main/kotlin/com/lambda/interaction/VisibilityChecker.kt b/common/src/main/kotlin/com/lambda/interaction/VisibilityChecker.kt deleted file mode 100644 index bf397e923..000000000 --- a/common/src/main/kotlin/com/lambda/interaction/VisibilityChecker.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.lambda.interaction - -import com.lambda.context.SafeContext -import com.lambda.util.primitives.extension.component6 -import net.minecraft.util.math.* -import java.util.* - -object VisibilityChecker { - inline fun SafeContext.scanVisibleSurfaces(box: Box, sides: Set, resolution: Int, check: (Vec3d) -> Unit) { - val shrunk = box.expand(-0.005) - getVisibleSides(box) - .forEach { side -> - if (sides.isNotEmpty() && side !in sides) { - return@forEach - } - val (minX, minY, minZ, maxX, maxY, maxZ) = shrunk.bounds(side) - val stepX = (maxX - minX) / resolution - val stepY = (maxY - minY) / resolution - val stepZ = (maxZ - minZ) / resolution - for (i in 0 .. resolution) { - val x = if (stepX != 0.0) minX + stepX * i else minX - for (j in 0 .. resolution) { - val y = if (stepY != 0.0) minY + stepY * j else minY - val z = if (stepZ != 0.0) minZ + stepZ * ((if (stepX != 0.0) j else i)) else minZ - check(Vec3d(x, y, z)) - } - } - } - } - - fun Box.bounds(side: Direction) = - when (side) { - Direction.DOWN -> doubleArrayOf(minX, minY, minZ, maxX, minY, maxZ) - Direction.UP -> doubleArrayOf(minX, maxY, minZ, maxX, maxY, maxZ) - Direction.NORTH -> doubleArrayOf(minX, minY, minZ, maxX, maxY, minZ) - Direction.SOUTH -> doubleArrayOf(minX, minY, maxZ, maxX, maxY, maxZ) - Direction.WEST -> doubleArrayOf(minX, minY, minZ, minX, maxY, maxZ) - Direction.EAST -> doubleArrayOf(maxX, minY, minZ, maxX, maxY, maxZ) - } - - fun SafeContext.getVisibleSides(box: Box): Set { - val visibleSides = EnumSet.noneOf(Direction::class.java) - - val eyePos = player.eyePos - val center = box.center - - return visibleSides - .checkAxis(eyePos.x - center.x, box.lengthX / 2, Direction.WEST, Direction.EAST) - .checkAxis(eyePos.y - center.y, box.lengthY / 2, Direction.DOWN, Direction.UP) - .checkAxis(eyePos.z - center.z, box.lengthZ / 2, Direction.NORTH, Direction.SOUTH) - } - - private fun EnumSet.checkAxis( - diff: Double, - limit: Double, - negativeSide: Direction, - positiveSide: Direction - ) = apply { - when { - diff < -limit -> { - add(negativeSide) - } - diff > limit -> { - add(positiveSide) - } - } - } -} diff --git a/common/src/main/kotlin/com/lambda/interaction/rotation/RotationRequest.kt b/common/src/main/kotlin/com/lambda/interaction/rotation/RotationRequest.kt new file mode 100644 index 000000000..27282e1e1 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/interaction/rotation/RotationRequest.kt @@ -0,0 +1,11 @@ +package com.lambda.interaction.rotation + +data class RotationRequest( + val priority: Int = 1, + val config: IRotationConfig, + val rotation: Rotation, + var isPending: Boolean = true +) : Comparable { + override fun compareTo(other: RotationRequest) = + priority.compareTo(other.priority) +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/interaction/visibilty/EntityInteraction.kt b/common/src/main/kotlin/com/lambda/interaction/visibilty/EntityInteraction.kt new file mode 100644 index 000000000..c9098e5bc --- /dev/null +++ b/common/src/main/kotlin/com/lambda/interaction/visibilty/EntityInteraction.kt @@ -0,0 +1,4 @@ +package com.lambda.interaction.visibilty + +object EntityInteraction { +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/interaction/visibilty/VisibilityChecker.kt b/common/src/main/kotlin/com/lambda/interaction/visibilty/VisibilityChecker.kt new file mode 100644 index 000000000..72a87f787 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/interaction/visibilty/VisibilityChecker.kt @@ -0,0 +1,144 @@ +package com.lambda.interaction.visibilty + +import com.lambda.config.RotationSettings +import com.lambda.context.SafeContext +import com.lambda.interaction.InteractionConfig +import com.lambda.interaction.RotationManager +import com.lambda.interaction.rotation.IRotationConfig +import com.lambda.interaction.rotation.Rotation +import com.lambda.interaction.rotation.Rotation.Companion.distance +import com.lambda.interaction.rotation.Rotation.Companion.rotationTo +import com.lambda.interaction.rotation.RotationRequest +import com.lambda.util.math.VecUtils.distSq +import com.lambda.util.primitives.extension.component6 +import net.minecraft.util.hit.HitResult +import net.minecraft.util.math.* +import java.util.* + +object VisibilityChecker { + fun SafeContext.findRotation( + rotationConfig: IRotationConfig, + interact: InteractionConfig, + boxes: List, + priority: Int = 0, + sides: Set = emptySet(), + hitCheck: HitResult.() -> Boolean, + ) : RotationRequest? { + val eye = player.getCameraPosVec(mc.tickDelta) + + if (boxes.any { it.contains(eye) }) { + return stay(priority, rotationConfig) + } + + val currentRotation = RotationManager.currentRotation + val currentCast = currentRotation.rayCast( + interact.reach, + interact.rayCastMask, + eye + ) + val check = currentCast?.let { it.hitCheck() } ?: false + + // Slowdown or freeze if looking correct + (rotationConfig as? RotationSettings)?.slowdownIf(check) ?: run { + if (check) { + return stay(priority, rotationConfig) + } + } + + val reachSq = interact.reach * interact.reach + + var closestRotation: Rotation? = null + var rotationDist = 0.0 + + boxes.forEach { box -> + scanVisibleSurfaces(box, sides, interact.resolution) { vec -> + if (eye distSq vec > reachSq) return@scanVisibleSurfaces + + val newRotation = eye.rotationTo(vec) + + val cast = newRotation.rayCast( + interact.reach, + interact.rayCastMask, + eye + ) ?: return@scanVisibleSurfaces + if (!cast.hitCheck()) return@scanVisibleSurfaces + + val dist = newRotation.distance(currentRotation) + if (dist >= rotationDist && closestRotation != null) return@scanVisibleSurfaces + + rotationDist = dist + closestRotation = newRotation + } + } + + // Rotate to selected point + closestRotation?.let { rotation -> + return RotationRequest(priority, rotationConfig, rotation) + } + + return null + } + + private fun stay(priority: Int = 0, config: IRotationConfig) = + RotationRequest(priority, config, RotationManager.currentRotation) + + inline fun SafeContext.scanVisibleSurfaces(box: Box, sides: Set, resolution: Int, check: (Vec3d) -> Unit) { + val shrunk = box.expand(-0.005) + getVisibleSides(box) + .forEach { side -> + if (sides.isNotEmpty() && side !in sides) { + return@forEach + } + val (minX, minY, minZ, maxX, maxY, maxZ) = shrunk.bounds(side) + val stepX = (maxX - minX) / resolution + val stepY = (maxY - minY) / resolution + val stepZ = (maxZ - minZ) / resolution + for (i in 0 .. resolution) { + val x = if (stepX != 0.0) minX + stepX * i else minX + for (j in 0 .. resolution) { + val y = if (stepY != 0.0) minY + stepY * j else minY + val z = if (stepZ != 0.0) minZ + stepZ * ((if (stepX != 0.0) j else i)) else minZ + check(Vec3d(x, y, z)) + } + } + } + } + + fun Box.bounds(side: Direction) = + when (side) { + Direction.DOWN -> doubleArrayOf(minX, minY, minZ, maxX, minY, maxZ) + Direction.UP -> doubleArrayOf(minX, maxY, minZ, maxX, maxY, maxZ) + Direction.NORTH -> doubleArrayOf(minX, minY, minZ, maxX, maxY, minZ) + Direction.SOUTH -> doubleArrayOf(minX, minY, maxZ, maxX, maxY, maxZ) + Direction.WEST -> doubleArrayOf(minX, minY, minZ, minX, maxY, maxZ) + Direction.EAST -> doubleArrayOf(maxX, minY, minZ, maxX, maxY, maxZ) + } + + fun SafeContext.getVisibleSides(box: Box): Set { + val visibleSides = EnumSet.noneOf(Direction::class.java) + + val eyePos = player.eyePos + val center = box.center + + return visibleSides + .checkAxis(eyePos.x - center.x, box.lengthX / 2, Direction.WEST, Direction.EAST) + .checkAxis(eyePos.y - center.y, box.lengthY / 2, Direction.DOWN, Direction.UP) + .checkAxis(eyePos.z - center.z, box.lengthZ / 2, Direction.NORTH, Direction.SOUTH) + } + + private fun EnumSet.checkAxis( + diff: Double, + limit: Double, + negativeSide: Direction, + positiveSide: Direction + ) = apply { + when { + diff < -limit -> { + add(negativeSide) + } + diff > limit -> { + add(positiveSide) + } + } + } +} diff --git a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt b/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt index 2277ca6b5..2efdabd38 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt @@ -5,8 +5,6 @@ import com.lambda.config.RotationSettings import com.lambda.event.events.RotationEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.module.Module -import com.lambda.util.world.EntityUtils.getClosestEntity -import net.minecraft.entity.passive.VillagerEntity import net.minecraft.util.Hand import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.math.BlockPos @@ -30,13 +28,27 @@ object RotationTest : Module( side = hit.side } - listener { + listener { event -> // val target = getClosestEntity( // player.eyePos, interaction.reachDistance.toDouble() // ) ?: return@listener - it.lookAt(rotationConfig, interactionConfig, pos, setOf(side)) + event.lookAtBlock(rotationConfig, interactionConfig, pos, setOf(side)) + } + + listener { + (mc.crosshairTarget as? BlockHitResult)?.let { hit -> + if (hit.blockPos != pos || hit.side != side) { + interaction.cancelBlockBreaking() + return@listener + } + + interaction.updateBlockBreakingProgress(pos, side) + player.swingHand(Hand.MAIN_HAND) + return@listener + } + interaction.cancelBlockBreaking() } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt index 2cad65113..7d2542469 100644 --- a/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt @@ -1,7 +1,7 @@ package com.lambda.util.player import com.lambda.context.SafeContext -import com.lambda.manager.RotationManager +import com.lambda.interaction.RotationManager import com.lambda.util.math.MathUtils.random import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.MathUtils.toRadian