@@ -24,22 +24,28 @@ import com.lambda.context.SafeContext
2424import com.lambda.event.events.RenderEvent
2525import com.lambda.event.events.TickEvent
2626import com.lambda.event.listener.SafeListener.Companion.listen
27+ import com.lambda.graphics.renderer.esp.builders.ofBox
2728import com.lambda.graphics.renderer.esp.builders.ofShape
2829import com.lambda.interaction.RotationManager.rotate
2930import com.lambda.interaction.rotation.RotationContext
3031import com.lambda.interaction.visibilty.VisibilityChecker.lookAtBlock
3132import com.lambda.module.Module
3233import com.lambda.module.tag.ModuleTag
34+ import com.lambda.threading.runSafe
3335import com.lambda.util.BlockUtils.blockState
3436import com.lambda.util.collections.LimitedDecayQueue
3537import com.lambda.util.combat.CombatUtils.explosionDamage
38+ import com.lambda.util.math.MathUtils.ceilToInt
3639import com.lambda.util.math.VecUtils.dist
3740import com.lambda.util.math.VecUtils.vec3d
3841import com.lambda.util.math.transform
42+ import com.lambda.util.world.fastEntitySearch
43+ import com.lambda.util.world.raycast.RayCastUtils.blockResult
3944import net.minecraft.block.Blocks
4045import net.minecraft.entity.LivingEntity
46+ import net.minecraft.entity.decoration.EndCrystalEntity
47+ import net.minecraft.item.Items
4148import net.minecraft.util.Hand
42- import net.minecraft.util.hit.BlockHitResult
4349import net.minecraft.util.math.BlockPos
4450import net.minecraft.util.math.Box
4551import net.minecraft.util.math.Vec3d
@@ -50,29 +56,32 @@ object CrystalAura : Module(
5056 description = " Automatically attacks entities with crystals" ,
5157 defaultTags = setOf(ModuleTag .COMBAT ),
5258) {
53- private val page by setting(" Page" , Page .Targeting )
59+ private val page by setting(" Page" , Page .General )
60+
61+ /* General */
62+ private val strategy by setting(" Strategy" , Strategy .ExplodeBeforePlace ) { page == Page .General }
5463
5564 /* Targeting */
5665 // ToDo: Targeting Range should be reach + crystal range (also based on min damage)
5766 private val targeting = Targeting .Combat (this , 10.0 ) { page == Page .Targeting }
5867
5968 /* Placing */
60- private val doPlace by setting(" Do Place" , true ) { page == Page .Placing }
61- private val swap by setting(" Swap" , Hand .MAIN_HAND , description = " Automatically swap to place crystals" ) { page == Page .Placing }
62- private val placeMethod by setting(" Place Sort" , DamageSort .Deadly ) { page == Page .Placing }
63- // private val multiPlace by setting("Multi Place", true, description = "Place crystals") { page == Page.Placing }
64- private val minSeparation by setting(" Minimum Crystal Separation" , 1 , 1 .. 3 , 1 , description = " The minimum space between crystals" , unit = " blocks" ) { page == Page .Placing }
65- private val placeDelay by setting(" Place Delay" , 0L , 0L .. 1000L , 10L , description = " Delay between crystal placements" , unit = " ms" ) { page == Page .Placing }
66- private val placeMinHealth by setting(" Place Min Health" , 10.0 , 0.0 .. 36.0 , 0.5 , description = " Minimum health to place a crystal" ) { page == Page .Placing }
67- private val placeMinDamage by setting(" Place Min Damage" , 6.0 , 0.0 .. 20.0 , 0.5 , description = " Minimum damage to place a crystal" ) { page == Page .Placing }
68- private val placeMaxSelfDamage by setting(" Place Max Self Damage" , 8.0 , 0.0 .. 20.0 , 0.5 , description = " Maximum self damage to place a crystal" ) { page == Page .Placing }
69+ private val place by setting(" Place Crystals " , true ) { page == Page .Placing }
70+ private val swap by setting(" Swap" , Hand .MAIN_HAND , description = " Automatically swap to place crystals" ) { page == Page .Placing && place }
71+ private val placeMethod by setting(" Place Sort" , DamageSort .Deadly ) { page == Page .Placing && place }
72+ // private val multiPlace by setting("Multi Place", true, description = "Place crystals") { page == Page.Placing && place }
73+ private val minSeparation by setting(" Minimum Crystal Separation" , 1 , 1 .. 3 , 1 , " The minimum space between crystals" , " blocks" ) { page == Page .Placing && place }
74+ private val placeDelay by setting(" Place Delay" , 0L , 0L .. 1000L , 10L , " Delay between crystal placements" , " ms" ) { page == Page .Placing && place }
75+ private val placeMinHealth by setting(" Place Min Health" , 10.0 , 0.0 .. 36.0 , 0.5 , " Minimum health to place a crystal" ) { page == Page .Placing && place }
76+ private val placeMinDamage by setting(" Place Min Damage" , 6.0 , 0.0 .. 20.0 , 0.5 , " Minimum damage to place a crystal" ) { page == Page .Placing && place }
77+ private val placeMaxSelfDamage by setting(" Place Max Self Damage" , 8.0 , 0.0 .. 20.0 , 0.5 , " Maximum self damage to place a crystal" ) { page == Page .Placing && place }
6978
7079 /* Exploding */
71- private val doExplode by setting(" Do Explode" , true ) { page == Page .Exploding }
72- private val explodeDelay by setting(" Explode Delay" , 0 , 0 .. 20 , 1 , description = " Delay between crystal explosions" , unit = " ticks" ) { page == Page .Exploding }
73- private val explodeRange by setting(" Explode Range" , 5.0 , 0.1 .. 7.0 , 0.1 , description = " Range to explode crystals" ) { page == Page .Exploding }
74- private val explodeMethod by setting(" Explode Sort" , DamageSort .Deadly ) { page == Page .Exploding }
75- private val explodeMinDamage by setting(" Explode Min Damage" , 6.0 , 0.0 .. 20.0 , 0.5 , description = " Minimum damage to explode a crystal" ) { page == Page .Exploding }
80+ private val explode by setting(" Explode Crystals " , true ) { page == Page .Exploding }
81+ private val explodeDelay by setting(" Explode Delay" , 0 , 0 .. 20 , 1 , " Delay between crystal explosions" , " ticks" ) { page == Page .Exploding && explode }
82+ private val explodeRange by setting(" Explode Range" , 5.0 , 0.1 .. 7.0 , 0.1 , " Range to explode crystals" , " blocks " ) { page == Page .Exploding && explode }
83+ private val explodeMethod by setting(" Explode Sort" , DamageSort .Deadly ) { page == Page .Exploding && explode }
84+ private val explodeMinDamage by setting(" Explode Min Damage" , 6.0 , 0.0 .. 20.0 , 0.5 , " Minimum damage to explode a crystal" ) { page == Page .Exploding && explode }
7685
7786 /* Rotation */
7887 private val rotation = RotationSettings (this ) { page == Page .Rotation }
@@ -82,28 +91,43 @@ object CrystalAura : Module(
8291
8392 /* Rendering */
8493 private val renderCrystals by setting(" Render Crystal" , true ) { page == Page .Rendering }
85- private val crystalColor by setting(" Color Comparator" , ColorComparator . Damage ) { page == Page .Rendering && renderCrystals }
94+ private val crystalColor by setting(" Color Comparator" , ColorMode . TargetDamage ) { page == Page .Rendering && renderCrystals }
8695 private val crystalAlpha by setting(" Color Alpha" , 128 , 0 .. 255 ) { page == Page .Rendering && renderCrystals }
8796
97+ private enum class Page {
98+ General ,
99+ Targeting ,
100+ Placing ,
101+ Exploding ,
102+ Rotation ,
103+ Interaction ,
104+ Rendering
105+ }
106+
88107 private val placements = LimitedDecayQueue <BlockPos >(64 , 1000L )
108+ private val placementTargets = mutableListOf<PlacementTarget >()
89109 private val target: LivingEntity ? get() = targeting.target()
90110
91111 private var currentRotation: RotationContext ? = null
92112
93113 init {
94114 listen<TickEvent .Pre > {
95115 currentRotation?.let { rotate ->
116+ if (! place) return @let
96117 if (! rotate.isValid) return @let
97- (rotate.hitResult as ? BlockHitResult )?.let { result ->
98- interaction.interactBlock(player, Hand .MAIN_HAND , result)
99- placements.add(result.blockPos)
100- currentRotation = null
101- }
118+ val blockHit = rotate.hitResult?.blockResult ? : return @let
119+ val inMainHand = player.mainHandStack.item == Items .END_CRYSTAL
120+ val inOffHand = player.offHandStack.item == Items .END_CRYSTAL
121+ if (! inMainHand && ! inOffHand) return @let
122+ val hand = if (inMainHand) Hand .MAIN_HAND else Hand .OFF_HAND
123+ interaction.interactBlock(player, hand, blockHit)
124+ placements.add(blockHit.blockPos)
125+ currentRotation = null
102126 }
103127
104128 target?.let { tar ->
105- val validPositions = findTargetPositions (tar).filter { it.blockPos !in placements }
106- testRender .addAll(validPositions.map { it.blockPos } )
129+ val validPositions = findPlacementTargets (tar).filter { it.blockPos !in placements }
130+ placementTargets .addAll(validPositions)
107131 currentRotation = validPositions.firstNotNullOfOrNull {
108132 lookAtBlock(it.blockPos.toImmutable(), rotation, interact)
109133 }
@@ -112,44 +136,50 @@ object CrystalAura : Module(
112136
113137 rotate {
114138 request {
139+ if (! place) return @request null
115140 currentRotation
116141 }
117142 }
118143
119144 listen<RenderEvent .StaticESP > {
120- // worldCrystals(target ?: return@listen).forEach { crystal ->
121- // it.renderer.build(
122- // Box.of(crystal.blockPos.toCenterPos(), 1.0, 1.0, 1.0),
123- // crystalColor.compared(this, target ?: return@forEach, crystal.pos),
124- // crystalColor.compared(this, target ?: return@forEach, crystal.pos)
125- // )
126- // }
127-
128- val blurple = Color (85 , 57 , 204 , 50 )
129- testRender.forEach { pos ->
130- it.renderer.ofShape(pos, blurple, blurple)
145+ findExplosionTargets(target ? : return @listen).forEach { crystalExplosion ->
146+ val color = crystalExplosion.color
147+ it.renderer.ofBox(crystalExplosion.crystal.boundingBox, color, color)
131148 }
132149
133- testRender.clear()
150+ placementTargets.forEach { target ->
151+ val color = target.color
152+ it.renderer.ofShape(target.blockPos, color, color)
153+ }
154+
155+ placementTargets.clear()
134156 }
135157 }
136158
137- // private fun SafeContext.worldCrystals(target: LivingEntity) =
138- // fastEntitySearch<EndCrystalEntity>(explodeRange, pos = target.blockPos)
139- // .sortedByDescending { explodeMethod.sorted(this, target, it.blockPos) }
159+ private fun SafeContext.findExplosionTargets (target : LivingEntity ): List <ExplosionTarget > {
160+ val maximumRange = (1 - (explodeMinDamage / 12.0 )) * 12.0
161+ return fastEntitySearch<EndCrystalEntity >(maximumRange, target.blockPos)
162+ .filter { it.pos.distanceTo(target.pos) <= maximumRange }
163+ .map { crystal ->
164+ val targetDamage = crystalDamage(crystal.pos, target)
165+ val selfDamage = crystalDamage(crystal.pos, player)
166+ val distance = target.dist(crystal.pos)
167+ ExplosionTarget (crystal, targetDamage, selfDamage, distance)
168+ }
169+ }
140170
141- private fun SafeContext.findTargetPositions (target : LivingEntity ): List <TargetPosition > {
171+ private fun SafeContext.findPlacementTargets (target : LivingEntity ): List <PlacementTarget > {
142172 // This formula is derived from the explosion damage scaling logic. The damage decreases linearly
143173 // with distance, modeled as `damage = (1 - (distance / (power * 2))) * exposure`, where power is the
144174 // explosion's strength (6.0) and exposure defines how much of the explosion affects the target.
145- val maximumRange = ((1 - (placeMinDamage / 12.0 )) * 12.0 ).toInt ()
175+ val maximumRange = ((1 - (placeMinDamage / 12.0 )) * 12.0 ).ceilToInt ()
146176
147177 return BlockPos .iterateOutwards(target.blockPos, maximumRange, maximumRange, maximumRange).mapNotNull { pos ->
148178 targetData(pos, target)
149179 }.sortedWith(placeMethod.comparator)
150180 }
151181
152- private fun SafeContext.targetData (pos : BlockPos , target : LivingEntity ): TargetPosition ? {
182+ private fun SafeContext.targetData (pos : BlockPos , target : LivingEntity ): PlacementTarget ? {
153183 val inRange = pos.dist(player.eyePos) < interact.reach + 1
154184 if (! inRange) return null
155185 val state = pos.blockState(world)
@@ -167,16 +197,73 @@ object CrystalAura : Module(
167197 if (targetDamage <= placeMinDamage) return null
168198 val selfDamage = explosionDamage(crystalPos, player, 6.0 )
169199 if (selfDamage > placeMaxSelfDamage) return null
170- return TargetPosition (pos.toImmutable(), targetDamage, selfDamage)
200+ val distance = target.dist(crystalPos)
201+ return PlacementTarget (pos.toImmutable(), targetDamage, selfDamage, distance)
171202 }
172203
173- private val testRender = mutableListOf<BlockPos >()
174-
175- data class TargetPosition (
204+ /* *
205+ * @property blockPos The block position associated with this placement target.
206+ * @property targetDamage The damage inflicted on the target.
207+ * @property selfDamage The damage inflicted on the self due to some actions or interactions.
208+ * @property distanceToTarget The distance to the target from the player or reference point.
209+ */
210+ data class PlacementTarget (
176211 val blockPos : BlockPos ,
177- val targetDamage : Double ,
178- val selfDamage : Double ,
179- )
212+ override val targetDamage : Double ,
213+ override val selfDamage : Double ,
214+ override val distanceToTarget : Double ,
215+ ) : Target()
216+
217+ /* *
218+ * @property crystal The targeted `EndCrystalEntity` in the context of the explosion.
219+ * @property targetDamage The amount of damage inflicted on the target as part of the explosion.
220+ * @property selfDamage The amount of damage inflicted on the self due to the explosion.
221+ * @property distanceToTarget The distance from the origin point (e.g., player) to the target.
222+ */
223+ data class ExplosionTarget (
224+ val crystal : EndCrystalEntity ,
225+ override val targetDamage : Double ,
226+ override val selfDamage : Double ,
227+ override val distanceToTarget : Double
228+ ) : Target()
229+
230+ /* *
231+ * Represents a target in a system where damage, distance, and other attributes are evaluated.
232+ *
233+ * @property targetDamage The damage inflicted on the target.
234+ * @property selfDamage The damage inflicted on the self due to some actions or interactions.
235+ * @property distanceToTarget The distance to the target from the player or reference point.
236+ * @property color The dynamically calculated color based on the color mode and associated parameters.
237+ */
238+ abstract class Target {
239+ abstract val targetDamage: Double
240+ abstract val selfDamage: Double
241+ abstract val distanceToTarget: Double
242+
243+ val color: Color by lazy {
244+ when (crystalColor) {
245+ ColorMode .TargetDamage -> {
246+ val targetHealth = target?.health?.toDouble() ? : 0.0
247+ val damage = targetDamage.coerceAtMost(targetHealth)
248+ val red = transform(damage, 0.0 , targetHealth, 0.0 , 255.0 ).toInt()
249+ Color (red, 255 - red, 0 , crystalAlpha)
250+ }
251+ ColorMode .SelfDamage -> {
252+ runSafe {
253+ val selfHealth = player.health.toDouble()
254+ val damage = selfDamage.coerceAtMost(selfHealth)
255+ val red = transform(damage, 0.0 , selfHealth, 0.0 , 255.0 ).toInt()
256+ Color (red, 255 - red, 0 , crystalAlpha)
257+ } ? : Color .WHITE
258+ }
259+ ColorMode .Distance -> {
260+ val distance = distanceToTarget.coerceAtMost(explodeRange)
261+ val red = transform(distance, 0.0 , explodeRange, 0.0 , 255.0 ).toInt()
262+ Color (red, 0 , 255 - red, crystalAlpha)
263+ }
264+ }
265+ }
266+ }
180267
181268 /* *
182269 * Damage sorter parameter
@@ -185,37 +272,31 @@ object CrystalAura : Module(
185272 * balanced -> sort by the highest ratio of enemy damage to self-damage
186273 * safe -> always prioritize the least amount of self-damage
187274 */
188- private enum class DamageSort (val comparator : Comparator <TargetPosition >) {
189- Deadly (compareByDescending<TargetPosition > { it.targetDamage }.thenBy { it.selfDamage }),
190- Balanced (compareByDescending<TargetPosition > { it.targetDamage / it.selfDamage }.thenBy { it.selfDamage }),
191- Safe (compareBy<TargetPosition > { it.selfDamage }.thenByDescending { it.targetDamage });
275+ private enum class DamageSort (val comparator : Comparator <PlacementTarget >) {
276+ Deadly (compareByDescending<PlacementTarget > { it.targetDamage }.thenBy { it.selfDamage }),
277+ Balanced (compareByDescending<PlacementTarget > { it.targetDamage / it.selfDamage }.thenBy { it.selfDamage }),
278+ Safe (compareBy<PlacementTarget > { it.selfDamage }.thenByDescending { it.targetDamage });
279+ }
280+
281+ private enum class Strategy {
282+ ExplodeBeforePlace ,
283+ PlaceBeforeExplode ,
192284 }
193285
194286 /* *
195- * Comparator for different render modes
287+ * Represents the different modes of color categorization or operations.
196288 *
197- * @param compared Lambda that takes in a living target and crystal position and then returns a color
289+ * Enum values:
290+ * - TargetDamage: Indicates color mode based on damage to a target.
291+ * - SelfDamage: Indicates color mode based on damage to oneself.
292+ * - Distance: Indicates color mode based on distance criteria.
198293 */
199- private enum class ColorComparator (val compared : SafeContext .(LivingEntity , Vec3d ) -> Color ) {
200- Distance ({ target, dest ->
201- val red = transform(target dist dest, 0.0 , explodeRange, 255.0 , 0.0 ).toInt()
202- Color (red, 255 - red, 0 , crystalAlpha)
203- }),
204- Damage ({ target, dest ->
205- val damage = explosionDamage(dest, target, 6.0 )
206- .coerceIn(0.0 , target.health.toDouble())
207-
208- val red = transform(damage, 0.0 , target.health.toDouble(), 0.0 , 255.0 ).toInt()
209- Color (red, 255 - red, 0 , crystalAlpha)
210- })
294+ private enum class ColorMode {
295+ TargetDamage ,
296+ SelfDamage ,
297+ Distance
211298 }
212299
213- private enum class Page {
214- Targeting ,
215- Placing ,
216- Exploding ,
217- Rotation ,
218- Interaction ,
219- Rendering
220- }
300+ private fun SafeContext.crystalDamage (vec3d : Vec3d , target : LivingEntity ) =
301+ explosionDamage(vec3d, target, 6.0 )
221302}
0 commit comments