From f3757f6fbd378ef88e70e925cac6a3c84f298d8e Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 8 Aug 2024 16:02:05 +0300 Subject: [PATCH 01/16] Global toggle sounds --- .../lambda/gui/impl/clickgui/buttons/ModuleButton.kt | 12 ++++-------- common/src/main/kotlin/com/lambda/module/Module.kt | 10 ++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 86ec9933c..df80cf068 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -174,12 +174,11 @@ class ModuleButton( } override fun performClickAction(e: GuiEvent.MouseClick) { - val sound = when (e.button) { + when (e.button) { Mouse.Button.Left -> { module.toggle() - if (module.isEnabled) LambdaSound.MODULE_ON else LambdaSound.MODULE_OFF - } + } Mouse.Button.Right -> { // Don't let user spam val targetHeight = if (isOpen) settingsHeight else 0.0 @@ -189,13 +188,10 @@ class ModuleButton( if (isOpen) settingsLayer.onEvent(GuiEvent.Show()) updateHeight() - if (isOpen) LambdaSound.SETTINGS_OPEN else LambdaSound.SETTINGS_CLOSE + val sound = if (isOpen) LambdaSound.SETTINGS_OPEN else LambdaSound.SETTINGS_CLOSE + playSoundRandomly(sound.event) } - - else -> return } - - playSoundRandomly(sound.event) } override fun equals(other: Any?) = diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 4cca48a40..61545b980 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -18,6 +18,8 @@ import com.lambda.gui.impl.clickgui.LambdaClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.module.modules.client.ClickGui import com.lambda.module.tag.ModuleTag +import com.lambda.sound.LambdaSound +import com.lambda.sound.SoundManager.playSoundRandomly import com.lambda.util.KeyCode import com.lambda.util.Nameable @@ -119,6 +121,14 @@ abstract class Module( || screen is LambdaClickGui) ) toggle() } + + onEnable { + playSoundRandomly(LambdaSound.MODULE_ON.event) + } + + onDisable { + playSoundRandomly(LambdaSound.MODULE_OFF.event) + } } fun enable() { From 65751e3e0d84ae6c7d2c43bb16107c9383187f98 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sat, 10 Aug 2024 13:37:37 +0300 Subject: [PATCH 02/16] Tickshift improvements --- .../lambda/mixin/MinecraftClientMixin.java | 10 ++++++++++ .../com/lambda/event/events/TickEvent.kt | 19 +++++++++++++++++-- .../lambda/module/modules/movement/Blink.kt | 18 ++++++++++++------ .../module/modules/movement/TickShift.kt | 11 +++++++---- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index 9ffcd5c65..6c92d6558 100644 --- a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -35,6 +35,16 @@ void onTickPost(CallbackInfo ci) { EventFlow.post(new TickEvent.Post()); } + @Inject(method = "render", at = @At("HEAD")) + void onLoopTickPre(CallbackInfo ci) { + EventFlow.post(new TickEvent.GameLoop.Pre()); + } + + @Inject(method = "render", at = @At("RETURN")) + void onLoopTickPost(CallbackInfo ci) { + EventFlow.post(new TickEvent.GameLoop.Post()); + } + @Inject(at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;info(Ljava/lang/String;)V", shift = At.Shift.AFTER, remap = false), method = "stop") private void onShutdown(CallbackInfo ci) { EventFlow.post(new ClientEvent.Shutdown()); diff --git a/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt b/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt index 85f9b1a0a..d47597fdb 100644 --- a/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/TickEvent.kt @@ -18,15 +18,30 @@ import com.lambda.event.events.TickEvent.Pre */ abstract class TickEvent : Event { /** - * A class representing a [TickEvent] that is triggered before each tick of the game loop. + * A class representing a [TickEvent] that is triggered before each tick of the tick loop. */ class Pre : TickEvent() /** - * A class representing a [TickEvent] that is triggered after each tick of the game loop. + * A class representing a [TickEvent] that is triggered after each tick of the tick loop. */ class Post : TickEvent() + /** + * A class representing a [TickEvent] that is triggered on each tick of the game loop. + */ + abstract class GameLoop : TickEvent() { + /** + * A class representing a [TickEvent.Player] that is triggered before each tick of the game loop. + */ + class Pre : TickEvent() + + /** + * A class representing a [TickEvent.Player] that is triggered after each tick of the game loop. + */ + class Post : TickEvent() + } + /** * A class representing a [TickEvent] that is triggered when the player gets ticked. */ diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt index ddae9757b..702931923 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt @@ -14,10 +14,12 @@ import com.lambda.util.ClientPacket import com.lambda.util.PacketUtils.handlePacketSilently import com.lambda.util.PacketUtils.sendPacketSilently import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.VecUtils.minus import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d import java.util.concurrent.ConcurrentLinkedDeque object Blink : Module( @@ -61,6 +63,16 @@ object Blink : Module( return@listener } + listener { event -> + val packet = event.packet + if (packet !is PlayerMoveC2SPacket) return@listener + + val vec = Vec3d(packet.getX(0.0), packet.getY(0.0), packet.getZ(0.0)) + if (vec == Vec3d.ZERO) return@listener + + lastBox = player.boundingBox.offset(vec - player.pos) + } + listener { event -> if (!isActive || !shiftVelocity) return@listener @@ -81,12 +93,6 @@ object Blink : Module( while (packetPool.isNotEmpty()) { packetPool.poll().let { packet -> connection.sendPacketSilently(packet) - - if (packet is PlayerMoveC2SPacket && packet.changesPosition()) { - lastBox = player.boundingBox - .offset(player.pos.negate()) - .offset(packet.getX(0.0), packet.getY(0.0), packet.getZ(0.0)) - } } } diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt index 1f9d92f1c..893674986 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt @@ -26,10 +26,13 @@ object TickShift : Module( private val boostAmount by setting("Boost", 3.0, 1.1..20.0, 0.01) private val slowdown by setting("Slowdown", 0.35, 0.01..0.9, 0.01) private val delaySetting by setting("Delay", 0, 0..2000, 10) - private val strict by setting("Strict", true) - private val shiftVelocity by setting("Shift velocity", true) + private val grim by setting("Grim", true) + private val strictSetting by setting("Strict", true) { !grim } + private val shiftVelocity by setting("Shift velocity", true) { grim } private val requiresAura by setting("Requires Aura", false) + private val strict get() = grim || strictSetting + val isActive: Boolean get() { if (requiresAura && (!KillAura.isEnabled || KillAura.target == null)) return false return System.currentTimeMillis() - lastBoost > delaySetting @@ -90,7 +93,7 @@ object TickShift : Module( } listener { event -> - if (!isActive) return@listener + if (!isActive || !grim || event.isCanceled()) return@listener if (event.packet !is CommonPongC2SPacket) return@listener pingPool.add(event.packet) @@ -99,7 +102,7 @@ object TickShift : Module( } listener { event -> - if (!isActive || !shiftVelocity) return@listener + if (!isActive || !grim || !shiftVelocity || event.isCanceled()) return@listener if (event.packet !is EntityVelocityUpdateS2CPacket) return@listener if (event.packet.id != player.id) return@listener From 7df4edd16e71e4e413f300b94ecec335e318211a Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Tue, 13 Aug 2024 17:08:36 +0300 Subject: [PATCH 03/16] Misc fixes --- common/src/main/kotlin/com/lambda/config/groups/Targeting.kt | 2 ++ .../src/main/kotlin/com/lambda/module/modules/movement/Speed.kt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/common/src/main/kotlin/com/lambda/config/groups/Targeting.kt b/common/src/main/kotlin/com/lambda/config/groups/Targeting.kt index aef28e9bf..5d536b1d6 100644 --- a/common/src/main/kotlin/com/lambda/config/groups/Targeting.kt +++ b/common/src/main/kotlin/com/lambda/config/groups/Targeting.kt @@ -10,6 +10,7 @@ import com.lambda.util.math.VecUtils.distSq import com.lambda.util.world.WorldUtils.getFastEntities import net.minecraft.client.network.ClientPlayerEntity import net.minecraft.entity.LivingEntity +import net.minecraft.entity.decoration.ArmorStandEntity import net.minecraft.entity.mob.MobEntity import net.minecraft.entity.passive.PassiveEntity @@ -45,6 +46,7 @@ abstract class Targeting( !players && entity.isPlayer -> false !animals && entity is PassiveEntity -> false !hostiles && entity is MobEntity -> false + entity is ArmorStandEntity -> false !invisible && entity.isInvisibleTo(player) -> false !dead && entity.isDead -> false diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt index ea49516a9..ccb068f27 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt @@ -111,7 +111,7 @@ object Speed : Module( // TODO: Diagonal movement when not jumping // needs movement prediction engine or a workaround to detect jumping 1 tick before - listener { event -> + listener(100) { event -> if (mode != Mode.GRIM_STRAFE) return@listener if (!shouldWork() || !isInputting) return@listener if (player.input.handledByBaritone || TargetStrafe.isActive) return@listener From d03121aa54dea937cbeea181cfe0e96273f74049 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 16 Aug 2024 12:44:07 +0300 Subject: [PATCH 04/16] Refactored raycast, rotation movement utils --- .../com/lambda/interaction/RotationManager.kt | 6 ++--- .../lambda/module/modules/movement/Speed.kt | 25 +++++++++++-------- .../com/lambda/util/player/MovementUtils.kt | 5 +++- .../lambda/util/world/raycast/RayCastUtils.kt | 5 +++- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt index 9f1f4f7f3..922778a29 100644 --- a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt @@ -38,13 +38,13 @@ object RotationManager : Loadable { fun Any.requestRotation( priority: Int = 0, alwaysListen: Boolean = false, - onUpdate: SafeContext.() -> RotationContext?, - onReceive: SafeContext.() -> Unit + onUpdate: SafeContext.(lastContext: RotationContext?) -> RotationContext?, + onReceive: SafeContext.() -> Unit = {} ) { var lastCtx: RotationContext? = null this.listener(priority, alwaysListen) { event -> - val rotationContext = onUpdate() + val rotationContext = onUpdate(event.context) rotationContext?.let { event.context = it diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt index ccb068f27..48b957884 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt @@ -6,6 +6,7 @@ import com.lambda.event.events.ClientEvent import com.lambda.event.events.MovementEvent import com.lambda.event.events.RotationEvent import com.lambda.event.listener.SafeListener.Companion.listener +import com.lambda.interaction.RotationManager.requestRotation import com.lambda.interaction.rotation.Rotation import com.lambda.interaction.rotation.RotationContext import com.lambda.interaction.rotation.RotationMode @@ -111,17 +112,19 @@ object Speed : Module( // TODO: Diagonal movement when not jumping // needs movement prediction engine or a workaround to detect jumping 1 tick before - listener(100) { event -> - if (mode != Mode.GRIM_STRAFE) return@listener - if (!shouldWork() || !isInputting) return@listener - if (player.input.handledByBaritone || TargetStrafe.isActive) return@listener - - val input = newMovementInput() - val yaw = calcMoveYaw(player.yaw, input.roundedForward, input.roundedStrafing) - val rotation = Rotation(yaw, event.context?.rotation?.pitch ?: player.pitch.toDouble()) - - event.context = RotationContext(rotation, rotationConfig) - } + requestRotation(100, false, + onUpdate = { lastContext -> + if (mode != Mode.GRIM_STRAFE) return@requestRotation null + if (!shouldWork() || !isInputting) return@requestRotation null + if (player.input.handledByBaritone || TargetStrafe.isActive) return@requestRotation null + + val input = newMovementInput() + val yaw = calcMoveYaw(player.yaw, input.roundedForward, input.roundedStrafing) + val rotation = Rotation(yaw, lastContext?.rotation?.pitch ?: player.pitch.toDouble()) + + RotationContext(rotation, rotationConfig) + }, {} + ) onEnable { reset() 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 7186654bc..072b06ed5 100644 --- a/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt @@ -138,9 +138,12 @@ object MovementUtils { val Entity.velocityDelta get() = hypot(this.velocity.x, this.velocity.z) val Entity.octant: EightWayDirection + get() = yaw.octant + + val Float.octant: EightWayDirection get() { // Normalize the yaw to be within the range of -180 to 179 degrees - var normalizedYaw = (yaw + 180.0) % 360.0 + var normalizedYaw = (this + 180.0) % 360.0 if (normalizedYaw < 0) { normalizedYaw += 360.0 } 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 54c8746e1..0dce21481 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 @@ -5,6 +5,7 @@ import com.lambda.context.SafeContext import com.lambda.interaction.rotation.Rotation import com.lambda.threading.runSafe import com.lambda.util.math.VecUtils.distSq +import net.minecraft.client.network.ClientPlayerEntity import net.minecraft.entity.Entity import net.minecraft.entity.projectile.ProjectileUtil import net.minecraft.util.hit.BlockHitResult @@ -16,7 +17,9 @@ import kotlin.math.max import kotlin.math.pow object RayCastUtils { - private val entityPredicate = { entity: Entity -> !entity.isSpectator && entity.canHit() } + private val entityPredicate = { entity: Entity -> + !entity.isSpectator && entity.canHit() && entity !is ClientPlayerEntity + } fun SafeContext.rayCast( start: Vec3d, From 19caa3c5841c7961a8f0f1cd0edcd633c6eda171 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 16 Aug 2024 12:52:53 +0300 Subject: [PATCH 05/16] Placement utils --- .../interaction/blockplace/PlaceFinder.kt | 81 +++++++++++++++++++ .../interaction/blockplace/PlaceInfo.kt | 15 ++++ .../blockplace/PlaceInteraction.kt | 49 +++++++++++ .../visibilty/EntityInteraction.kt | 4 - .../com/lambda/task/tasks/PlaceBlock.kt | 24 +----- .../kotlin/com/lambda/util/math/VecUtils.kt | 10 +++ 6 files changed, 157 insertions(+), 26 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceFinder.kt create mode 100644 common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInfo.kt create mode 100644 common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInteraction.kt delete mode 100644 common/src/main/kotlin/com/lambda/interaction/visibilty/EntityInteraction.kt diff --git a/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceFinder.kt b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceFinder.kt new file mode 100644 index 000000000..648d6af56 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceFinder.kt @@ -0,0 +1,81 @@ +package com.lambda.interaction.blockplace + +import com.lambda.context.SafeContext +import com.lambda.interaction.blockplace.PlaceInteraction.canPlaceAt +import com.lambda.interaction.blockplace.PlaceInteraction.isClickable +import com.lambda.interaction.visibilty.VisibilityChecker.getVisibleSurfaces +import com.lambda.util.BlockUtils.blockState +import com.lambda.util.math.VecUtils.distSq +import com.lambda.util.math.VecUtils.getHitVec +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Box +import net.minecraft.util.math.Direction +import java.util.* +import kotlin.collections.Collection + +class PlaceFinder( + private val basePos: BlockPos, + private val maxAttempts: Int, + range: Double, + private val visibleCheck: Boolean, + private val sides: Set +) { + private val rangeSq = range * range + + private val Collection.selectClosest get() = minByOrNull { it.eyeDistanceSq } + private val Collection.selectBest get() = this.let { infos -> + if (infos.isEmpty()) return@let null + val lowestStepAmount = infos.minOf { it.placeSteps } + infos.filter { it.placeSteps == lowestStepAmount }.selectClosest + } + + companion object { + fun SafeContext.buildPlaceInfo( + basePos: BlockPos, + maxAttempts: Int = 4, + range: Double = 3.25, + visibleCheck: Boolean = true, + sides: Set = EnumSet.allOf(Direction::class.java) + ) = PlaceFinder(basePos, maxAttempts, range, visibleCheck, sides).build(this) + } + + private fun build( + ctx: SafeContext, + pos: BlockPos = basePos, + attempts: Int = 0 + ): PlaceInfo? = with(ctx) { + if (sides.isEmpty()) return null + if (!canPlaceAt(pos)) return null + + sides.mapNotNull { checkSide(pos, it, attempts) }.selectClosest?.let { + return it + } + + if (attempts > maxAttempts) return null + + return sides.mapNotNull { side -> + build(this, pos.offset(side), attempts + 1) + }.selectBest + } + + private fun SafeContext.checkSide(pos: BlockPos, side: Direction, attempts: Int): PlaceInfo? { + val eye = player.eyePos + + val clickPos = pos.offset(side) + val clickSide = side.opposite + + val hitVec = clickPos.getHitVec(clickSide) + val distSq = eye distSq hitVec + + if (distSq > rangeSq) return null + if (clickPos.blockState(world).isClickable) return null + + if (visibleCheck) { + val box = Box(clickPos) + val visible = box.getVisibleSurfaces(eye) + if (clickSide !in visible) return null + } + + return PlaceInfo(clickPos, clickSide, pos, hitVec, distSq, attempts) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInfo.kt b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInfo.kt new file mode 100644 index 000000000..e21d38428 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInfo.kt @@ -0,0 +1,15 @@ +package com.lambda.interaction.blockplace + +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction +import net.minecraft.util.math.Vec3d + +data class PlaceInfo( + val clickPos: BlockPos, + val clickSide: Direction, + val placedPos: BlockPos, + val hitVec: Vec3d, + + val eyeDistanceSq: Double, + val placeSteps: Int +) \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInteraction.kt b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInteraction.kt new file mode 100644 index 000000000..00b7ae097 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInteraction.kt @@ -0,0 +1,49 @@ +package com.lambda.interaction.blockplace + +import com.lambda.context.SafeContext +import com.lambda.util.Communication.info +import net.minecraft.block.* +import net.minecraft.util.Hand +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World + +object PlaceInteraction { + fun SafeContext.placeBlock(result: BlockHitResult, hand: Hand, swing: Boolean) { + val actionResult = interaction.interactBlock(player, hand, result) + + if (!actionResult.isAccepted) { + info("Internal interaction failed with $actionResult") + return + } + + if (!swing) return + + if (actionResult.shouldSwingHand()) { + player.swingHand(hand) + } + + if (!player.getStackInHand(hand).isEmpty && interaction.hasCreativeInventory()) { + mc.gameRenderer.firstPersonRenderer.resetEquipProgress(hand) + } + } + + fun SafeContext.canPlaceAt(blockPos: BlockPos, state: BlockState = Blocks.OBSIDIAN.defaultState): Boolean { + if (!World.isValid(blockPos)) return false + if (!world.getBlockState(blockPos).isReplaceable) return false + + return world.canPlace(state, blockPos, ShapeContext.absent()) + } + + val BlockState.isClickable get() = isReplaceable || + block is CraftingTableBlock || + block is AnvilBlock || + block is ButtonBlock || + block is AbstractPressurePlateBlock || + block is BlockWithEntity || + block is BedBlock || + block is FenceGateBlock || + block is DoorBlock || + block is NoteBlock || + block is TrapdoorBlock +} \ 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 deleted file mode 100644 index c9098e5bc..000000000 --- a/common/src/main/kotlin/com/lambda/interaction/visibilty/EntityInteraction.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.lambda.interaction.visibilty - -object EntityInteraction { -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/task/tasks/PlaceBlock.kt b/common/src/main/kotlin/com/lambda/task/tasks/PlaceBlock.kt index 5359feaf8..65a5c550d 100644 --- a/common/src/main/kotlin/com/lambda/task/tasks/PlaceBlock.kt +++ b/common/src/main/kotlin/com/lambda/task/tasks/PlaceBlock.kt @@ -6,11 +6,11 @@ import com.lambda.core.PingManager import com.lambda.event.events.RotationEvent import com.lambda.event.events.WorldEvent import com.lambda.event.listener.SafeListener.Companion.listener +import com.lambda.interaction.blockplace.PlaceInteraction.placeBlock import com.lambda.interaction.construction.context.PlaceContext import com.lambda.module.modules.client.TaskFlow import com.lambda.task.Task import com.lambda.util.BlockUtils.blockState -import com.lambda.util.Communication.info import net.minecraft.block.BlockState class PlaceBlock @Ta5kBuilder constructor( @@ -72,27 +72,7 @@ class PlaceBlock @Ta5kBuilder constructor( } private fun SafeContext.placeBlock() { - val actionResult = interaction.interactBlock( - player, - ctx.hand, - ctx.result - ) - - if (actionResult.isAccepted) { - if (actionResult.shouldSwingHand() && swingHand) { - player.swingHand(ctx.hand) - } - - if (!player.getStackInHand(ctx.hand).isEmpty && interaction.hasCreativeInventory()) { - mc.gameRenderer.firstPersonRenderer.resetEquipProgress(ctx.hand) - } - - if (matches) { - if (!waitForConfirmation) finish() - } - } else { - info("Internal interaction failed with $actionResult") - } + placeBlock(ctx.result, ctx.hand, swingHand) } private fun SafeContext.finish() { diff --git a/common/src/main/kotlin/com/lambda/util/math/VecUtils.kt b/common/src/main/kotlin/com/lambda/util/math/VecUtils.kt index 21d3626fc..102e81634 100644 --- a/common/src/main/kotlin/com/lambda/util/math/VecUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/math/VecUtils.kt @@ -2,6 +2,7 @@ package com.lambda.util.math import com.lambda.util.math.MathUtils.sq import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3i import kotlin.math.pow @@ -11,6 +12,14 @@ object VecUtils { val Vec3d.blockPos: BlockPos get() = BlockPos(x.roundToInt(), y.roundToInt(), z.roundToInt()) + val Vec3i.vec3d get() = Vec3d.of(this) + + fun BlockPos.getHitVec(side: Direction) = + vec3d + side.hitVecOffset + + val Direction.hitVecOffset get() = + CENTER + vector.vec3d * 0.5 + infix fun Vec3d.dist(other: Vec3d): Double = this.distanceTo(other) infix fun Vec3d.distSq(other: Vec3d): Double = this.squaredDistanceTo(other) @@ -35,4 +44,5 @@ object VecUtils { val UP = Vec3d(0.0, 1.0, 0.0) val DOWN = Vec3d(0.0, -1.0, 0.0) + val CENTER = Vec3d(0.5, 0.5, 0.5) } From 3a42ff773936a9608803a89445a35e0d21c06646 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 16 Aug 2024 12:54:48 +0300 Subject: [PATCH 06/16] PlayerPacketManager changes --- .../lambda/event/events/PlayerPacketEvent.kt | 4 +- .../lambda/interaction/PlayerPacketManager.kt | 49 +++++++++++++------ 2 files changed, 38 insertions(+), 15 deletions(-) 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 a60a9c5d1..c30b85e7d 100644 --- a/common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt @@ -16,7 +16,9 @@ abstract class PlayerPacketEvent : Event { var isSneaking: Boolean, ) : PlayerPacketEvent(), ICancellable by Cancellable() - class Post( + class Post : PlayerPacketEvent() + + class Send( val packet: PlayerMoveC2SPacket, ) : PlayerPacketEvent(), ICancellable by Cancellable() } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt b/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt index 05f26ca5b..65484ebae 100644 --- a/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt @@ -5,7 +5,7 @@ import com.lambda.core.Loadable import com.lambda.event.EventFlow.post import com.lambda.event.EventFlow.postChecked import com.lambda.event.events.PlayerPacketEvent -import com.lambda.interaction.rotation.Rotation.Companion.fixSensitivity +import com.lambda.interaction.rotation.Rotation import com.lambda.threading.runSafe import com.lambda.util.collections.LimitedOrderedSet import com.lambda.util.math.VecUtils.approximate @@ -16,9 +16,17 @@ 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.Vec3d object PlayerPacketManager : Loadable { val configurations = LimitedOrderedSet(100) + + var lastPosition = Vec3d.ZERO + var lastRotation = Rotation.ZERO + var lastSprint = false + var lastSneak = false + var lastOnGround = false + private var sendTicks = 0 @JvmStatic @@ -37,11 +45,10 @@ object PlayerPacketManager : Loadable { } private fun SafeContext.updatePlayerPackets(new: PlayerPacketEvent.Pre) { - val previous = configurations.lastOrNull() ?: new configurations.add(new) - reportSprint(previous, new) - reportSneak(previous, new) + reportSprint(lastSprint, new.isSprinting) + reportSneak(lastSneak, new.isSneaking) if (mc.cameraEntity != player) return @@ -64,9 +71,9 @@ object PlayerPacketManager : Loadable { return } - val updatePosition = position.approximate(previous.position, 2.0E-4) || ++sendTicks >= 20 + val updatePosition = position.approximate(lastPosition, 2.0E-4) || ++sendTicks >= 20 // has to be different in float precision - val updateRotation = !rotation.equalFloat(previous.rotation) + val updateRotation = !rotation.equalFloat(lastRotation) val (x, y, z) = position @@ -83,7 +90,7 @@ object PlayerPacketManager : Loadable { LookAndOnGround(yaw, pitch, onGround) } - previous.onGround != onGround -> { + lastOnGround != onGround -> { OnGroundOnly(onGround) } @@ -95,34 +102,48 @@ object PlayerPacketManager : Loadable { } packet?.let { - PlayerPacketEvent.Post(it).postChecked { + PlayerPacketEvent.Send(it).postChecked { connection.sendPacket(this.packet) + + if (updatePosition) { + lastPosition = position + } + + if (updateRotation) { + lastRotation = rotation + } + + lastOnGround = onGround } } + + PlayerPacketEvent.Post().post() } - private fun SafeContext.reportSprint(previous: PlayerPacketEvent.Pre, new: PlayerPacketEvent.Pre) { - if (previous.isSprinting == new.isSprinting) return + fun SafeContext.reportSprint(previous: Boolean, new: Boolean) { + if (previous == new) return - val state = if (new.isSprinting) { + val state = if (new) { ClientCommandC2SPacket.Mode.START_SPRINTING } else { ClientCommandC2SPacket.Mode.STOP_SPRINTING } connection.sendPacket(ClientCommandC2SPacket(player, state)) + lastSprint = new } - private fun SafeContext.reportSneak(previous: PlayerPacketEvent.Pre, new: PlayerPacketEvent.Pre) { - if (previous.isSneaking == new.isSneaking) return + fun SafeContext.reportSneak(previous: Boolean, new: Boolean) { + if (previous == new) return - val state = if (new.isSneaking) { + val state = if (new) { ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY } else { ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY } connection.sendPacket(ClientCommandC2SPacket(player, state)) + lastSneak = new } } From 07ee52f215edc121a8bfcda6f1d70f6af2dbd30b Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Wed, 21 Aug 2024 13:01:58 +0300 Subject: [PATCH 07/16] Refactor: BlockUtils & PlaceFinder --- .../com/lambda/interaction/blockplace/PlaceFinder.kt | 11 ++++++----- common/src/main/kotlin/com/lambda/util/BlockUtils.kt | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceFinder.kt b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceFinder.kt index 648d6af56..5db3da3e6 100644 --- a/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceFinder.kt +++ b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceFinder.kt @@ -10,6 +10,7 @@ import com.lambda.util.math.VecUtils.getHitVec 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 java.util.* import kotlin.collections.Collection @@ -17,6 +18,7 @@ class PlaceFinder( private val basePos: BlockPos, private val maxAttempts: Int, range: Double, + private val eyes: Vec3d, private val visibleCheck: Boolean, private val sides: Set ) { @@ -34,9 +36,10 @@ class PlaceFinder( basePos: BlockPos, maxAttempts: Int = 4, range: Double = 3.25, + eyes: Vec3d = player.eyePos, visibleCheck: Boolean = true, sides: Set = EnumSet.allOf(Direction::class.java) - ) = PlaceFinder(basePos, maxAttempts, range, visibleCheck, sides).build(this) + ) = PlaceFinder(basePos, maxAttempts, range, eyes, visibleCheck, sides).build(this) } private fun build( @@ -59,20 +62,18 @@ class PlaceFinder( } private fun SafeContext.checkSide(pos: BlockPos, side: Direction, attempts: Int): PlaceInfo? { - val eye = player.eyePos - val clickPos = pos.offset(side) val clickSide = side.opposite val hitVec = clickPos.getHitVec(clickSide) - val distSq = eye distSq hitVec + val distSq = eyes distSq hitVec if (distSq > rangeSq) return null if (clickPos.blockState(world).isClickable) return null if (visibleCheck) { val box = Box(clickPos) - val visible = box.getVisibleSurfaces(eye) + val visible = box.getVisibleSurfaces(eyes) if (clickSide !in visible) return null } diff --git a/common/src/main/kotlin/com/lambda/util/BlockUtils.kt b/common/src/main/kotlin/com/lambda/util/BlockUtils.kt index b60bbd435..6741d5cc5 100644 --- a/common/src/main/kotlin/com/lambda/util/BlockUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/BlockUtils.kt @@ -3,6 +3,7 @@ package com.lambda.util import com.lambda.context.SafeContext import com.lambda.util.item.ItemUtils.block import com.lambda.util.item.ItemUtils.shulkerBoxes +import com.lambda.util.math.MathUtils.floorToInt import net.minecraft.block.Block import net.minecraft.block.BlockState import net.minecraft.block.Blocks @@ -11,7 +12,6 @@ import net.minecraft.fluid.Fluids import net.minecraft.item.Item import net.minecraft.util.math.* import net.minecraft.world.BlockView -import kotlin.math.floor object BlockUtils { private val shulkerBlocks = shulkerBoxes.map { it.block } @@ -106,7 +106,7 @@ object BlockUtils { } val Vec3i.blockPos: BlockPos get() = BlockPos(this) val Block.item: Item get() = asItem() - val Vec3d.flooredPos: BlockPos get() = BlockPos(floor(x).toInt(), floor(y).toInt(), floor(z).toInt()) + val Vec3d.flooredPos: BlockPos get() = BlockPos(x.floorToInt(), y.floorToInt(), z.floorToInt()) fun BlockPos.vecOf(direction: Direction): Vec3d = toCenterPos().add(Vec3d.of(direction.vector).multiply(0.5)) fun BlockPos.offset(eightWayDirection: EightWayDirection, amount: Int): BlockPos = add(eightWayDirection.offsetX * amount, 0, eightWayDirection.offsetZ * amount) From 069431a2171f7b93b3ae5bb6a4b3b8ed181ffd33 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Wed, 21 Aug 2024 15:32:42 +0300 Subject: [PATCH 08/16] Scaffold & MovementPrediction --- .../lambda/config/groups/RotationSettings.kt | 4 +- .../lambda/module/modules/combat/KillAura.kt | 29 +- .../lambda/module/modules/player/Scaffold.kt | 261 ++++++++++++++++++ .../lambda/util/player/MovementPrediction.kt | 244 ++++++++++++++++ .../src/main/resources/lambda.accesswidener | 2 + 5 files changed, 534 insertions(+), 6 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt create mode 100644 common/src/main/kotlin/com/lambda/util/player/MovementPrediction.kt diff --git a/common/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt b/common/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt index f5e038bb0..5135bb10c 100644 --- a/common/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt +++ b/common/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt @@ -16,8 +16,8 @@ class RotationSettings( vis ) - override val keepTicks by c.setting("Keep Rotation", 3, 1..10, 1, "Ticks to keep rotation", " ticks", vis) - override val resetTicks by c.setting("Reset Rotation", 3, 1..10, 1, "Ticks before rotation is reset", " ticks", vis) + override val keepTicks by c.setting("Keep Rotation", 3, 0..30, 1, "Ticks to keep rotation", " ticks", vis) + override val resetTicks by c.setting("Reset Rotation", 3, 0..10, 1, "Ticks before rotation is reset", " ticks", vis) /** * If true, rotation will be instant without any transition. If false, rotation will transition over time. diff --git a/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt b/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt index a17f46a0e..d981a5202 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt @@ -22,10 +22,10 @@ import com.lambda.threading.runSafe import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.random import com.lambda.util.math.VecUtils.distSq -import com.lambda.util.math.VecUtils.minus import com.lambda.util.math.VecUtils.plus import com.lambda.util.math.VecUtils.times import com.lambda.util.player.MovementUtils.moveDiff +import com.lambda.util.player.predictPlayerMovement import com.lambda.util.world.raycast.RayCastUtils.entityResult import kotlinx.coroutines.delay import net.minecraft.entity.EquipmentSlot @@ -64,6 +64,7 @@ object KillAura : Module( private val rotate by setting("Rotate", true) { page == Page.Aiming } private val rotation = RotationSettings(this) { page == Page.Aiming && rotate } private val stabilize by setting("Stabilize", true) { page == Page.Aiming && !rotation.instant && rotate } + private val stabilizationSpeed by setting("Stabilization Speed", 1.0, 0.1..3.0, 0.01) { page == Page.Aiming && !rotation.instant && rotate && stabilize } private val centerFactor by setting("Center Factor", 0.4, 0.0..1.0, 0.01) { page == Page.Aiming && rotate } private val shakeFactor by setting("Shake Factor", 0.4, 0.0..1.0, 0.01) { page == Page.Aiming && rotate } private val shakeChance by setting("Shake Chance", 0.2, 0.05..1.0, 0.01) { page == Page.Aiming && shakeFactor > 0.0 && rotate } @@ -153,7 +154,27 @@ object KillAura : Module( private fun SafeContext.buildRotation(target: LivingEntity): RotationContext? { val currentRotation = RotationManager.currentRotation - val eye = player.getCameraPosVec(1f) + val prediction = predictPlayerMovement(1) + + val eye = when { + selfPredict < 1 -> { + lerp(player.eyePos, prediction.eyePos, selfPredict) + } + + selfPredict < 2 -> { + val pos1 = prediction.eyePos + prediction.tickMovement(this) + val pos2 = prediction.eyePos + + lerp(pos1, pos2, selfPredict - 1) + } + + else -> { + prediction.tickMovement(this) + prediction.eyePos + } + } + val box = target.boundingBox val reach = targeting.targetingRange + 2.0 @@ -170,7 +191,7 @@ object KillAura : Module( with(rotation) { val targetSpeed = if (slowDown) 0.0 else 1.0 - val acceleration = if (slowDown) 0.2 else 0.1 + val acceleration = if (slowDown) 0.2 * stabilizationSpeed else 0.1 / stabilizationSpeed targetSpeed.coerceIn( speedMultiplier - acceleration, @@ -229,7 +250,7 @@ object KillAura : Module( vec = validHits.minByOrNull { vecRotation dist it.value }?.key ?: return null } - val predictOffset = target.moveDiff * targetPredict - player.moveDiff * Vec3d(1.0, -0.5, 1.0) * selfPredict + val predictOffset = target.moveDiff * targetPredict return RotationContext(eye.rotationTo(vec + predictOffset), rotation) } diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt new file mode 100644 index 000000000..1e4cb78a6 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt @@ -0,0 +1,261 @@ +package com.lambda.module.modules.player + +import com.lambda.config.groups.InteractionSettings +import com.lambda.config.groups.RotationSettings +import com.lambda.context.SafeContext +import com.lambda.event.events.* +import com.lambda.event.listener.SafeListener.Companion.listener +import com.lambda.graphics.renderer.esp.DirectionMask +import com.lambda.graphics.renderer.esp.DirectionMask.buildSideMesh +import com.lambda.graphics.renderer.esp.builders.build +import com.lambda.interaction.RotationManager.currentRotation +import com.lambda.interaction.RotationManager.requestRotation +import com.lambda.interaction.blockplace.PlaceFinder.Companion.buildPlaceInfo +import com.lambda.interaction.blockplace.PlaceInfo +import com.lambda.interaction.blockplace.PlaceInteraction.placeBlock +import com.lambda.interaction.rotation.Rotation +import com.lambda.interaction.rotation.Rotation.Companion.dist +import com.lambda.interaction.rotation.Rotation.Companion.rotationTo +import com.lambda.interaction.rotation.RotationContext +import com.lambda.interaction.visibilty.VisibilityChecker.scanVisibleSurfaces +import com.lambda.module.Module +import com.lambda.module.modules.client.GuiSettings +import com.lambda.module.tag.ModuleTag +import com.lambda.util.math.ColorUtils.multAlpha +import com.lambda.util.math.MathUtils.floorToInt +import com.lambda.util.math.VecUtils.dist +import com.lambda.util.math.VecUtils.distSq +import com.lambda.util.math.transform +import com.lambda.util.player.MovementUtils.calcMoveYaw +import com.lambda.util.player.MovementUtils.isInputting +import com.lambda.util.player.MovementUtils.octant +import com.lambda.util.world.raycast.RayCastUtils.blockResult +import net.minecraft.util.Hand +import net.minecraft.util.hit.BlockHitResult +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 java.util.* +import kotlin.math.floor +import kotlin.math.pow + +object Scaffold : Module( + name = "Scaffold", + description = "Places blocks under the player", + defaultTags = setOf(ModuleTag.PLAYER) +) { + private val page by setting("Page", Page.General) + + private val keepY by setting("Keep Y", true) { page == Page.General } + private val airOnly by setting("In Air Only", true) { page == Page.General } + private val minAirTicks by setting("Min Air Ticks", 3, 1..7) { page == Page.General && airOnly } + private val minPlaceDist by setting("Min Place Dist", 0.1, 0.0..0.3, 0.01) { page == Page.General } + //private val renderPrediction by setting("Render Prediction", false) { page == Page.General } + + private val rotationConfig = RotationSettings(this) { page == Page.Rotation } + private val interactionConfig = InteractionSettings(this) { page == Page.Interaction } + + private var placeInfo: PlaceInfo? = null + private val infoSet = HashSet>() + + private var keepLevel: Int? = null + private var airTicks = 0 + + private val currentTime get() = System.currentTimeMillis() + + private val builderSideMask = EnumSet.allOf(Direction::class.java).apply { + remove(Direction.UP) // Don't place above feet + } + + /*private var prediction: PredictionEntity? = null + private val predictedRenderBox = DynamicAABB() + + private val SafeContext.predictedEyes get() = prediction?.eyePos ?: player.eyePos + private val SafeContext.predictedPos get() = prediction?.position ?: player.pos + private val SafeContext.predictedBox get() = prediction?.boundingBox ?: player.boundingBox*/ + + enum class Page { + General, + Rotation, + Interaction + } + + init { + requestRotation( + onUpdate = { + val info = placeInfo ?: return@requestRotation null + + val pause = getPause(info) + if (pause.rotatePause) return@requestRotation null + + val rotation = rotate(info) ?: return@requestRotation null + RotationContext(rotation, rotationConfig) + }, + onReceive = { + val info = placeInfo ?: return@requestRotation + + val pause = getPause(info) + if (pause.placePause) return@requestRotation + + val result = castRotation(currentRotation, info) ?: return@requestRotation + infoSet.add(info to currentTime) + placeBlock(result, Hand.MAIN_HAND, interactionConfig.swingHand) + } + ) + + listener { + updatePlaceInfo() + + /*prediction = predictPlayerMovement(1) + predictedRenderBox.update(predictedBox)*/ + } + + listener { + airTicks++ + if (player.isOnGround) airTicks = 0 + } + + /*listener { event -> + if (!mc.gameRenderer.camera.isThirdPerson || !renderPrediction) return@listener + + val c = GuiSettings.primaryColor + event.renderer.build(predictedRenderBox, c.multAlpha(0.3), c) + }*/ + + // ToDo: optimize + listener { event -> + val c = GuiSettings.primaryColor + + infoSet.removeIf { + val (info, time) = it + + val pos = info.placedPos + val seconds = (currentTime - time) / 1000.0 + + val sides = buildSideMesh(pos) { meshPos -> + infoSet.any { it.first.placedPos == meshPos } + } + + val box = Box(info.placedPos) + val alpha = transform(seconds, 0.0, 0.5, 1.0, 0.0).coerceIn(0.0, 1.0) + + event.renderer.build( + box, + c.multAlpha(0.3 * alpha), + c.multAlpha(alpha), + sides, + DirectionMask.OutlineMode.AND + ) + + seconds > 1 + } + } + + onEnable { + keepLevel = null + placeInfo = null + airTicks = 0 + + /*prediction = null + predictedRenderBox.reset()*/ + } + } + + private fun SafeContext.updatePlaceInfo() { + placeInfo = null + + val playerPos = player.pos + var y = (floor(playerPos.y) - 0.00001).floorToInt() + + if (keepY && isInputting) { + keepLevel?.let { + if (it <= y) y = it + } + } + + val placePos = BlockPos(playerPos.x.floorToInt(), y, playerPos.z.floorToInt()) + + placeInfo = buildPlaceInfo(placePos, 4, interactionConfig.reach + 1, player.eyePos, true, builderSideMask) + keepLevel = placeInfo?.placedPos?.y ?: keepLevel + } + + private fun SafeContext.rotate(info: PlaceInfo): Rotation? { + val eye = player.eyePos + val validHits = mutableSetOf() + + val reach = interactionConfig.reach + val reachSq = reach.pow(2) + + scanVisibleSurfaces(eye, Box(info.clickPos), setOf(info.clickSide), interactionConfig.resolution) { _, vec -> + if (eye distSq vec > reachSq) return@scanVisibleSurfaces + + if (interactionConfig.useRayCast) { + val newRotation = eye.rotationTo(vec) + castRotation(newRotation, info) ?: return@scanVisibleSurfaces + } + + validHits += vec + } + + val moveYaw = calcMoveYaw(player.yaw).toFloat() + val isDiagonal = moveYaw.octant.directions.size == 2 + + validHits.minByOrNull { + if (isDiagonal) { + currentRotation dist eye.rotationTo(it) + } else { + distanceToEdge(info.clickPos, it) + } + } ?.let { closest -> + return eye.rotationTo(closest) + } + + return null + } + + private fun SafeContext.distanceToEdge(pos: BlockPos, from: Vec3d = player.pos): Double { + val x = player.pos.x.coerceIn(pos.x.toDouble(), pos.x.toDouble() + 1) + val z = player.pos.z.coerceIn(pos.z.toDouble(), pos.z.toDouble() + 1) + val to = Vec3d(x, from.y, z) + + return from dist to + } + + private fun castRotation(rotation: Rotation, info: PlaceInfo): BlockHitResult? { + val blockResult = rotation.rayCast(interactionConfig.reach)?.blockResult ?: return null + if (blockResult.blockPos != info.clickPos || blockResult.side != info.clickSide) return null + return blockResult + } + + private fun SafeContext.getPause(info: PlaceInfo) = Pause.build { + if (airOnly && player.input.jumping && airTicks <= minAirTicks) { + pausePlacement() + } + + if (isInputting) { + val dist = distanceToEdge(info.clickPos) + if (dist < minPlaceDist) { + pausePlacement() + pauseRotation() + } + } + } + + private class Pause { + var rotatePause = false; private set + var placePause = false; private set + + fun pauseRotation() { + rotatePause = true + } + + fun pausePlacement() { + placePause = true + } + + companion object { + fun build(block: Pause.() -> Unit) = Pause().apply(block) + } + } +} diff --git a/common/src/main/kotlin/com/lambda/util/player/MovementPrediction.kt b/common/src/main/kotlin/com/lambda/util/player/MovementPrediction.kt new file mode 100644 index 000000000..766d182e6 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/player/MovementPrediction.kt @@ -0,0 +1,244 @@ +package com.lambda.util.player + +import com.lambda.context.SafeContext +import com.lambda.interaction.rotation.Rotation +import com.lambda.util.BlockUtils.blockState +import com.lambda.util.BlockUtils.flooredPos +import com.lambda.util.math.MathUtils.floorToInt +import com.lambda.util.math.MathUtils.toIntSign +import com.lambda.util.math.MathUtils.toRadian +import com.lambda.util.math.VecUtils +import com.lambda.util.math.VecUtils.minus +import com.lambda.util.math.VecUtils.plus +import com.lambda.util.math.VecUtils.times +import com.lambda.util.player.MovementUtils.motion +import com.lambda.util.player.MovementUtils.moveYaw +import com.lambda.util.player.MovementUtils.movementVector +import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.enchantment.EnchantmentHelper +import net.minecraft.entity.Entity +import net.minecraft.entity.effect.StatusEffects +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.MathHelper +import net.minecraft.util.math.Vec3d +import kotlin.math.abs +import kotlin.math.floor + +/** + * Predicts players movement based on minecraft physics logic + * + * Currently not implemented: + * - Elytra movement + * - Movement in liquids + * - Ladder climbing + * - Movement in webs + * - Sneaking safewalk + * + * And im fucking tired of merging all shit from minecraft + */ +fun SafeContext.predictPlayerMovement(ticks: Int): PredictionEntity { + val simulated = PredictionEntity(player) + + repeat(ticks) { + simulated.tickMovement(this) + } + + return simulated +} + +// Todo: any player entity support +class PredictionEntity(val player: ClientPlayerEntity) { + // Basics + var position = player.pos + var motion = player.motion + var boundingBox = player.boundingBox + + val eyePos get() = position + Vec3d(0.0, player.standingEyeHeight.toDouble(), 0.0) + private var rotation = Rotation(player.moveYaw, player.pitch) + + // Secondary movement-related fields + private var isOnGround = player.isOnGround + private val isSprinting = player.isSprinting + private val isSneaking = player.isSneaking + + // Movement input + private val pressingJump = player.input.jumping + private val forwardMovement = player.input.movementForward.toDouble() + private val strafeMovement = player.input.movementSideways.toDouble() + + private var verticalSpeed = pressingJump.toIntSign().toDouble() + private var forwardSpeed = forwardMovement + private var strafeSpeed = strafeMovement + + // Other shit + private var jumpingCooldown = player.jumpingCooldown + private var velocityAffectingPos = (player.pos - VecUtils.DOWN * 0.001).flooredPos + + private var horizontalCollision = player.horizontalCollision + private var verticalCollision = player.verticalCollision + + /** @see net.minecraft.client.network.ClientPlayerEntity.tickMovement */ + fun tickMovement(ctx: SafeContext) = ctx.apply { + forwardSpeed = forwardMovement + strafeSpeed = strafeMovement + + if (player.isUsingItem) { + forwardSpeed *= 0.2 + strafeSpeed *= 0.2 + } + + if (isSneaking) { + val mod = 0.3f + EnchantmentHelper.getSwiftSneakSpeedBoost(player) + forwardSpeed *= mod + strafeSpeed *= mod + } + + if (jumpingCooldown > 0) { + --jumpingCooldown + } + + val reduceX = abs(motion.x) < 0.03 + val reduceY = abs(motion.y) < 0.03 + val reduceZ = abs(motion.z) < 0.03 + + if (reduceX || reduceY || reduceZ) { + motion = Vec3d( + if (reduceX) 0.0 else motion.x, + if (reduceY) 0.0 else motion.y, + if (reduceZ) 0.0 else motion.z + ) + } + + if (pressingJump && isOnGround && jumpingCooldown == 0) { + jumpingCooldown = 10 + jump() + } + + forwardSpeed *= 0.98 + strafeSpeed *= 0.98 + + travel() + } + + /** @see net.minecraft.entity.LivingEntity.travel */ + private fun SafeContext.travel() { + val travelVec = Vec3d(strafeSpeed, verticalSpeed, forwardSpeed) + + val gravity = when { + motion.y < 0.0 && player.hasStatusEffect(StatusEffects.SLOW_FALLING) -> 0.01 + else -> 0.08 + } + + val slipperiness = velocityAffectingPos.blockState(world).block.slipperiness.toDouble() + var friction = 0.91 + + if (isOnGround) { + friction *= slipperiness + } + + applyMovementInput(travelVec, slipperiness) + move() + + motion += VecUtils.DOWN * gravity + motion *= Vec3d(friction, 0.98, friction) + } + + /** @see net.minecraft.entity.LivingEntity.applyMovementInput */ + private fun SafeContext.applyMovementInput(travelVec: Vec3d, slipperiness: Double) { + val movementSpeed = run { + /** @see net.minecraft.entity.LivingEntity.getMovementSpeed */ + + val slipperinessCubed = slipperiness * slipperiness * slipperiness + val movementSpeed = player.movementSpeed.toDouble() + + val groundSpeed = movementSpeed * (0.216 / slipperinessCubed) + val airSpeed = if (isSprinting) 0.026 else 0.02 + + if (isOnGround) groundSpeed else airSpeed + }.toFloat() + + /** @see net.minecraft.entity.Entity.updateVelocity */ + motion += Entity.movementInputToVelocity(travelVec, movementSpeed, rotation.yawF) + } + + /** @see net.minecraft.entity.Entity.move */ + private fun SafeContext.move() { + var movement = motion + movement = adjustMovementForCollisions(movement) + + if (movement.lengthSquared() > 1.0E-7) { + position += movement + } + + val xCollide = !MathHelper.approximatelyEquals(movement.x, motion.x) + val yCollide = !MathHelper.approximatelyEquals(movement.y, motion.y) + val zCollide = !MathHelper.approximatelyEquals(movement.z, motion.z) + + horizontalCollision = xCollide || zCollide + verticalCollision = yCollide + + isOnGround = yCollide && movement.y < 0.0 + + if (horizontalCollision) { + motion = Vec3d( + if (xCollide) 0.0 else motion.x, + motion.y, + if (zCollide) 0.0 else motion.z + ) + } + + val velocityMultiplier = run { + val f = position.flooredPos.blockState(world).block.velocityMultiplier.toDouble() + val g = velocityAffectingPos.blockState(world).block.velocityMultiplier.toDouble() + if (f == 1.0) g else f + } + + motion *= Vec3d(velocityMultiplier, 1.0, velocityMultiplier) + + boundingBox.apply { + val normalized = offset(-minX, -minY, -minZ).offset(-lengthX * 0.5, 0.0, -lengthZ * 0.5) + boundingBox = normalized.offset(position) + } + + val y = (floor(position.y) - 0.00001).floorToInt() + velocityAffectingPos = BlockPos(position.x.floorToInt(), y, position.z.floorToInt()) + } + + /** @see net.minecraft.entity.LivingEntity.jump */ + private fun SafeContext.jump() { + if (isSprinting) { + val yawRad = rotation.yaw.toRadian() + motion += movementVector(yawRad, 0.0) * 0.2 + } + + /** @see net.minecraft.entity.Entity.getJumpVelocityMultiplier */ + val jumpHeight = run { + val f = position.flooredPos.blockState(world).block.jumpVelocityMultiplier.toDouble() + val g = velocityAffectingPos.blockState(world).block.jumpVelocityMultiplier.toDouble() + if (f == 1.0) g else f + } * 0.42 + player.jumpBoostVelocityModifier + + motion += Vec3d(0.0, jumpHeight, 0.0) + } + + /** @see net.minecraft.entity.Entity.adjustMovementForCollisions */ + private fun SafeContext.adjustMovementForCollisions(movement: Vec3d): Vec3d { + if (movement.lengthSquared() == 0.0) { + return movement + } + + val prevPos = player.pos + val prevBox = player.boundingBox + + player.pos = position + player.boundingBox = boundingBox + + val list = world.getEntityCollisions(player, boundingBox.stretch(movement)) + val processed = Entity.adjustMovementForCollisions(player, movement, boundingBox, world, list) + + player.pos = prevPos + player.boundingBox = prevBox + + return processed + } +} \ No newline at end of file diff --git a/common/src/main/resources/lambda.accesswidener b/common/src/main/resources/lambda.accesswidener index bd4ab6ec7..a047a2237 100644 --- a/common/src/main/resources/lambda.accesswidener +++ b/common/src/main/resources/lambda.accesswidener @@ -19,6 +19,8 @@ accessible method net/minecraft/entity/Entity movementInputToVelocity (Lnet/mine accessible method net/minecraft/entity/passive/AbstractHorseEntity setHorseFlag (IZ)V accessible method net/minecraft/entity/passive/AbstractHorseEntity updateSaddle ()V accessible field net/minecraft/entity/LivingEntity lastAttackedTicks I +accessible field net/minecraft/entity/LivingEntity jumpingCooldown I +accessible field net/minecraft/entity/Entity pos Lnet/minecraft/util/math/Vec3d; # Camera accessible method net/minecraft/client/render/Camera setPos (DDD)V From 66a916543d3594ace10f9a3197bc0b93ef943243 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Wed, 21 Aug 2024 16:09:43 +0300 Subject: [PATCH 09/16] Refactor: MovementPrediction --- .../lambda/module/modules/combat/KillAura.kt | 14 +++--- .../com/lambda/util/player/MovementUtils.kt | 3 -- .../player/prediction/MovementPrediction.kt | 18 +++++++ .../PredictionEntity.kt} | 49 +++++++++---------- .../util/player/prediction/PredictionTick.kt | 32 ++++++++++++ 5 files changed, 78 insertions(+), 38 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/util/player/prediction/MovementPrediction.kt rename common/src/main/kotlin/com/lambda/util/player/{MovementPrediction.kt => prediction/PredictionEntity.kt} (91%) create mode 100644 common/src/main/kotlin/com/lambda/util/player/prediction/PredictionTick.kt diff --git a/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt b/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt index d981a5202..6fc582239 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt @@ -25,7 +25,7 @@ import com.lambda.util.math.VecUtils.distSq import com.lambda.util.math.VecUtils.plus import com.lambda.util.math.VecUtils.times import com.lambda.util.player.MovementUtils.moveDiff -import com.lambda.util.player.predictPlayerMovement +import com.lambda.util.player.prediction.buildPlayerPrediction import com.lambda.util.world.raycast.RayCastUtils.entityResult import kotlinx.coroutines.delay import net.minecraft.entity.EquipmentSlot @@ -154,24 +154,22 @@ object KillAura : Module( private fun SafeContext.buildRotation(target: LivingEntity): RotationContext? { val currentRotation = RotationManager.currentRotation - val prediction = predictPlayerMovement(1) + val prediction = buildPlayerPrediction() val eye = when { selfPredict < 1 -> { - lerp(player.eyePos, prediction.eyePos, selfPredict) + lerp(player.eyePos, prediction.next().eyePos, selfPredict) } selfPredict < 2 -> { - val pos1 = prediction.eyePos - prediction.tickMovement(this) - val pos2 = prediction.eyePos + val pos1 = prediction.next().eyePos + val pos2 = prediction.next().eyePos lerp(pos1, pos2, selfPredict - 1) } else -> { - prediction.tickMovement(this) - prediction.eyePos + prediction.next().eyePos } } 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 072b06ed5..c32d88061 100644 --- a/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt @@ -108,8 +108,6 @@ object MovementUtils { moveStrafe: Double = player.input.roundedStrafing ) = yawIn.toRadian() + inputMoveOffset(moveForward, moveStrafe) - fun randomDirection() = random(-180.0, 180.0).toRadian() - fun SafeContext.movementVector(radDir: Double = calcMoveRad(), y: Double = 0.0) = Vec3d(-sin(radDir), y, cos(radDir)) @@ -135,7 +133,6 @@ object MovementUtils { 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.velocityDelta get() = hypot(this.velocity.x, this.velocity.z) val Entity.octant: EightWayDirection get() = yaw.octant diff --git a/common/src/main/kotlin/com/lambda/util/player/prediction/MovementPrediction.kt b/common/src/main/kotlin/com/lambda/util/player/prediction/MovementPrediction.kt new file mode 100644 index 000000000..4a8e1d9c4 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/player/prediction/MovementPrediction.kt @@ -0,0 +1,18 @@ +package com.lambda.util.player.prediction + +import com.lambda.context.SafeContext + +/** + * Builds the player movement prediction engine based on minecraft physics logic + * + * Currently not implemented: + * - Elytra movement + * - Movement in liquids + * - Ladder climbing + * - Movement in webs + * - Sneaking safewalk + * + * And im fucking tired of merging all shit from minecraft + */ +fun SafeContext.buildPlayerPrediction(): PredictionTick = + PredictionEntity(player).lastTick \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/player/MovementPrediction.kt b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt similarity index 91% rename from common/src/main/kotlin/com/lambda/util/player/MovementPrediction.kt rename to common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt index 766d182e6..54f418db9 100644 --- a/common/src/main/kotlin/com/lambda/util/player/MovementPrediction.kt +++ b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt @@ -1,7 +1,8 @@ -package com.lambda.util.player +package com.lambda.util.player.prediction import com.lambda.context.SafeContext import com.lambda.interaction.rotation.Rotation +import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.blockState import com.lambda.util.BlockUtils.flooredPos import com.lambda.util.math.MathUtils.floorToInt @@ -24,34 +25,23 @@ import net.minecraft.util.math.Vec3d import kotlin.math.abs import kotlin.math.floor -/** - * Predicts players movement based on minecraft physics logic - * - * Currently not implemented: - * - Elytra movement - * - Movement in liquids - * - Ladder climbing - * - Movement in webs - * - Sneaking safewalk - * - * And im fucking tired of merging all shit from minecraft - */ -fun SafeContext.predictPlayerMovement(ticks: Int): PredictionEntity { - val simulated = PredictionEntity(player) - - repeat(ticks) { - simulated.tickMovement(this) - } - - return simulated -} - // Todo: any player entity support class PredictionEntity(val player: ClientPlayerEntity) { + val lastTick get() = PredictionTick( + position, + rotation, + motion, + boundingBox, + eyePos, + isOnGround, + isJumping, + this + ) + // Basics - var position = player.pos - var motion = player.motion - var boundingBox = player.boundingBox + private var position = player.pos + private var motion = player.motion + private var boundingBox = player.boundingBox val eyePos get() = position + Vec3d(0.0, player.standingEyeHeight.toDouble(), 0.0) private var rotation = Rotation(player.moveYaw, player.pitch) @@ -60,6 +50,7 @@ class PredictionEntity(val player: ClientPlayerEntity) { private var isOnGround = player.isOnGround private val isSprinting = player.isSprinting private val isSneaking = player.isSneaking + private var isJumping = false // Movement input private val pressingJump = player.input.jumping @@ -78,7 +69,7 @@ class PredictionEntity(val player: ClientPlayerEntity) { private var verticalCollision = player.verticalCollision /** @see net.minecraft.client.network.ClientPlayerEntity.tickMovement */ - fun tickMovement(ctx: SafeContext) = ctx.apply { + fun tickMovement() = runSafe { forwardSpeed = forwardMovement strafeSpeed = strafeMovement @@ -109,8 +100,11 @@ class PredictionEntity(val player: ClientPlayerEntity) { ) } + isJumping = false + if (pressingJump && isOnGround && jumpingCooldown == 0) { jumpingCooldown = 10 + isJumping = true jump() } @@ -211,6 +205,7 @@ class PredictionEntity(val player: ClientPlayerEntity) { motion += movementVector(yawRad, 0.0) * 0.2 } + /** @see net.minecraft.entity.Entity.getJumpVelocityMultiplier */ /** @see net.minecraft.entity.Entity.getJumpVelocityMultiplier */ val jumpHeight = run { val f = position.flooredPos.blockState(world).block.jumpVelocityMultiplier.toDouble() diff --git a/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionTick.kt b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionTick.kt new file mode 100644 index 000000000..3366c1134 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionTick.kt @@ -0,0 +1,32 @@ +package com.lambda.util.player.prediction + +import com.lambda.interaction.rotation.Rotation +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d + +/** + * Data class representing a movement prediction tick for an entity. + * + * @property position The current position of the entity. + * @property rotation The current rotation (yaw, pitch) of the entity. + * @property velocity The current velocity vector of the entity. + * @property boundingBox The bounding box that defines the entity's space in the world. + * @property eyePos The position of the entity's eyes, typically used for raycasting or viewing purposes. + * @property onGround Indicates whether the entity is currently touching the ground. + * @property isJumping Indicates whether the entity is currently jumping. + */ +data class PredictionTick( + val position: Vec3d, + val rotation: Rotation, + val velocity: Vec3d, + val boundingBox: Box, + val eyePos: Vec3d, + val onGround: Boolean, + val isJumping: Boolean, + val predictionEntity: PredictionEntity +) { + fun next() = with(predictionEntity) { + tickMovement() + lastTick + } +} \ No newline at end of file From 59e622e81d0413b32e3a4edbfa0941639c35e496 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Wed, 21 Aug 2024 17:06:50 +0300 Subject: [PATCH 10/16] Diagonal grim strafe --- .../lambda/module/modules/movement/Speed.kt | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt index 48b957884..f39c402fc 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt @@ -4,7 +4,6 @@ import com.lambda.config.groups.IRotationConfig import com.lambda.context.SafeContext import com.lambda.event.events.ClientEvent import com.lambda.event.events.MovementEvent -import com.lambda.event.events.RotationEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.interaction.RotationManager.requestRotation import com.lambda.interaction.rotation.Rotation @@ -14,11 +13,9 @@ import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.Nameable import com.lambda.util.player.MovementUtils.addSpeed -import com.lambda.util.player.MovementUtils.buildMovementInput import com.lambda.util.player.MovementUtils.calcMoveYaw import com.lambda.util.player.MovementUtils.handledByBaritone import com.lambda.util.player.MovementUtils.isInputting -import com.lambda.util.player.MovementUtils.mergeFrom import com.lambda.util.player.MovementUtils.motionY import com.lambda.util.player.MovementUtils.moveDelta import com.lambda.util.player.MovementUtils.newMovementInput @@ -43,8 +40,9 @@ object Speed : Module( } // Grim + private val diagonal by setting("Diagonal", true) { mode == Mode.GRIM_STRAFE } private val grimEntityBoost by setting("Entity Boost", 1.0, 0.0..2.0, 0.01) { mode == Mode.GRIM_STRAFE } - private val grimCollideMultiplier by setting("Entity Collide Multiplier", 0.5, 0.0..1.0, 0.01) { mode == Mode.GRIM_STRAFE && grimEntityBoost > 0.0} + private val grimCollideMultiplier by setting("Entity Collide Multiplier", 0.5, 0.0..1.0, 0.01) { mode == Mode.GRIM_STRAFE && grimEntityBoost > 0.0 } private val grimBoatBoost by setting("Boat Boost", 0.4, 0.0..1.0, 0.01) { mode == Mode.GRIM_STRAFE } private val grimMaxSpeed by setting("Max Speed", 1.0, 0.2..1.0, 0.01) { mode == Mode.GRIM_STRAFE } @@ -110,17 +108,33 @@ object Speed : Module( } } - // TODO: Diagonal movement when not jumping - // needs movement prediction engine or a workaround to detect jumping 1 tick before - requestRotation(100, false, + requestRotation(100, alwaysListen = false, onUpdate = { lastContext -> if (mode != Mode.GRIM_STRAFE) return@requestRotation null - if (!shouldWork() || !isInputting) return@requestRotation null + if (!shouldWork()) return@requestRotation null if (player.input.handledByBaritone || TargetStrafe.isActive) return@requestRotation null + var yaw = player.yaw val input = newMovementInput() - val yaw = calcMoveYaw(player.yaw, input.roundedForward, input.roundedStrafing) - val rotation = Rotation(yaw, lastContext?.rotation?.pitch ?: player.pitch.toDouble()) + + if (!input.isInputting) return@requestRotation null + + run { + if (!diagonal) return@run + + if (player.isOnGround && input.jumping) return@run + + val forward = input.roundedForward.toFloat() + var strafe = input.roundedStrafing.toFloat() + + if (strafe == 0f) strafe = -1f + if (forward == 0f) strafe *= -1 + + yaw -= 45 * strafe + } + + val moveYaw = calcMoveYaw(yaw, input.roundedForward, input.roundedStrafing) + val rotation = Rotation(moveYaw, lastContext?.rotation?.pitch ?: player.pitch.toDouble()) RotationContext(rotation, rotationConfig) }, {} From b1392dc44bfbe1fe5b601d3b6d17252686d3cb68 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 22 Aug 2024 12:45:38 +0300 Subject: [PATCH 11/16] Fixed rotation update timing --- .../main/java/com/lambda/mixin/MinecraftClientMixin.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index 6c92d6558..e5ad4fb8a 100644 --- a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -27,7 +27,6 @@ public class MinecraftClientMixin { @Inject(method = "tick", at = @At("HEAD")) void onTickPre(CallbackInfo ci) { EventFlow.post(new TickEvent.Pre()); - RotationManager.update(); } @Inject(method = "tick", at = @At("RETURN")) @@ -35,6 +34,11 @@ void onTickPost(CallbackInfo ci) { EventFlow.post(new TickEvent.Post()); } + @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/DebugHud;shouldShowDebugHud()Z")) + void onInteractionPostEvent(CallbackInfo ci) { + RotationManager.update(); + } + @Inject(method = "render", at = @At("HEAD")) void onLoopTickPre(CallbackInfo ci) { EventFlow.post(new TickEvent.GameLoop.Pre()); From 37f9c4544fae33a647425a168194b4aff2631c3a Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 22 Aug 2024 13:27:50 +0300 Subject: [PATCH 12/16] Extended predicions, fixed killaura mistakes --- .../kotlin/com/lambda/module/modules/combat/KillAura.kt | 4 ++-- .../com/lambda/util/player/prediction/PredictionTick.kt | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt b/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt index 6fc582239..0b1ce60b9 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt @@ -169,7 +169,7 @@ object KillAura : Module( } else -> { - prediction.next().eyePos + prediction.next().next().eyePos } } @@ -185,7 +185,7 @@ object KillAura : Module( // Rotation stabilizer rotation.speedMultiplier = if (stabilize && !rotation.instant) { - val slowDown = currentRotation.castBox(box, reach) != null + val slowDown = currentRotation.castBox(box, reach, eye) != null with(rotation) { val targetSpeed = if (slowDown) 0.0 else 1.0 diff --git a/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionTick.kt b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionTick.kt index 3366c1134..eeb85e9c7 100644 --- a/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionTick.kt +++ b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionTick.kt @@ -25,8 +25,13 @@ data class PredictionTick( val isJumping: Boolean, val predictionEntity: PredictionEntity ) { - fun next() = with(predictionEntity) { - tickMovement() + fun next() = skipTicks(1) + + fun skipTicks(amount: Int) = with(predictionEntity) { + repeat(amount) { + tickMovement() + } + lastTick } } \ No newline at end of file From 392ca9e2b428b859efeabe51ad90a92c908f851a Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sun, 25 Aug 2024 21:14:04 +0300 Subject: [PATCH 13/16] Fix: 1 tick delayed input in predictions --- .../player/prediction/PredictionEntity.kt | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt index 54f418db9..243fede0b 100644 --- a/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt +++ b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt @@ -1,5 +1,6 @@ package com.lambda.util.player.prediction +import com.lambda.Lambda.mc import com.lambda.context.SafeContext import com.lambda.interaction.rotation.Rotation import com.lambda.threading.runSafe @@ -15,8 +16,10 @@ import com.lambda.util.math.VecUtils.times import com.lambda.util.player.MovementUtils.motion import com.lambda.util.player.MovementUtils.moveYaw import com.lambda.util.player.MovementUtils.movementVector +import net.minecraft.client.input.KeyboardInput import net.minecraft.client.network.ClientPlayerEntity import net.minecraft.enchantment.EnchantmentHelper +import net.minecraft.enchantment.EnchantmentHelper.getSwiftSneakSpeedBoost import net.minecraft.entity.Entity import net.minecraft.entity.effect.StatusEffects import net.minecraft.util.math.BlockPos @@ -53,11 +56,15 @@ class PredictionEntity(val player: ClientPlayerEntity) { private var isJumping = false // Movement input - private val pressingJump = player.input.jumping - private val forwardMovement = player.input.movementForward.toDouble() - private val strafeMovement = player.input.movementSideways.toDouble() + private val input = KeyboardInput(mc.options).apply { + tick(true, 1f) + } + + private val pressingJump = input.jumping + private val forwardMovement = input.movementForward.toDouble() + private val strafeMovement = input.movementSideways.toDouble() + private val verticalMovement = pressingJump.toIntSign().toDouble() - private var verticalSpeed = pressingJump.toIntSign().toDouble() private var forwardSpeed = forwardMovement private var strafeSpeed = strafeMovement @@ -79,7 +86,7 @@ class PredictionEntity(val player: ClientPlayerEntity) { } if (isSneaking) { - val mod = 0.3f + EnchantmentHelper.getSwiftSneakSpeedBoost(player) + val mod = 0.3f + getSwiftSneakSpeedBoost(player) forwardSpeed *= mod strafeSpeed *= mod } @@ -116,7 +123,7 @@ class PredictionEntity(val player: ClientPlayerEntity) { /** @see net.minecraft.entity.LivingEntity.travel */ private fun SafeContext.travel() { - val travelVec = Vec3d(strafeSpeed, verticalSpeed, forwardSpeed) + val travelVec = Vec3d(strafeSpeed, verticalMovement, forwardSpeed) val gravity = when { motion.y < 0.0 && player.hasStatusEffect(StatusEffects.SLOW_FALLING) -> 0.01 From 410d1bbf390a2b7a428cf1fe2c80782e8b912164 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Mon, 2 Sep 2024 18:38:34 +0300 Subject: [PATCH 14/16] Scaffold, rotation system fixes --- .../lambda/mixin/MinecraftClientMixin.java | 11 +- .../mixin/entity/ClientPlayerEntityMixin.java | 12 + .../config/groups/InteractionSettings.kt | 4 +- .../com/lambda/event/events/MovementEvent.kt | 1 + .../lambda/interaction/PlayerPacketManager.kt | 5 +- .../com/lambda/interaction/RotationManager.kt | 9 +- .../blockplace/PlaceInteraction.kt | 8 +- .../lambda/interaction/rotation/Rotation.kt | 2 +- .../visibilty/VisibilityChecker.kt | 4 +- .../lambda/module/modules/combat/KillAura.kt | 13 +- .../module/modules/movement/SafeWalk.kt | 2 +- .../lambda/module/modules/player/Scaffold.kt | 369 +++++++++++------- .../player/prediction/PredictionEntity.kt | 11 +- 13 files changed, 265 insertions(+), 186 deletions(-) diff --git a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index e5ad4fb8a..16fa23bed 100644 --- a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -2,11 +2,7 @@ import com.lambda.Lambda; import com.lambda.event.EventFlow; -import com.lambda.event.events.ClientEvent; -import com.lambda.event.events.ScreenEvent; -import com.lambda.event.events.ScreenHandlerEvent; -import com.lambda.event.events.TickEvent; -import com.lambda.interaction.RotationManager; +import com.lambda.event.events.*; import com.lambda.module.modules.player.Interact; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; @@ -34,11 +30,6 @@ void onTickPost(CallbackInfo ci) { EventFlow.post(new TickEvent.Post()); } - @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/DebugHud;shouldShowDebugHud()Z")) - void onInteractionPostEvent(CallbackInfo ci) { - RotationManager.update(); - } - @Inject(method = "render", at = @At("HEAD")) void onLoopTickPre(CallbackInfo ci) { EventFlow.post(new TickEvent.GameLoop.Pre()); 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 89cb14a95..a05eeb164 100644 --- a/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java +++ b/common/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java @@ -16,6 +16,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.Objects; @@ -65,11 +66,22 @@ boolean isSprinting(ClientPlayerEntity entity) { return EventFlow.post(new MovementEvent.Sprint(entity.isSprinting())).getSprint(); } + @Inject(method = "isSneaking", at = @At(value = "HEAD"), cancellable = true) + void redirectSneaking(CallbackInfoReturnable cir) { + ClientPlayerEntity self = (ClientPlayerEntity) (Object) this; + if (self != Lambda.getMc().player) return; + + if (self.input == null) return; + cir.setReturnValue(EventFlow.post(new MovementEvent.Sneak(self.input.sneaking)).getSneak()); + } + @Inject(method = "sendMovementPackets", at = @At(value = "HEAD"), cancellable = true) void sendBegin(CallbackInfo ci) { ci.cancel(); PlayerPacketManager.sendPlayerPackets(); autoJumpEnabled = Lambda.getMc().options.getAutoJump().getValue(); + + RotationManager.update(); } @Inject(method = "tick", at = @At(value = "HEAD")) diff --git a/common/src/main/kotlin/com/lambda/config/groups/InteractionSettings.kt b/common/src/main/kotlin/com/lambda/config/groups/InteractionSettings.kt index bcaf64897..e90ce0028 100644 --- a/common/src/main/kotlin/com/lambda/config/groups/InteractionSettings.kt +++ b/common/src/main/kotlin/com/lambda/config/groups/InteractionSettings.kt @@ -8,7 +8,7 @@ class InteractionSettings( vis: () -> Boolean = { true }, ) : InteractionConfig { override val reach by c.setting("Reach", defaultReach, 0.1..10.0, 0.1, "Players reach / range", " blocks", vis) - override val useRayCast by c.setting("Raycast", false, "Verify hit vector with ray casting (for very strict ACs)", vis) - override val resolution by c.setting("Resolution", 10, 1..30, 1, "How many raycast checks per surface (will be squared)") { vis() && useRayCast } + override val useRayCast by c.setting("Raycast", true, "Verify hit vector with ray casting (for very strict ACs)", vis) + override val resolution by c.setting("Resolution", 20, 1..40, 1, "How many raycast checks per surface (will be squared)") { vis() && useRayCast } override val swingHand by c.setting("Swing Hand", true, "Swing hand on interactions", vis) } \ No newline at end of file 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 4087c26eb..57b42d626 100644 --- a/common/src/main/kotlin/com/lambda/event/events/MovementEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/MovementEvent.kt @@ -21,6 +21,7 @@ abstract class MovementEvent : Event { ) : MovementEvent() class Sprint(var sprint: Boolean) : MovementEvent() + class Sneak(var sneak: Boolean) : MovementEvent() class ClipAtLedge( var clip: Boolean, diff --git a/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt b/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt index 65484ebae..c59bc658f 100644 --- a/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt @@ -97,15 +97,12 @@ object PlayerPacketManager : Loadable { else -> null } - if (updatePosition) { - sendTicks = 0 - } - packet?.let { PlayerPacketEvent.Send(it).postChecked { connection.sendPacket(this.packet) if (updatePosition) { + sendTicks = 0 lastPosition = position } diff --git a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt index 922778a29..17f963200 100644 --- a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt @@ -162,23 +162,20 @@ object RotationManager : Loadable { @JvmStatic val movementYaw: Float? get() { - val config = currentContext?.config ?: return null - if (config.rotationMode == RotationMode.SILENT) return null + if (currentContext?.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 + if (currentContext?.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 + if (currentContext?.config?.rotationMode == RotationMode.SILENT) return null val rot = lerp(prevRotation, currentRotation, deltaTime) return Vec2d(rot.yaw, rot.pitch) diff --git a/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInteraction.kt b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInteraction.kt index 00b7ae097..4a2302b9e 100644 --- a/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInteraction.kt +++ b/common/src/main/kotlin/com/lambda/interaction/blockplace/PlaceInteraction.kt @@ -3,6 +3,7 @@ package com.lambda.interaction.blockplace import com.lambda.context.SafeContext import com.lambda.util.Communication.info import net.minecraft.block.* +import net.minecraft.util.ActionResult import net.minecraft.util.Hand import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.math.BlockPos @@ -12,9 +13,10 @@ object PlaceInteraction { fun SafeContext.placeBlock(result: BlockHitResult, hand: Hand, swing: Boolean) { val actionResult = interaction.interactBlock(player, hand, result) - if (!actionResult.isAccepted) { - info("Internal interaction failed with $actionResult") - return + when (actionResult) { + ActionResult.PASS -> info("Internal interaction skipped") + ActionResult.FAIL -> info("Internal interaction failed") + else -> {} } if (!swing) return diff --git a/common/src/main/kotlin/com/lambda/interaction/rotation/Rotation.kt b/common/src/main/kotlin/com/lambda/interaction/rotation/Rotation.kt index 321dac45f..5d21f1adb 100644 --- a/common/src/main/kotlin/com/lambda/interaction/rotation/Rotation.kt +++ b/common/src/main/kotlin/com/lambda/interaction/rotation/Rotation.kt @@ -69,7 +69,7 @@ data class Rotation(val yaw: Double, val pitch: Double) { val DOWN = Rotation(0.0, 90.0) val Entity.rotation get() = Rotation(yaw, pitch) - private fun wrap(deg: Double) = MathHelper.wrapDegrees(deg) + fun wrap(deg: Double) = MathHelper.wrapDegrees(deg) fun Rotation.lerp(other: Rotation, delta: Double): Rotation { val yaw = this.yaw + delta * (other.yaw - this.yaw) diff --git a/common/src/main/kotlin/com/lambda/interaction/visibilty/VisibilityChecker.kt b/common/src/main/kotlin/com/lambda/interaction/visibilty/VisibilityChecker.kt index ae3f9f118..7b348b659 100644 --- a/common/src/main/kotlin/com/lambda/interaction/visibilty/VisibilityChecker.kt +++ b/common/src/main/kotlin/com/lambda/interaction/visibilty/VisibilityChecker.kt @@ -95,8 +95,8 @@ object VisibilityChecker { inline fun scanVisibleSurfaces( eyes: Vec3d, box: Box, - sides: Set, - resolution: Int, + sides: Set = emptySet(), + resolution: Int = 30, check: (Direction, Vec3d) -> Unit, ) { box.getVisibleSurfaces(eyes) diff --git a/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt b/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt index 0b1ce60b9..e4fe4e017 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt @@ -103,11 +103,6 @@ object KillAura : Module( target?.let { target -> buildRotation(target) } - }, - onReceive = { - target?.let { entity -> - runAttack(entity) - } } ) @@ -121,10 +116,8 @@ object KillAura : Module( target = targeting.getTarget() if (!timerSync) attackTicks++ - if (!rotate) { - target?.let { entity -> - runAttack(entity) - } + target?.let { entity -> + runAttack(entity) } } @@ -233,7 +226,7 @@ object KillAura : Module( // Get visible point set val validHits = mutableMapOf() - scanVisibleSurfaces(eye, box, emptySet(), interactionSettings.resolution) { _, vec -> + scanVisibleSurfaces(eye, box, resolution = interactionSettings.resolution) { _, vec -> if (eye distSq vec > reachSq) return@scanVisibleSurfaces val newRotation = eye.rotationTo(vec) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt index de109ee47..a9032a950 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt @@ -32,7 +32,7 @@ object SafeWalk : Module( var dx = deltaX var dz = deltaZ while (dx != 0.0 || dz != 0.0) { - if (world.isSpaceEmpty(this, boundingBox.offset(dx, -stepHeight, dz))) { + if (world.isBlockSpaceEmpty(this, boundingBox.offset(dx, -stepHeight, dz))) { return true } if (dx != 0.0) dx = adjustDelta(dx) diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt index 1e4cb78a6..2786626e0 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt @@ -14,8 +14,10 @@ import com.lambda.interaction.blockplace.PlaceFinder.Companion.buildPlaceInfo import com.lambda.interaction.blockplace.PlaceInfo import com.lambda.interaction.blockplace.PlaceInteraction.placeBlock import com.lambda.interaction.rotation.Rotation +import com.lambda.interaction.rotation.Rotation.Companion.angleDifference import com.lambda.interaction.rotation.Rotation.Companion.dist import com.lambda.interaction.rotation.Rotation.Companion.rotationTo +import com.lambda.interaction.rotation.Rotation.Companion.wrap import com.lambda.interaction.rotation.RotationContext import com.lambda.interaction.visibilty.VisibilityChecker.scanVisibleSurfaces import com.lambda.module.Module @@ -25,10 +27,13 @@ import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.MathUtils.floorToInt import com.lambda.util.math.VecUtils.dist import com.lambda.util.math.VecUtils.distSq +import com.lambda.util.math.step import com.lambda.util.math.transform import com.lambda.util.player.MovementUtils.calcMoveYaw import com.lambda.util.player.MovementUtils.isInputting -import com.lambda.util.player.MovementUtils.octant +import com.lambda.util.player.MovementUtils.newMovementInput +import com.lambda.util.player.MovementUtils.roundedForward +import com.lambda.util.player.MovementUtils.roundedStrafing import com.lambda.util.world.raycast.RayCastUtils.blockResult import net.minecraft.util.Hand import net.minecraft.util.hit.BlockHitResult @@ -45,217 +50,305 @@ object Scaffold : Module( description = "Places blocks under the player", defaultTags = setOf(ModuleTag.PLAYER) ) { - private val page by setting("Page", Page.General) + private val page by setting("Page", Page.GENERAL) - private val keepY by setting("Keep Y", true) { page == Page.General } - private val airOnly by setting("In Air Only", true) { page == Page.General } - private val minAirTicks by setting("Min Air Ticks", 3, 1..7) { page == Page.General && airOnly } - private val minPlaceDist by setting("Min Place Dist", 0.1, 0.0..0.3, 0.01) { page == Page.General } - //private val renderPrediction by setting("Render Prediction", false) { page == Page.General } + private val keepY by setting("Keep Y", true) { page == Page.GENERAL } + private val minPlaceDist by setting("Min Place Dist", 0.0, 0.0..0.2, 0.01) { page == Page.GENERAL } + private val minRotateDist by setting("Min Rotate Dist", 0.10, 0.0..0.2, 0.01) { page == Page.GENERAL } - private val rotationConfig = RotationSettings(this) { page == Page.Rotation } - private val interactionConfig = InteractionSettings(this) { page == Page.Interaction } + private val rotationConfig = RotationSettings(this) { page == Page.ROTATION } + private val safeWalk by setting("Sneak Before Rotation", true) { page == Page.ROTATION } + private val direction by setting("Direction", LookingDirection.FREE) { page == Page.ROTATION } + private val optimalPitch by setting("Optimal Pitch", 81.0, 70.0..85.0, 0.05) { page == Page.ROTATION } - private var placeInfo: PlaceInfo? = null - private val infoSet = HashSet>() + private val interactionConfig = InteractionSettings(this) { page == Page.INTERACTION } + // Placement + private var placeInfo: PlaceInfo? = null private var keepLevel: Int? = null - private var airTicks = 0 + private var lastRotation: Rotation? = null + private var edjeDistance = 0.0 + + // Sneaking + private var placeInfoAge = 0 + private var sneakTicks = 0 + // Rendering + private val renderInfo = HashSet>() private val currentTime get() = System.currentTimeMillis() + // Other + private val yawList = listOf(0.0, 90.0, 180.0, 270.0) + private val diagonalYawList = yawList.map { it + 45 } private val builderSideMask = EnumSet.allOf(Direction::class.java).apply { - remove(Direction.UP) // Don't place above feet + remove(Direction.UP) } - /*private var prediction: PredictionEntity? = null - private val predictedRenderBox = DynamicAABB() + // Yaw values within this range will not make your movement unstable + private const val YAW_THRESHOLD = 15.0 - private val SafeContext.predictedEyes get() = prediction?.eyePos ?: player.eyePos - private val SafeContext.predictedPos get() = prediction?.position ?: player.pos - private val SafeContext.predictedBox get() = prediction?.boundingBox ?: player.boundingBox*/ + private enum class Page { + GENERAL, + ROTATION, + INTERACTION + } - enum class Page { - General, - Rotation, - Interaction + private enum class LookingDirection { + FREE, + ClAMPED, + STRAIGHT, + DIAGONAL } init { requestRotation( onUpdate = { - val info = placeInfo ?: return@requestRotation null - - val pause = getPause(info) - if (pause.rotatePause) return@requestRotation null - + lastRotation = null + val info = updatePlaceInfo() ?: return@requestRotation null val rotation = rotate(info) ?: return@requestRotation null - RotationContext(rotation, rotationConfig) - }, - onReceive = { - val info = placeInfo ?: return@requestRotation - - val pause = getPause(info) - if (pause.placePause) return@requestRotation - val result = castRotation(currentRotation, info) ?: return@requestRotation - infoSet.add(info to currentTime) - placeBlock(result, Hand.MAIN_HAND, interactionConfig.swingHand) + RotationContext(rotation, rotationConfig) } ) - listener { - updatePlaceInfo() - - /*prediction = predictPlayerMovement(1) - predictedRenderBox.update(predictedBox)*/ + listener { + if (sneakTicks > 0) it.sneak = true } - listener { - airTicks++ - if (player.isOnGround) airTicks = 0 - } + listener { + currentRotation.rayCast(interactionConfig.reach)?.blockResult?.let { + if (player.age % 2 == 0) return@let + val pos = BlockPos.ofFloored(player.pos.x, (floor(player.pos.y) - 0.00001), player.pos.z) + if (it.pos == pos && it.side == Direction.UP) interaction.interactBlock(player, Hand.MAIN_HAND, it) + } - /*listener { event -> - if (!mc.gameRenderer.camera.isThirdPerson || !renderPrediction) return@listener + placeInfo?.let { info -> + tickPlacement(info) + } - val c = GuiSettings.primaryColor - event.renderer.build(predictedRenderBox, c.multAlpha(0.3), c) - }*/ + updateSneaking() + } - // ToDo: optimize listener { event -> - val c = GuiSettings.primaryColor - - infoSet.removeIf { - val (info, time) = it - - val pos = info.placedPos - val seconds = (currentTime - time) / 1000.0 - - val sides = buildSideMesh(pos) { meshPos -> - infoSet.any { it.first.placedPos == meshPos } - } - - val box = Box(info.placedPos) - val alpha = transform(seconds, 0.0, 0.5, 1.0, 0.0).coerceIn(0.0, 1.0) - - event.renderer.build( - box, - c.multAlpha(0.3 * alpha), - c.multAlpha(alpha), - sides, - DirectionMask.OutlineMode.AND - ) - - seconds > 1 - } + buildRenderer(event) } onEnable { - keepLevel = null placeInfo = null - airTicks = 0 + renderInfo.clear() - /*prediction = null - predictedRenderBox.reset()*/ + keepLevel = null + sneakTicks = 0 } } - private fun SafeContext.updatePlaceInfo() { - placeInfo = null - - val playerPos = player.pos - var y = (floor(playerPos.y) - 0.00001).floorToInt() + private fun SafeContext.updatePlaceInfo(): PlaceInfo? { + // Feet placing blockpos + var y = (floor(player.pos.y) - 0.00001).floorToInt() + // KeepY update if (keepY && isInputting) { keepLevel?.let { - if (it <= y) y = it + y = it } } - val placePos = BlockPos(playerPos.x.floorToInt(), y, playerPos.z.floorToInt()) + // Getting the latest block of the placement sequence + placeInfo = buildPlaceInfo( + basePos = BlockPos(player.pos.x.floorToInt(), y, player.pos.z.floorToInt()), + range = interactionConfig.reach + 2, + sides = builderSideMask + ) + + placeInfo?.let { info -> + placeInfoAge = 0 + + // Ignore supporting blocks + if (info.placeSteps != 0) return@let + + // Updating keep level + keepLevel = info.placedPos.y + + edjeDistance = distanceToEdge(info.clickPos) + if (info.clickSide.axis == Direction.Axis.Y) edjeDistance = -1.0 + } - placeInfo = buildPlaceInfo(placePos, 4, interactionConfig.reach + 1, player.eyePos, true, builderSideMask) - keepLevel = placeInfo?.placedPos?.y ?: keepLevel + return placeInfo } private fun SafeContext.rotate(info: PlaceInfo): Rotation? { val eye = player.eyePos - val validHits = mutableSetOf() val reach = interactionConfig.reach val reachSq = reach.pow(2) - scanVisibleSurfaces(eye, Box(info.clickPos), setOf(info.clickSide), interactionConfig.resolution) { _, vec -> - if (eye distSq vec > reachSq) return@scanVisibleSurfaces + val input = newMovementInput() + val moveYaw = calcMoveYaw(player.yaw, input.roundedForward, input.roundedStrafing) - if (interactionConfig.useRayCast) { - val newRotation = eye.rotationTo(vec) - castRotation(newRotation, info) ?: return@scanVisibleSurfaces - } + // Checking whether the player is moving diagonally + val isDiagonal = diagonalYawList.any { + angleDifference(moveYaw, it) < YAW_THRESHOLD + } + + // Assumed yaw values + val assumedYaw = assumeYawByDirection(moveYaw) + + // No need to rotate, already looking correctly + val lookingCorrectly = castRotation(currentRotation, info) != null + val isYawStable = angleDifference(currentRotation.yaw, assumedYaw) < YAW_THRESHOLD + if (lookingCorrectly && isYawStable) return currentRotation + + // Dividing the surface by segments and iterating through them + val pointScan = mutableSetOf().apply { + scanVisibleSurfaces( + eyes = eye, + box = Box(info.clickPos), + resolution = interactionConfig.resolution + ) { _, vec -> + if (eye distSq vec > reachSq) return@scanVisibleSurfaces - validHits += vec + val rotation = eye.rotationTo(vec) + castRotation(rotation, info) ?: return@scanVisibleSurfaces + + add(rotation) + } } - val moveYaw = calcMoveYaw(player.yaw).toFloat() - val isDiagonal = moveYaw.octant.directions.size == 2 + // Iterating through assumed angle ranges + val angleScan = mutableSetOf().apply { + val pitchRange = 55.0..85.0 + val pitchList = pitchRange.step(0.1) + + pitchList.forEach { pitch -> + val rotation = Rotation(assumedYaw, pitch) + castRotation(rotation, info) ?: return@forEach - validHits.minByOrNull { - if (isDiagonal) { - currentRotation dist eye.rotationTo(it) - } else { - distanceToEdge(info.clickPos, it) + add(rotation) } - } ?.let { closest -> - return eye.rotationTo(closest) } - return null + var optimalPitch = optimalPitch + if (isDiagonal) optimalPitch++ + + val assumedRotation = Rotation(assumedYaw, optimalPitch) + + // Check if the assumed rotation is ok + if (castRotation(assumedRotation, info) != null) { + return assumedRotation + } + + val optimalRotation = when { + // Placing supporting block + info.placeSteps > 0 && !isDiagonal -> currentRotation + + // Placing base block + else -> assumedRotation + } + + // Otherwise selecting the most similar rotation + val rotation = (angleScan + pointScan).minByOrNull { rotation -> + optimalRotation dist rotation + }.also { + lastRotation = it + } + + if (isDiagonal) { + edjeDistance = -1.0 + } + + // Check the distance to the edge (stabilizes rotation) + if (edjeDistance > 0 && edjeDistance < minRotateDist) return null + + return rotation } - private fun SafeContext.distanceToEdge(pos: BlockPos, from: Vec3d = player.pos): Double { - val x = player.pos.x.coerceIn(pos.x.toDouble(), pos.x.toDouble() + 1) - val z = player.pos.z.coerceIn(pos.z.toDouble(), pos.z.toDouble() + 1) - val to = Vec3d(x, from.y, z) + private fun SafeContext.tickPlacement(info: PlaceInfo) { + // Check the distance to the edge + if (edjeDistance > 0 && edjeDistance < minPlaceDist) return + + // Raycast the rotation + var blockResult: BlockHitResult? = castRotation(currentRotation, info) - return from dist to + // Use fallback hit vec for nonstrict ac's + if (!interactionConfig.useRayCast && blockResult == null) { + blockResult = BlockHitResult(info.hitVec, info.clickSide, info.clickPos, false) + } + + // Run placement + placeBlock(blockResult ?: return, Hand.MAIN_HAND, interactionConfig.swingHand) + renderInfo.add(info to currentTime) } - private fun castRotation(rotation: Rotation, info: PlaceInfo): BlockHitResult? { - val blockResult = rotation.rayCast(interactionConfig.reach)?.blockResult ?: return null - if (blockResult.blockPos != info.clickPos || blockResult.side != info.clickSide) return null - return blockResult + private fun SafeContext.updateSneaking() { + sneakTicks-- + placeInfoAge++ + + if (!safeWalk) return + + /*val vec = movementVector(y = -0.5) * player.moveDelta + val predictedBox = player.boundingBox.offset(vec) + val isNearLedge = world.isBlockSpaceEmpty(player, predictedBox)*/ + + val sneak = lastRotation?.let { + currentRotation dist it > YAW_THRESHOLD && player.isOnGround + } ?: (sneakTicks > 0 && placeInfoAge < 4) + + if (sneak) sneakTicks = 3 } - private fun SafeContext.getPause(info: PlaceInfo) = Pause.build { - if (airOnly && player.input.jumping && airTicks <= minAirTicks) { - pausePlacement() - } + private fun buildRenderer(event: RenderEvent.StaticESP) { + val c = GuiSettings.primaryColor + + renderInfo.removeIf { + val (info, time) = it + + val pos = info.placedPos + val seconds = (currentTime - time) / 1000.0 - if (isInputting) { - val dist = distanceToEdge(info.clickPos) - if (dist < minPlaceDist) { - pausePlacement() - pauseRotation() + val sides = buildSideMesh(pos) { meshPos -> + renderInfo.any { it.first.placedPos == meshPos } } + + val box = Box(info.placedPos) + val alpha = transform(seconds, 0.0, 0.5, 1.0, 0.0).coerceIn(0.0, 1.0) + + event.renderer.build( + box, + c.multAlpha(0.3 * alpha), + c.multAlpha(alpha), + sides, + DirectionMask.OutlineMode.AND + ) + + seconds > 1 } } - private class Pause { - var rotatePause = false; private set - var placePause = false; private set + private fun assumeYawByDirection(moveYaw: Double): Double { + val moveYawReversed = wrap(moveYaw + 180) - fun pauseRotation() { - rotatePause = true - } + return when (direction) { + LookingDirection.FREE -> listOf(moveYawReversed) + LookingDirection.ClAMPED -> yawList + diagonalYawList + LookingDirection.STRAIGHT -> yawList + LookingDirection.DIAGONAL -> diagonalYawList + }.minBy { angleDifference(moveYawReversed, it) } + } - fun pausePlacement() { - placePause = true - } + // Calculates the distance from the player to the edge of the block + private fun SafeContext.distanceToEdge(pos: BlockPos, from: Vec3d = player.pos) = + edgeOf(pos) dist Vec3d(from.x, pos.y.toDouble(), from.z) - companion object { - fun build(block: Pause.() -> Unit) = Pause().apply(block) - } + private fun SafeContext.edgeOf(pos: BlockPos): Vec3d { + val x = player.pos.x.coerceIn(pos.x.toDouble(), pos.x.toDouble() + 1) + val z = player.pos.z.coerceIn(pos.z.toDouble(), pos.z.toDouble() + 1) + return Vec3d(x, pos.y.toDouble(), z) + } + + // Checks if the rotation matches the placement requirements + private fun castRotation(rotation: Rotation, info: PlaceInfo): BlockHitResult? { + val blockResult = rotation.rayCast(interactionConfig.reach)?.blockResult ?: return null + if (blockResult.blockPos != info.clickPos || blockResult.side != info.clickSide) return null + return blockResult } } diff --git a/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt index 243fede0b..ff43930b8 100644 --- a/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt +++ b/common/src/main/kotlin/com/lambda/util/player/prediction/PredictionEntity.kt @@ -6,11 +6,9 @@ import com.lambda.interaction.rotation.Rotation import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.blockState import com.lambda.util.BlockUtils.flooredPos -import com.lambda.util.math.MathUtils.floorToInt import com.lambda.util.math.MathUtils.toIntSign import com.lambda.util.math.MathUtils.toRadian import com.lambda.util.math.VecUtils -import com.lambda.util.math.VecUtils.minus import com.lambda.util.math.VecUtils.plus import com.lambda.util.math.VecUtils.times import com.lambda.util.player.MovementUtils.motion @@ -18,15 +16,12 @@ import com.lambda.util.player.MovementUtils.moveYaw import com.lambda.util.player.MovementUtils.movementVector import net.minecraft.client.input.KeyboardInput import net.minecraft.client.network.ClientPlayerEntity -import net.minecraft.enchantment.EnchantmentHelper import net.minecraft.enchantment.EnchantmentHelper.getSwiftSneakSpeedBoost import net.minecraft.entity.Entity import net.minecraft.entity.effect.StatusEffects -import net.minecraft.util.math.BlockPos import net.minecraft.util.math.MathHelper import net.minecraft.util.math.Vec3d import kotlin.math.abs -import kotlin.math.floor // Todo: any player entity support class PredictionEntity(val player: ClientPlayerEntity) { @@ -70,7 +65,7 @@ class PredictionEntity(val player: ClientPlayerEntity) { // Other shit private var jumpingCooldown = player.jumpingCooldown - private var velocityAffectingPos = (player.pos - VecUtils.DOWN * 0.001).flooredPos + private var velocityAffectingPos = player.supportingBlockPos.orElse((position + VecUtils.DOWN * 0.001).flooredPos) private var horizontalCollision = player.horizontalCollision private var verticalCollision = player.verticalCollision @@ -201,8 +196,7 @@ class PredictionEntity(val player: ClientPlayerEntity) { boundingBox = normalized.offset(position) } - val y = (floor(position.y) - 0.00001).floorToInt() - velocityAffectingPos = BlockPos(position.x.floorToInt(), y, position.z.floorToInt()) + velocityAffectingPos = (position + VecUtils.DOWN * 0.001).flooredPos } /** @see net.minecraft.entity.LivingEntity.jump */ @@ -212,7 +206,6 @@ class PredictionEntity(val player: ClientPlayerEntity) { motion += movementVector(yawRad, 0.0) * 0.2 } - /** @see net.minecraft.entity.Entity.getJumpVelocityMultiplier */ /** @see net.minecraft.entity.Entity.getJumpVelocityMultiplier */ val jumpHeight = run { val f = position.flooredPos.blockState(world).block.jumpVelocityMultiplier.toDouble() From 6cae2f51654d53f281dd6a69e964bf5447e1c44e Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Mon, 2 Sep 2024 19:03:25 +0300 Subject: [PATCH 15/16] Removed useless workaround test --- .../kotlin/com/lambda/module/modules/player/Scaffold.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt index 2786626e0..c495e861f 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt @@ -116,12 +116,6 @@ object Scaffold : Module( } listener { - currentRotation.rayCast(interactionConfig.reach)?.blockResult?.let { - if (player.age % 2 == 0) return@let - val pos = BlockPos.ofFloored(player.pos.x, (floor(player.pos.y) - 0.00001), player.pos.z) - if (it.pos == pos && it.side == Direction.UP) interaction.interactBlock(player, Hand.MAIN_HAND, it) - } - placeInfo?.let { info -> tickPlacement(info) } From 4690562b3265a50b3389b5c949625c7026539bd3 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Mon, 2 Sep 2024 20:59:40 +0300 Subject: [PATCH 16/16] Grim diagonal jumping fix --- .../lambda/module/modules/movement/Speed.kt | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt index 360f6206b..6d27d1de6 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt @@ -12,6 +12,7 @@ import com.lambda.interaction.rotation.RotationMode import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.Nameable +import com.lambda.util.extension.contains import com.lambda.util.player.MovementUtils.addSpeed import com.lambda.util.player.MovementUtils.calcMoveYaw import com.lambda.util.player.MovementUtils.handledByBaritone @@ -22,7 +23,6 @@ import com.lambda.util.player.MovementUtils.newMovementInput import com.lambda.util.player.MovementUtils.roundedForward import com.lambda.util.player.MovementUtils.roundedStrafing import com.lambda.util.player.MovementUtils.setSpeed -import com.lambda.util.extension.contains import com.lambda.util.world.WorldUtils.getFastEntities import net.minecraft.entity.LivingEntity import net.minecraft.entity.decoration.ArmorStandEntity @@ -57,6 +57,8 @@ object Speed : Module( override val rotationMode = RotationMode.SYNC } + private var prevTickJumping = false + // NCP const val NCP_BASE_SPEED = 0.2873 private const val NCP_AIR_DECAY = 0.9937 @@ -100,11 +102,17 @@ object Speed : Module( } listener { - if (!shouldWork()) return@listener + if (mode == Mode.NCP_STRAFE && shouldWork()) it.cancel() + } - when (mode) { - Mode.NCP_STRAFE -> it.cancel() - else -> {} + listener(Int.MIN_VALUE) { + if (mode != Mode.GRIM_STRAFE || !shouldWork()) return@listener + + // Delay jumping key state by 1 tick to let the rotation predict jump timing + it.input.apply { + val jump = jumping + jumping = prevTickJumping + prevTickJumping = jump } } @@ -112,7 +120,6 @@ object Speed : Module( onUpdate = { lastContext -> if (mode != Mode.GRIM_STRAFE) return@requestRotation null if (!shouldWork()) return@requestRotation null - if (player.input.handledByBaritone || TargetStrafe.isActive) return@requestRotation null var yaw = player.yaw val input = newMovementInput() @@ -121,7 +128,6 @@ object Speed : Module( run { if (!diagonal) return@run - if (player.isOnGround && input.jumping) return@run val forward = input.roundedForward.toFloat() @@ -215,12 +221,18 @@ object Speed : Module( setSpeed(moveSpeed) } - private fun SafeContext.shouldWork() = - !player.abilities.flying - && !player.isFallFlying - && !player.input.sneaking - && !player.isTouchingWater - && !player.isInLava + private fun SafeContext.shouldWork(): Boolean { + if (player.abilities.flying || player.isFallFlying || player.isTouchingWater || player.isInLava) return false + + return when (mode) { + Mode.GRIM_STRAFE -> { + !player.input.handledByBaritone && !TargetStrafe.isActive + } + Mode.NCP_STRAFE -> { + !player.isSneaking + } + } + } private fun reset() { ncpPhase = NCPPhase.SLOWDOWN