-
Notifications
You must be signed in to change notification settings - Fork 41
Improve crystal aura (second try at git) #326
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 1.21.11
Are you sure you want to change the base?
Changes from all commits
a11561a
31514f7
b250f6f
f0f62ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,11 +22,14 @@ import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomat | |
| 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.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,20 +50,17 @@ 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 | ||
| 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 | ||
|
|
@@ -70,6 +70,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 | ||
|
|
@@ -85,9 +86,10 @@ 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) | ||
| @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 | ||
|
|
@@ -109,13 +111,32 @@ 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 } | ||
|
|
||
| @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 }} | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we typically keep spaces between }} in scenarios like this. No biggie, just thought i'd say anyway |
||
| } | ||
| } | ||
| @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<BlockPos, Opportunity>() | ||
| private var activeOpportunity: Opportunity? = null | ||
| private var currentTarget: LivingEntity? = null | ||
|
|
@@ -132,9 +153,12 @@ object CrystalAura : Module( | |
|
|
||
| private val predictionTimer = Timer() | ||
| private var lastEntityId = 0 | ||
| private var waitingForCrystal = false | ||
| private var safeToPlaceInstantly = false | ||
|
|
||
| private val decay = LimitedDecayQueue<Int>(10000, 3000L) | ||
|
|
||
| private var lastPlace: Pair<BlockPos, Long>? = null | ||
| private val collidingOffsets = mutableListOf<BlockPos>().apply { | ||
| for (x in -1..1) { | ||
| for (z in -1..1) { | ||
|
|
@@ -218,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<EntityEvent.Removal> { event -> | ||
|
|
@@ -240,6 +268,24 @@ object CrystalAura : Module( | |
| decay += crystal.id | ||
| } | ||
|
|
||
| immediateRenderer("CrystalAura Immediate Renderer") { | ||
| runSafe { | ||
| if (lastPlace != null) { | ||
| if (lastPlace!!.second + 100 < System.currentTimeMillis()) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we never use !! as its an unsafe operator. Could be changed to use val place = lastPlace ?: return@listen then using the place value as we know its not null |
||
| return@runSafe | ||
| } | ||
|
|
||
| box( | ||
| lastPlace!!.first, | ||
| renderLineSettings | ||
| ) { | ||
| outlineGradientY(secondaryColorLine, primaryColorLine) | ||
| fillGradientY(secondaryColor, primaryColor) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| onEnable { | ||
| currentTarget = null | ||
| resetBlueprint() | ||
|
|
@@ -262,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 | ||
| } | ||
|
|
||
|
|
@@ -285,14 +330,19 @@ object CrystalAura : Module( | |
| } | ||
|
|
||
| private fun SafeContext.placeInternal(opportunity: Opportunity, hand: Hand) { | ||
| interaction.syncSelectedSlot() | ||
| connection.sendPacket { | ||
| PlayerInteractBlockC2SPacket( | ||
| hand, BlockHitResult(opportunity.crystalPosition, opportunity.side, opportunity.blockPos, false), 0 | ||
| ) | ||
| } | ||
| runSafe { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we're already in a SafeContext so we shouldnt need runSafe here |
||
| lastPlace = Pair(opportunity.blockPos, System.currentTimeMillis()) | ||
| } | ||
| interaction.syncSelectedSlot() // TODO: when server only hotbar swap gets implemented, this will be removed | ||
| mc.interactionManager!!.sendSequencedPacket(world, { sequence -> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can just use interaction.sendSequencedPacket due to the SafeContext |
||
|
|
||
| PlayerInteractBlockC2SPacket( | ||
| hand, BlockHitResult(opportunity.crystalPosition, opportunity.side, opportunity.blockPos, false), sequence | ||
| ) | ||
| }); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need for ; here and the lambda can be moved out of the parenthesis like how the settings do visibility |
||
|
|
||
| player.swingHand(hand) | ||
| waitingForCrystal = true | ||
| } | ||
|
|
||
| private fun SafeContext.explodeInternal(id: Int) { | ||
|
|
@@ -361,7 +411,7 @@ object CrystalAura : Module( | |
|
|
||
| val entitiesNearby = fastEntitySearch<Entity>(3.5, pos) | ||
| val crystals = entitiesNearby.filterIsInstance<EndCrystalEntity>() | ||
| val otherEntities = entitiesNearby - crystals + player | ||
| val otherEntities = entitiesNearby - crystals.toSet() + player | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this to make duplicate lookups faster?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah |
||
|
|
||
| if (otherEntities.any { | ||
| it.boundingBox.intersects(crystalBox) | ||
|
|
@@ -411,14 +461,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 | ||
| } | ||
| } | ||
|
|
@@ -481,38 +530,56 @@ 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) { | ||
| val swapTo = when (swapHand) { | ||
| Hand.MAIN_HAND -> HotbarContainer | ||
| Hand.OFF_HAND -> OffHandContainer | ||
| } | ||
| if (!selection.transfer(swapTo)) return@runSafe | ||
| crystalSlot = player.hotbarStacks.indexOfFirst { selection.filterStack(it) } | ||
| } | ||
| if (!HotbarRequest(crystalSlot, this).submit().done) return@runSafe | ||
| 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 | ||
| } | ||
|
|
||
| if (itemToUse == null || swapHand == Hand.MAIN_HAND) { | ||
| if (swapHand == Hand.MAIN_HAND) { | ||
| val itemStack = selection.bestItemMatch(player.hotbarStacks) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this works, but ive been migrating things to use the containers. This would instead use HotbarContainer to access the slots |
||
| if (itemStack == null) { // retrieve to hotbar | ||
| if (!selection.transfer(swapTo)) return@runSafe | ||
| } | ||
| val s = player.hotbarStacks.indexOf(itemStack) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. instead of indexOf here, you could use the container as said above, and then access the index through Slot::index |
||
| if ((!HotbarRequest(s, this@CrystalAura, nowOrNothing = false).submit().done) && itemToUse == null) return@runSafe | ||
| } else { // retrieve to offhand | ||
| if (!selection.transfer(swapTo)) return@runSafe | ||
| } | ||
| } | ||
| } | ||
|
|
||
| placeTimer.runSafeIfPassed(placeDelay.milliseconds) { | ||
| placeInternal(this@Opportunity, swapHand) | ||
| if (placeTimer.timePassed(placeDelay.milliseconds) || (postPacketPlace && safeToPlaceInstantly && !placePostPause)) { | ||
| runSafe { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldnt be a need here for runSafe as we're already in a runSafe context from the start of the function |
||
| 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() | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -523,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) | ||
|
|
@@ -570,6 +644,8 @@ object CrystalAura : Module( | |
| // Predict on place | ||
| Deferred(false, true), | ||
|
|
||
| Tick(false, false), | ||
|
|
||
| // Predict on both timings | ||
| Mixed(true, true); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can inline this so its (::worldWidthSetting)