From a11561a7ac03a15e6413d83ef59f4c7130c34572 Mon Sep 17 00:00:00 2001 From: Matias Date: Thu, 20 Aug 2026 03:23:21 +0300 Subject: [PATCH 1/4] Fix CrystalAura flagging BadPacketsH on Grim and add a very simple renderer for it --- .../module/modules/combat/CrystalAura.kt | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt index 9bfa55a20..a89d749bd 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt @@ -27,6 +27,7 @@ import com.lambda.context.SafeContext import com.lambda.event.events.EntityEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.graphics.mc.renderer.ImmediateRenderer.Companion.immediateRenderer import com.lambda.interaction.handlers.ContainerHandler.transfer import com.lambda.interaction.managers.hotbar.HotbarRequest import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest @@ -47,13 +48,9 @@ import com.lambda.util.Timer import com.lambda.util.collections.LimitedDecayQueue import com.lambda.util.combat.CombatUtils.crystalDamage import com.lambda.util.extension.fullHealth +import com.lambda.util.math.* import com.lambda.util.math.MathUtils.ceilToInt import com.lambda.util.math.MathUtils.roundToStep -import com.lambda.util.math.distSq -import com.lambda.util.math.flooredBlockPos -import com.lambda.util.math.getHitVec -import com.lambda.util.math.minus -import com.lambda.util.math.plus import com.lambda.util.player.RotationUtils.getVisibleSurfaces import com.lambda.util.player.SlotUtils.hotbarStacks import com.lambda.util.world.fastEntitySearch @@ -135,6 +132,7 @@ object CrystalAura : Module( private val decay = LimitedDecayQueue(10000, 3000L) + private var lastPlace: Pair? = null private val collidingOffsets = mutableListOf().apply { for (x in -1..1) { for (z in -1..1) { @@ -240,6 +238,20 @@ object CrystalAura : Module( decay += crystal.id } + immediateRenderer("CrystalAura Immediate Renderer") { + runSafe { + if (lastPlace != null) { + if (lastPlace!!.second + 50 < System.currentTimeMillis()) { + return@runSafe + } + + box( + lastPlace!!.first, + ) + } + } + } + onEnable { currentTarget = null resetBlueprint() @@ -285,12 +297,16 @@ object CrystalAura : Module( } private fun SafeContext.placeInternal(opportunity: Opportunity, hand: Hand) { + runSafe { + lastPlace = Pair(opportunity.blockPos, System.currentTimeMillis()) + } interaction.syncSelectedSlot() - connection.sendPacket { - PlayerInteractBlockC2SPacket( - hand, BlockHitResult(opportunity.crystalPosition, opportunity.side, opportunity.blockPos, false), 0 - ) - } + mc.interactionManager!!.sendSequencedPacket(world, { sequence -> + + PlayerInteractBlockC2SPacket( + hand, BlockHitResult(opportunity.crystalPosition, opportunity.side, opportunity.blockPos, false), sequence + ) + }); player.swingHand(hand) } From 31514f76962a4cafa76e6247ed072eacbca559eb Mon Sep 17 00:00:00 2001 From: Matias Date: Thu, 20 Aug 2026 17:31:27 +0300 Subject: [PATCH 2/4] improve rendering --- .../module/modules/combat/CrystalAura.kt | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt index a89d749bd..cd1f3ad4f 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt @@ -19,14 +19,18 @@ package com.lambda.module.modules.combat import com.lambda.config.Tab import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.blocks.LineConfig import com.lambda.config.blocks.TargetingSettings import com.lambda.config.hide import com.lambda.config.hideAllExcept +import com.lambda.config.blocks.WorldLineSettings +import com.lambda.config.forEachSetting import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.EntityEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.graphics.mc.BoxBuilder import com.lambda.graphics.mc.renderer.ImmediateRenderer.Companion.immediateRenderer import com.lambda.interaction.handlers.ContainerHandler.transfer import com.lambda.interaction.managers.hotbar.HotbarRequest @@ -67,6 +71,7 @@ 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.awt.Color import kotlin.concurrent.fixedRateTimer import kotlin.math.max import kotlin.time.Duration.Companion.milliseconds @@ -82,6 +87,7 @@ object CrystalAura : Module( private const val EXPLODING_TAB = "Exploding" private const val PREDICTION_TAB = "Prediction" private const val TARGETING_TAB = "Targeting" + private const val RENDERING_TAB = "Rendering" @Tab(GENERAL_TAB) private val rotate by setting("Rotate", true) @Tab(GENERAL_TAB) private val updateMode by setting("Update Mode", UpdateMode.Async) @@ -113,6 +119,23 @@ object CrystalAura : Module( @Tab(PREDICTION_TAB) private val targetingSettings by configBlock(TargetingSettings.CombatSettings(this, 10.0)) + @Tab(RENDERING_TAB) private val render by setting("Rendering", true) + @Tab(RENDERING_TAB) private val renderPlacements by setting("Placement Rendering", true) + + @Tab(RENDERING_TAB) private val renderLineSettings by configBlock(WorldLineSettings(this)) + .withEdits { + hideAllExcept ( + ::worldWidthSetting + ) + forEachSetting { + visibility { old -> { old() && render }} + } + } + @Tab(RENDERING_TAB) val primaryColorLine by setting("Primary Color (outline)", Color(130, 200, 255, 200), visibility = { render }) + @Tab(RENDERING_TAB) val secondaryColorLine by setting("Secondary Color (outline)", Color(130, 130, 255, 200), visibility = { render }) + @Tab(RENDERING_TAB) val primaryColor by setting("Primary Color", Color(225, 130, 225, 100), visibility = { render }) + @Tab(RENDERING_TAB) val secondaryColor by setting("Secondary Color", Color(170, 60, 170, 100), visibility = { render }) + private val blueprint = mutableMapOf() private var activeOpportunity: Opportunity? = null private var currentTarget: LivingEntity? = null @@ -247,7 +270,11 @@ object CrystalAura : Module( box( lastPlace!!.first, - ) + renderLineSettings + ) { + outlineGradientY(secondaryColorLine, primaryColorLine) + fillGradientY(secondaryColor, primaryColor) + } } } } From b250f6f23549fd7968e97dff9af842ed8193cab4 Mon Sep 17 00:00:00 2001 From: Matias Date: Thu, 20 Aug 2026 22:28:27 +0300 Subject: [PATCH 3/4] Fixed main hand not swapping because the HotbarRequest was being submitted as now or nothing. Offhand still does not work correctly. --- .../module/modules/combat/CrystalAura.kt | 71 +++++++++++++++---- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt index cd1f3ad4f..4c27f8a30 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt @@ -19,7 +19,6 @@ package com.lambda.module.modules.combat import com.lambda.config.Tab import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.blocks.LineConfig import com.lambda.config.blocks.TargetingSettings import com.lambda.config.hide import com.lambda.config.hideAllExcept @@ -30,7 +29,6 @@ import com.lambda.context.SafeContext import com.lambda.event.events.EntityEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.graphics.mc.BoxBuilder import com.lambda.graphics.mc.renderer.ImmediateRenderer.Companion.immediateRenderer import com.lambda.interaction.handlers.ContainerHandler.transfer import com.lambda.interaction.managers.hotbar.HotbarRequest @@ -47,21 +45,25 @@ import com.lambda.threading.runSafeAutomated import com.lambda.threading.runSafeGameScheduled import com.lambda.util.BlockUtils.blockState import com.lambda.util.CommunicationUtils.info +import com.lambda.util.CommunicationUtils.log import com.lambda.util.PacketUtils.sendPacket import com.lambda.util.Timer import com.lambda.util.collections.LimitedDecayQueue import com.lambda.util.combat.CombatUtils.crystalDamage import com.lambda.util.extension.fullHealth +import com.lambda.util.item.ItemStackUtils.slotId import com.lambda.util.math.* import com.lambda.util.math.MathUtils.ceilToInt import com.lambda.util.math.MathUtils.roundToStep import com.lambda.util.player.RotationUtils.getVisibleSurfaces +import com.lambda.util.player.SlotUtils.hotbarSlots import com.lambda.util.player.SlotUtils.hotbarStacks import com.lambda.util.world.fastEntitySearch import net.minecraft.block.Blocks import net.minecraft.entity.Entity import net.minecraft.entity.LivingEntity import net.minecraft.entity.decoration.EndCrystalEntity +import net.minecraft.item.ItemStack import net.minecraft.item.Items import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket @@ -264,7 +266,7 @@ object CrystalAura : Module( immediateRenderer("CrystalAura Immediate Renderer") { runSafe { if (lastPlace != null) { - if (lastPlace!!.second + 50 < System.currentTimeMillis()) { + if (lastPlace!!.second + 100 < System.currentTimeMillis()) { return@runSafe } @@ -327,7 +329,7 @@ object CrystalAura : Module( runSafe { lastPlace = Pair(opportunity.blockPos, System.currentTimeMillis()) } - interaction.syncSelectedSlot() + interaction.syncSelectedSlot() // TODO: when server only hotbar swap gets implemented, this will be removed mc.interactionManager!!.sendSequencedPacket(world, { sequence -> PlayerInteractBlockC2SPacket( @@ -404,7 +406,7 @@ object CrystalAura : Module( val entitiesNearby = fastEntitySearch(3.5, pos) val crystals = entitiesNearby.filterIsInstance() - val otherEntities = entitiesNearby - crystals + player + val otherEntities = entitiesNearby - crystals.toSet() + player if (otherEntities.any { it.boundingBox.intersects(crystalBox) @@ -454,14 +456,13 @@ object CrystalAura : Module( // Associate by actions blueprint.values.forEach { opportunity -> actionMap.getOrPut(opportunity.actionType, ::mutableListOf) += opportunity - if (opportunity.actionType.priority > actionType.priority) { actionType = opportunity.actionType } } // Select best action - activeOpportunity = actionMap[actionType]?.maxByOrNull { + activeOpportunity = actionMap[actionType]?.filter { !it.blocked }?.maxByOrNull { it.priority } } @@ -524,26 +525,66 @@ object CrystalAura : Module( fun place() = runSafe { if (rotate && !rotationRequest { rotation(placeRotation) }.submit().done) return@runSafe - + var crystalHand: Hand? = null val selection = selectStack { isItem(Items.END_CRYSTAL) } - if ((swapHand == Hand.MAIN_HAND && player.mainHandStack.item != selection.item) || - (swapHand == Hand.OFF_HAND && player.offHandStack.item != selection.item) + if ((swapHand == Hand.MAIN_HAND && player.mainHandStack.item != Items.END_CRYSTAL) || + (swapHand == Hand.OFF_HAND && player.offHandStack.item != Items.END_CRYSTAL) ) runSafeAutomated { if (!swap) return@runSafe - var crystalSlot = player.hotbarStacks.indexOfFirst { selection.filterStack(it) } - if (crystalSlot < 0) { + var hotbarStack: ItemStack? = null + + fun findInHotbar(): Pair { + hotbarStack = selection.bestItemMatch(player.hotbarStacks)?: return (false to -1) + val hotbarSlot = hotbarStack.slotId + return (hotbarSlot >= 0) to hotbarSlot + } + + fun findInOffhand(): Pair { + return (player.offHandStack.item == selection.item) to player.offHandStack.slotId + } + + val crystalSearch = when (swapHand) { + Hand.MAIN_HAND -> listOf( + Hand.MAIN_HAND to ::findInHotbar, + Hand.OFF_HAND to ::findInOffhand + ) + Hand.OFF_HAND -> listOf( + Hand.OFF_HAND to ::findInOffhand, + Hand.MAIN_HAND to ::findInHotbar + ) + } + + val searchResult = crystalSearch + .asSequence() + .map { (hand, finder) -> + val (found, slot) = finder() + Triple(found, slot, hand) + } + .firstOrNull { (found) -> found } + + crystalHand = searchResult?.third + + if (crystalHand == null) { // no crystal stack found in main or offhand val swapTo = when (swapHand) { + //TODO: add support for server side hotbar switching Hand.MAIN_HAND -> HotbarContainer Hand.OFF_HAND -> OffHandContainer } + + // retrieve from inventory, return if the task is not ready if (!selection.transfer(swapTo)) return@runSafe - crystalSlot = player.hotbarStacks.indexOfFirst { selection.filterStack(it) } } - if (!HotbarRequest(crystalSlot, this).submit().done) return@runSafe + if (crystalHand == Hand.MAIN_HAND && swapHand == Hand.MAIN_HAND) { + val s = player.hotbarStacks.indexOf(hotbarStack?: return@runSafe) + Lambda.LOG.info("$s, $swapHand, $crystalHand, ${player.hotbarStacks.size}") + if (!HotbarRequest(s, this@CrystalAura, nowOrNothing = false).submit().done) return@runSafe + } else if (crystalHand == null) { + return@runSafe + } } placeTimer.runSafeIfPassed(placeDelay.milliseconds) { - placeInternal(this@Opportunity, swapHand) + placeInternal(this@Opportunity, crystalHand?: swapHand) // we should not be here without a crystal in hand but ig better to check than not to if (prediction.onPlace) predictionTimer.runIfNotPassed(packetLifetime.milliseconds, false) { From f0f62aeae4f9aee66472f75d2f0e9cf15c84f9ca Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 21 Aug 2026 20:27:02 +0300 Subject: [PATCH 4/4] New prediction mode that does not flag grim, set the default update mode to ticked as async was being weird. Fixed hotbar logic. --- .../module/modules/combat/CrystalAura.kt | 134 ++++++++---------- .../module/modules/movement/TargetStrafe.kt | 4 +- 2 files changed, 65 insertions(+), 73 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt index 4c27f8a30..03c0927d1 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt @@ -45,18 +45,15 @@ import com.lambda.threading.runSafeAutomated import com.lambda.threading.runSafeGameScheduled import com.lambda.util.BlockUtils.blockState import com.lambda.util.CommunicationUtils.info -import com.lambda.util.CommunicationUtils.log import com.lambda.util.PacketUtils.sendPacket import com.lambda.util.Timer import com.lambda.util.collections.LimitedDecayQueue import com.lambda.util.combat.CombatUtils.crystalDamage import com.lambda.util.extension.fullHealth -import com.lambda.util.item.ItemStackUtils.slotId import com.lambda.util.math.* import com.lambda.util.math.MathUtils.ceilToInt import com.lambda.util.math.MathUtils.roundToStep import com.lambda.util.player.RotationUtils.getVisibleSurfaces -import com.lambda.util.player.SlotUtils.hotbarSlots import com.lambda.util.player.SlotUtils.hotbarStacks import com.lambda.util.world.fastEntitySearch import net.minecraft.block.Blocks @@ -92,7 +89,7 @@ object CrystalAura : Module( private const val RENDERING_TAB = "Rendering" @Tab(GENERAL_TAB) private val rotate by setting("Rotate", true) - @Tab(GENERAL_TAB) private val updateMode by setting("Update Mode", UpdateMode.Async) + @Tab(GENERAL_TAB) private val updateMode by setting("Update Mode", UpdateMode.Ticked) @Tab(GENERAL_TAB) private val updateDelaySetting by setting("Update Delay", 25L, 5L..200L, 5L, unit = " ms") { updateMode == UpdateMode.Async } @Tab(GENERAL_TAB) private val maxUpdatesPerFrame by setting("Max Updates Per Frame", 5, 1..20, 1) { updateMode == UpdateMode.Async } @Tab(GENERAL_TAB) private val updateDelay get() = if (updateMode == UpdateMode.Async) updateDelaySetting else 0L @@ -114,8 +111,10 @@ object CrystalAura : Module( @Tab(EXPLODING_TAB) private val explodeDelay by setting("Explode Delay", 10L, 0L..1000L, 1L, "Delay between explosion attempts", " ms") @Tab(PREDICTION_TAB) private val prediction by setting("Prediction", PredictionMode.None) - @Tab(PREDICTION_TAB) private val packetPredictions by setting("Packet Predictions", 1, 0..20, 1) { prediction.onPacket } - @Tab(PREDICTION_TAB) private val placePostPause by setting("Place Post Pause", true) { prediction.onPacket } + @Tab(PREDICTION_TAB) private val packetPredictions by setting("Packet Predictions", 1, 0..20, 1, "Flags grim") { prediction.onPacket } + @Tab(PREDICTION_TAB) private val explodeOnPacket by setting("Explode On Packet", false, "Explodes the received crystal on packet") { prediction != PredictionMode.None } + @Tab(PREDICTION_TAB) private val placePostPause by setting("Place Post Pause", false, "Resets the place delay timer after receiving a entity spawn packet (adds a delay)") { prediction != PredictionMode.None } + @Tab(PREDICTION_TAB) private val postPacketPlace by setting("Post Packet Place", true, "Places the crystal on the next tick from the entity spawn packet") { prediction == PredictionMode.Tick && !placePostPause } @Tab(PREDICTION_TAB) private val placePredictions by setting("Place Predictions", 4, 1..20, 1) { prediction.onPlace } @Tab(PREDICTION_TAB) private val packetLifetime by setting("Packet Lifetime", 500L, 50L..1000L) { prediction.onPlace } @@ -154,6 +153,8 @@ object CrystalAura : Module( private val predictionTimer = Timer() private var lastEntityId = 0 + private var waitingForCrystal = false + private var safeToPlaceInstantly = false private val decay = LimitedDecayQueue(10000, 3000L) @@ -241,16 +242,20 @@ object CrystalAura : Module( // Run packet prediction if (!prediction.isActive || activeOpportunity != opportunity) return@listen - explodeInternal(lastEntityId) - - if (!prediction.onPacket) return@listen + if (explodeOnPacket) { + explodeInternal(lastEntityId) + } - repeat(packetPredictions) { - placeInternal(opportunity, swapHand) - explodeInternal(++lastEntityId) + if (!prediction.onPacket) { + // this only works in vanilla + repeat(packetPredictions) { + placeInternal(opportunity, swapHand) + explodeInternal(++lastEntityId) + } } if (placePostPause) placeTimer.reset() + if (postPacketPlace) safeToPlaceInstantly = true } listen { event -> @@ -303,9 +308,8 @@ object CrystalAura : Module( } private fun tickInteraction(best: Opportunity) { - if (!best.blocked) { + if (!best.blocked && best.crystal != null) { best.explode() - best.place() return } @@ -338,6 +342,7 @@ object CrystalAura : Module( }); player.swingHand(hand) + waitingForCrystal = true } private fun SafeContext.explodeInternal(id: Int) { @@ -531,72 +536,50 @@ object CrystalAura : Module( (swapHand == Hand.OFF_HAND && player.offHandStack.item != Items.END_CRYSTAL) ) runSafeAutomated { if (!swap) return@runSafe - var hotbarStack: ItemStack? = null - - fun findInHotbar(): Pair { - hotbarStack = selection.bestItemMatch(player.hotbarStacks)?: return (false to -1) - val hotbarSlot = hotbarStack.slotId - return (hotbarSlot >= 0) to hotbarSlot - } - - fun findInOffhand(): Pair { - return (player.offHandStack.item == selection.item) to player.offHandStack.slotId - } - - val crystalSearch = when (swapHand) { - Hand.MAIN_HAND -> listOf( - Hand.MAIN_HAND to ::findInHotbar, - Hand.OFF_HAND to ::findInOffhand - ) - Hand.OFF_HAND -> listOf( - Hand.OFF_HAND to ::findInOffhand, - Hand.MAIN_HAND to ::findInHotbar - ) + val itemToUse: ItemStack? = if (player.mainHandStack.item == Items.END_CRYSTAL) { + crystalHand = Hand.MAIN_HAND + player.mainHandStack + } else if (player.offHandStack.item == Items.END_CRYSTAL) { + crystalHand = Hand.OFF_HAND + player.offHandStack + } else null + + val swapTo = when (swapHand) { + Hand.MAIN_HAND -> HotbarContainer + Hand.OFF_HAND -> OffHandContainer } - val searchResult = crystalSearch - .asSequence() - .map { (hand, finder) -> - val (found, slot) = finder() - Triple(found, slot, hand) + if (itemToUse == null || swapHand == Hand.MAIN_HAND) { + if (swapHand == Hand.MAIN_HAND) { + val itemStack = selection.bestItemMatch(player.hotbarStacks) + if (itemStack == null) { // retrieve to hotbar + if (!selection.transfer(swapTo)) return@runSafe + } + val s = player.hotbarStacks.indexOf(itemStack) + if ((!HotbarRequest(s, this@CrystalAura, nowOrNothing = false).submit().done) && itemToUse == null) return@runSafe + } else { // retrieve to offhand + if (!selection.transfer(swapTo)) return@runSafe } - .firstOrNull { (found) -> found } - - crystalHand = searchResult?.third - - if (crystalHand == null) { // no crystal stack found in main or offhand - val swapTo = when (swapHand) { - //TODO: add support for server side hotbar switching - Hand.MAIN_HAND -> HotbarContainer - Hand.OFF_HAND -> OffHandContainer - } - - // retrieve from inventory, return if the task is not ready - if (!selection.transfer(swapTo)) return@runSafe - } - if (crystalHand == Hand.MAIN_HAND && swapHand == Hand.MAIN_HAND) { - val s = player.hotbarStacks.indexOf(hotbarStack?: return@runSafe) - Lambda.LOG.info("$s, $swapHand, $crystalHand, ${player.hotbarStacks.size}") - if (!HotbarRequest(s, this@CrystalAura, nowOrNothing = false).submit().done) return@runSafe - } else if (crystalHand == null) { - return@runSafe } } - placeTimer.runSafeIfPassed(placeDelay.milliseconds) { - placeInternal(this@Opportunity, crystalHand?: swapHand) // we should not be here without a crystal in hand but ig better to check than not to + if (placeTimer.timePassed(placeDelay.milliseconds) || (postPacketPlace && safeToPlaceInstantly && !placePostPause)) { + runSafe { + placeInternal(this@Opportunity, crystalHand?: swapHand) // we should not be here without a crystal in hand but ig better to check than not to + safeToPlaceInstantly = false + if (prediction.onPlace) + predictionTimer.runIfNotPassed(packetLifetime.milliseconds, false) { + val last = lastEntityId - if (prediction.onPlace) - predictionTimer.runIfNotPassed(packetLifetime.milliseconds, false) { - val last = lastEntityId + repeat(placePredictions) { + explodeInternal(++lastEntityId) + } - repeat(placePredictions) { - explodeInternal(++lastEntityId) + lastEntityId = last + 1 + crystal = null } - - lastEntityId = last + 1 - crystal = null - } + placeTimer.reset() + } } } @@ -607,6 +590,13 @@ object CrystalAura : Module( fun explode() { if (rotate && !rotationRequest { rotation(placeRotation) }.submit().done) return + if (waitingForCrystal && crystal == null && prediction == PredictionMode.Tick) { + runSafe { + explodeInternal(lastEntityId++) + waitingForCrystal = false + } + } + explodeTimer.runSafeIfPassed(explodeDelay.milliseconds) { crystal?.let { crystal -> explodeInternal(crystal.id) @@ -654,6 +644,8 @@ object CrystalAura : Module( // Predict on place Deferred(false, true), + Tick(false, false), + // Predict on both timings Mixed(true, true); diff --git a/src/main/kotlin/com/lambda/module/modules/movement/TargetStrafe.kt b/src/main/kotlin/com/lambda/module/modules/movement/TargetStrafe.kt index 116e68521..ae1cae803 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/TargetStrafe.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/TargetStrafe.kt @@ -17,8 +17,8 @@ package com.lambda.module.modules.movement -import com.lambda.config.ConfigEditor.forEachSetting -import com.lambda.config.ConfigEditor.hideAllExcept +import com.lambda.config.forEachSetting +import com.lambda.config.hideAllExcept import com.lambda.config.blocks.WorldLineSettings import com.lambda.config.withEdits import com.lambda.context.SafeContext