@@ -30,12 +30,17 @@ import com.lambda.graphics.gl.Matrices.buildWorldProjection
3030import com.lambda.graphics.gl.Matrices.withVertexTransform
3131import com.lambda.graphics.renderer.gui.FontRenderer
3232import com.lambda.graphics.renderer.gui.FontRenderer.drawString
33+ import com.lambda.interaction.material.StackSelection.Companion.selectStack
34+ import com.lambda.interaction.material.container.ContainerManager.transfer
35+ import com.lambda.interaction.material.container.containers.MainHandContainer
36+ import com.lambda.interaction.material.container.containers.OffHandContainer
3337import com.lambda.interaction.request.rotating.Rotation.Companion.rotationTo
3438import com.lambda.interaction.request.rotating.RotationManager
3539import com.lambda.interaction.request.rotating.visibilty.VisibilityChecker.getVisibleSurfaces
3640import com.lambda.interaction.request.rotating.visibilty.lookAt
3741import com.lambda.module.Module
3842import com.lambda.module.tag.ModuleTag
43+ import com.lambda.task.RootTask.run
3944import com.lambda.threading.runSafe
4045import com.lambda.threading.runSafeGameScheduled
4146import com.lambda.util.BlockUtils.blockState
@@ -45,6 +50,7 @@ import com.lambda.util.PacketUtils.sendPacket
4550import com.lambda.util.Timer
4651import com.lambda.util.collections.LimitedDecayQueue
4752import com.lambda.util.combat.CombatUtils.crystalDamage
53+ import com.lambda.util.extension.fullHealth
4854import com.lambda.util.math.MathUtils.ceilToInt
4955import com.lambda.util.math.MathUtils.roundToStep
5056import com.lambda.util.math.Vec2d
@@ -58,6 +64,7 @@ import net.minecraft.block.Blocks
5864import net.minecraft.entity.Entity
5965import net.minecraft.entity.LivingEntity
6066import net.minecraft.entity.decoration.EndCrystalEntity
67+ import net.minecraft.item.Items
6168import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket
6269import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket
6370import net.minecraft.util.Hand
@@ -76,24 +83,29 @@ object CrystalAura : Module(
7683 tag = ModuleTag .COMBAT ,
7784) {
7885 /* General */
79- private val placeRange by setting(" Place Range" , 4.6 , 1.0 .. 7.0 , 0.1 , " Range to place crystals" , " blocks" ).group(Group .General )
80- private val explodeRange by setting(" Explode Range" , 3.0 , 1.0 .. 7.0 , 0.1 , " Range to explode crystals" , " blocks" ).group(Group .General )
81- private val placeDelay by setting(" Place Delay" , 50L , 0L .. 1000L , 1L , " Delay between placement attempts" , " ms" ).group(Group .General )
82- private val explodeDelay by setting(" Explode Delay" , 10L , 0L .. 1000L , 1L , " Delay between explosion attempts" , " ms" ).group(Group .General )
8386 private val updateMode by setting(" Update Mode" , UpdateMode .Async ).group(Group .General )
8487 private val updateDelaySetting by setting(" Update Delay" , 25L , 5L .. 200L , 5L , unit = " ms" ) { updateMode == UpdateMode .Async }.group(Group .General )
8588 private val maxUpdatesPerFrame by setting(" Max Updates Per Frame" , 5 , 1 .. 20 , 1 ) { updateMode == UpdateMode .Async }.group(Group .General )
8689 private val updateDelay get() = if (updateMode == UpdateMode .Async ) updateDelaySetting else 0L
8790 private val debug by setting(" Debug" , false ).group(Group .General )
8891
8992 /* Placement */
93+ private val placeRange by setting(" Place Range" , 4.6 , 1.0 .. 7.0 , 0.1 , " Range to place crystals" , " blocks" ).group(Group .Placement )
94+ private val placeDelay by setting(" Place Delay" , 50L , 0L .. 1000L , 1L , " Delay between placement attempts" , " ms" ).group(Group .Placement )
95+ private val swap by setting(" Swap" , true , " Swaps to crystals" ).group(Group .Placement )
96+ private val swapHand by setting(" Swap Hand" , Hand .MAIN_HAND , " Which hand to swap the crystal to" ) { swap }.group(Group .Placement )
9097 private val priorityMode by setting(" Crystal Priority" , Priority .Damage ).group(Group .Placement )
9198 private val minDamageAdvantage by setting(" Min Damage Advantage" , 4.0 , 1.0 .. 10.0 , 0.5 ) { priorityMode == Priority .Advantage }.group(Group .Placement )
92- private val minTargetDamage by setting(" Min Target Damage" , 6 .0 , 0.0 .. 20.0 , 0.5 , " Minimum target damage to use crystals" ).group(Group .Placement )
99+ private val minTargetDamage by setting(" Min Target Damage" , 8 .0 , 0.0 .. 20.0 , 0.5 , " Minimum target damage to use crystals" ).group(Group .Placement )
93100 private val maxSelfDamage by setting(" Max Self Damage" , 8.0 , 0.0 .. 36.0 , 0.5 , " Maximum self damage to use crystals" ).group(Group .Placement )
94- // private val minHealth by setting("Min Health", 10.0, 0.0..36.0, 0.5, "Minimum player health to use crystals") { page == Page.General }
101+ private val minPlaceHealth by setting(" Min Place Health" , 5.0 , 0.0 .. 36.0 , 0.5 , " Minimum player health to place crystals" ).group(Group .Placement )
102+ private val preventDeath by setting(" Prevent Death" , true , " Prevent death by crystal" ).group(Group .Placement )
95103 private val oldPlace by setting(" 1.12 Placement" , false ).group(Group .Placement )
96104
105+ /* Exploding */
106+ private val explodeRange by setting(" Explode Range" , 3.0 , 1.0 .. 7.0 , 0.1 , " Range to explode crystals" , " blocks" ).group(Group .Exploding )
107+ private val explodeDelay by setting(" Explode Delay" , 10L , 0L .. 1000L , 1L , " Delay between explosion attempts" , " ms" ).group(Group .Exploding )
108+
97109 /* Prediction */
98110 private val prediction by setting(" Prediction" , PredictionMode .None ).group(Group .Prediction )
99111 private val packetPredictions by setting(" Packet Predictions" , 1 , 0 .. 20 , 1 ) { prediction.onPacket }.group(Group .Prediction )
@@ -216,7 +228,7 @@ object CrystalAura : Module(
216228 if (! prediction.onPacket) return @listen
217229
218230 repeat(packetPredictions) {
219- placeInternal(opportunity, Hand . MAIN_HAND )
231+ placeInternal(opportunity, swapHand )
220232 explodeInternal(++ lastEntityId)
221233 }
222234
@@ -301,29 +313,29 @@ object CrystalAura : Module(
301313 updateTimer.runIfPassed(updateDelay.milliseconds) {
302314 resetBlueprint()
303315
304- // Build damage info
305316 fun info (
306- pos : BlockPos , target : LivingEntity ,
317+ pos : BlockPos ,
318+ target : LivingEntity ,
307319 blocked : Boolean ,
308320 crystal : EndCrystalEntity ? = null
309321 ): Opportunity ? {
310322 val crystalPos = pos.crystalPosition
311323
312- // Calculate the damage to the target from the explosion of the crystal
313324 val targetDamage = crystalDamage(crystalPos, target)
314325 if (targetDamage < minTargetDamage) return null
315326
316- // Calculate the self-damage for the player
317327 val selfDamage = crystalDamage(crystalPos, player)
318- if (selfDamage > maxSelfDamage) return null
328+ if (selfDamage > maxSelfDamage ||
329+ player.fullHealth - selfDamage <= minPlaceHealth ||
330+ (preventDeath && player.fullHealth - selfDamage <= 0 )
331+ ) return null
319332
320333 if (priorityMode == Priority .Advantage && priorityMode.factor(
321334 targetDamage,
322335 selfDamage
323336 ) < minDamageAdvantage
324337 ) return null
325338
326- // Return the calculated damage info if conditions are met
327339 return Opportunity (
328340 pos.toImmutable(),
329341 targetDamage,
@@ -334,7 +346,6 @@ object CrystalAura : Module(
334346 }
335347
336348 // Extra checks for placement, because you may explode but not place in special cases(crystal in the air)
337- @Suppress(" ConvertArgumentToSet" )
338349 fun placeInfo (
339350 pos : BlockPos ,
340351 target : LivingEntity
@@ -470,24 +481,32 @@ object CrystalAura : Module(
470481
471482 /* *
472483 * Places the crystal on [blockPos]
473- * @return Whether the delay passed, null if the interaction failed
474484 */
475- fun place () {
476- if (rotation.rotate && ! lookAt(placeRotation).requestBy(rotation).done) return
485+ fun place () = runSafe {
486+ if (rotation.rotate && ! lookAt(placeRotation).requestBy(rotation).done)
487+ return @runSafe
488+
489+ val selection = selectStack { isItem(Items .END_CRYSTAL ) }
490+ if (swap &&
491+ (swapHand == Hand .MAIN_HAND && player.mainHandStack.item != selection.item) ||
492+ (swapHand == Hand .OFF_HAND && player.offHandStack.item != selection.item)
493+ ) selection.transfer(when (swapHand) { Hand .MAIN_HAND -> MainHandContainer ; Hand .OFF_HAND -> OffHandContainer })
494+ ?.run ()
477495
478496 placeTimer.runSafeIfPassed(placeDelay.milliseconds) {
479- placeInternal(this @Opportunity, Hand . MAIN_HAND )
497+ placeInternal(this @Opportunity, swapHand )
480498
481- if (prediction.onPlace) predictionTimer.runIfNotPassed(packetLifetime.milliseconds, false ) {
482- val last = lastEntityId
499+ if (prediction.onPlace)
500+ predictionTimer.runIfNotPassed(packetLifetime.milliseconds, false ) {
501+ val last = lastEntityId
483502
484- repeat(placePredictions) {
485- explodeInternal(++ lastEntityId)
486- }
503+ repeat(placePredictions) {
504+ explodeInternal(++ lastEntityId)
505+ }
487506
488- lastEntityId = last + 1
489- crystal = null
490- }
507+ lastEntityId = last + 1
508+ crystal = null
509+ }
491510 }
492511 }
493512
@@ -553,6 +572,7 @@ object CrystalAura : Module(
553572 private enum class Group (override val displayName : String ): NamedEnum {
554573 General (" General" ),
555574 Placement (" Placement" ),
575+ Exploding (" Exploding" ),
556576 Prediction (" Prediction" ),
557577 Targeting (" Targeting" ),
558578 Rotation (" Rotation" )
0 commit comments