@@ -38,7 +38,7 @@ import com.lambda.module.tag.ModuleTag
3838import com.lambda.threading.runSafe
3939import com.lambda.threading.runSafeGameScheduled
4040import com.lambda.util.BlockUtils.blockState
41- import com.lambda.util.SimpleTimer
41+ import com.lambda.util.Timer
4242import com.lambda.util.combat.CombatUtils.crystalDamage
4343import com.lambda.util.math.*
4444import com.lambda.util.math.MathUtils.ceilToInt
@@ -55,6 +55,8 @@ import net.minecraft.util.hit.BlockHitResult
5555import net.minecraft.util.math.*
5656import kotlin.concurrent.fixedRateTimer
5757import kotlin.math.max
58+ import kotlin.time.DurationUnit
59+ import kotlin.time.toDuration
5860
5961object CrystalAura : Module(
6062 name = " CrystalAura" ,
@@ -69,7 +71,7 @@ object CrystalAura : Module(
6971 private val placeDelay by setting(" Place Delay" , 50L , 0L .. 1000L , 5L , " Delay between placement attempts" , " ms" ) { page == Page .General }
7072 private val explodeDelay by setting(" Explode Delay" , 10L , 0L .. 1000L , 5L , " Delay between explosion attempts" , " ms" ) { page == Page .General }
7173 private val updateMode by setting(" Update Mode" , UpdateMode .Async ) { page == Page .General }
72- private val updateDelaySetting by setting(" Update Delay" , 25L , 5L .. 200L , 5L ) { page == Page .General && updateMode == UpdateMode .Async }
74+ private val updateDelaySetting by setting(" Update Delay" , 25L , 5L .. 200L , 5L , unit = " ms " ) { page == Page .General && updateMode == UpdateMode .Async }
7375 private val maxUpdatesPerFrame by setting(" Max Updates Per Frame" , 5 , 1 .. 20 , 1 ) { page == Page .General && updateMode == UpdateMode .Async }
7476 private val updateDelay get() = if (updateMode == UpdateMode .Async ) updateDelaySetting else 0L
7577 private val debug by setting(" Debug" , false ) { page == Page .General }
@@ -102,13 +104,13 @@ object CrystalAura : Module(
102104 private val actionMap = mutableMapOf<ActionType , MutableList <Opportunity >>()
103105 private var actionType = ActionType .Normal
104106
105- private val updateTimer = SimpleTimer ()
107+ private val updateTimer = Timer ()
106108 private var updatesThisFrame = 0
107109
108- private val placeTimer = SimpleTimer ()
109- private val explodeTimer = SimpleTimer ()
110+ private val placeTimer = Timer ()
111+ private val explodeTimer = Timer ()
110112
111- private val predictionTimer = SimpleTimer ()
113+ private val predictionTimer = Timer ()
112114 private var lastEntityId = 0
113115
114116 private val collidingOffsets = mutableListOf<BlockPos >().apply {
@@ -284,119 +286,120 @@ object CrystalAura : Module(
284286 player.swingHand(Hand .MAIN_HAND )
285287 }
286288
287- private fun SafeContext.updateBlueprint (target : LivingEntity ) = updateTimer.runIfPassed(updateDelay) {
288- resetBlueprint()
289-
290- // Build damage info
291- fun info (
292- pos : BlockPos , target : LivingEntity ,
293- blocked : Boolean ,
294- crystal : EndCrystalEntity ? = null
295- ): Opportunity ? {
296- val crystalPos = pos.crystalPosition
297-
298- // Calculate the damage to the target from the explosion of the crystal
299- val targetDamage = crystalDamage(crystalPos, target)
300- if (targetDamage < minTargetDamage) return null
301-
302- // Calculate the self-damage for the player
303- val selfDamage = crystalDamage(crystalPos, player)
304- if (selfDamage > maxSelfDamage) return null
305-
306- if (priorityMode == Priority .Advantage && priorityMode.factor(targetDamage, selfDamage) < minDamageAdvantage) return null
307-
308- // Return the calculated damage info if conditions are met
309- return Opportunity (
310- pos.toImmutable(),
311- targetDamage,
312- selfDamage,
313- blocked,
314- crystal
315- )
316- }
289+ private fun SafeContext.updateBlueprint (target : LivingEntity ) =
290+ updateTimer.runIfPassed(updateDelay.toDuration(DurationUnit .MILLISECONDS )) {
291+ resetBlueprint()
317292
318- // Extra checks for placement, because you may explode but not place in special cases(crystal in the air)
319- @Suppress(" ConvertArgumentToSet" )
320- fun placeInfo (
321- pos : BlockPos ,
322- target : LivingEntity
323- ): Opportunity ? {
324- // Check if crystals could be placed on the base block
325- val state = pos.blockState(world)
326- val isOfBlock = state.isOf(Blocks .OBSIDIAN ) || state.isOf(Blocks .BEDROCK )
327- if (! isOfBlock) return null
328-
329- // Check if the block above is air and other conditions for valid crystal placement
330- val above = pos.up()
331- if (! world.isAir(above)) return null
332- if (oldPlace && ! world.isAir(above.up())) return null
333-
334- // Exclude blocks blocked by entities
335- val crystalBox = pos.crystalBox
336-
337- val entitiesNearby = fastEntitySearch<Entity >(3.5 , pos)
338- val crystals = entitiesNearby.filterIsInstance<EndCrystalEntity >() as MutableList
339- val otherEntities = entitiesNearby - crystals + player
340-
341- if (otherEntities.any {
342- it.boundingBox.intersects(crystalBox)
343- }) return null
344-
345- // Placement collision checks
346- val baseCrystal = crystals.firstOrNull {
347- it.baseBlockPos == pos
293+ // Build damage info
294+ fun info (
295+ pos : BlockPos , target : LivingEntity ,
296+ blocked : Boolean ,
297+ crystal : EndCrystalEntity ? = null
298+ ): Opportunity ? {
299+ val crystalPos = pos.crystalPosition
300+
301+ // Calculate the damage to the target from the explosion of the crystal
302+ val targetDamage = crystalDamage(crystalPos, target)
303+ if (targetDamage < minTargetDamage) return null
304+
305+ // Calculate the self-damage for the player
306+ val selfDamage = crystalDamage(crystalPos, player)
307+ if (selfDamage > maxSelfDamage) return null
308+
309+ if (priorityMode == Priority .Advantage && priorityMode.factor(targetDamage, selfDamage) < minDamageAdvantage) return null
310+
311+ // Return the calculated damage info if conditions are met
312+ return Opportunity (
313+ pos.toImmutable(),
314+ targetDamage,
315+ selfDamage,
316+ blocked,
317+ crystal
318+ )
348319 }
349320
350- val crystalPlaceBox = pos.crystalPlaceHitBox
351- val blocked = baseCrystal == null && crystals.any {
352- it.boundingBox.intersects(crystalPlaceBox)
353- }
321+ // Extra checks for placement, because you may explode but not place in special cases(crystal in the air)
322+ @Suppress(" ConvertArgumentToSet" )
323+ fun placeInfo (
324+ pos : BlockPos ,
325+ target : LivingEntity
326+ ): Opportunity ? {
327+ // Check if crystals could be placed on the base block
328+ val state = pos.blockState(world)
329+ val isOfBlock = state.isOf(Blocks .OBSIDIAN ) || state.isOf(Blocks .BEDROCK )
330+ if (! isOfBlock) return null
331+
332+ // Check if the block above is air and other conditions for valid crystal placement
333+ val above = pos.up()
334+ if (! world.isAir(above)) return null
335+ if (oldPlace && ! world.isAir(above.up())) return null
336+
337+ // Exclude blocks blocked by entities
338+ val crystalBox = pos.crystalBox
339+
340+ val entitiesNearby = fastEntitySearch<Entity >(3.5 , pos)
341+ val crystals = entitiesNearby.filterIsInstance<EndCrystalEntity >() as MutableList
342+ val otherEntities = entitiesNearby - crystals + player
343+
344+ if (otherEntities.any {
345+ it.boundingBox.intersects(crystalBox)
346+ }) return null
347+
348+ // Placement collision checks
349+ val baseCrystal = crystals.firstOrNull {
350+ it.baseBlockPos == pos
351+ }
354352
355- return info(
356- pos,
357- target,
358- blocked,
359- baseCrystal
360- )
361- }
353+ val crystalPlaceBox = pos.crystalPlaceHitBox
354+ val blocked = baseCrystal == null && crystals.any {
355+ it.boundingBox.intersects(crystalPlaceBox)
356+ }
362357
363- val range = max(placeRange, explodeRange) + 1
364- val rangeInt = range.ceilToInt()
358+ return info(
359+ pos,
360+ target,
361+ blocked,
362+ baseCrystal
363+ )
364+ }
365365
366- // Iterate through existing crystals
367- val crystalBase = BlockPos .Mutable ()
368- fastEntitySearch<EndCrystalEntity >(range).forEach { crystal ->
369- crystalBase.set(crystal.x, crystal.y - 0.5 , crystal.z)
370- damage + = info(crystalBase, target, false , crystal) ? : return @forEach
371- }
366+ val range = max(placeRange, explodeRange) + 1
367+ val rangeInt = range.ceilToInt()
372368
373- // Iterate through possible place positions and calculate damage information for each
374- BlockPos .iterateOutwards(player.blockPos.up(), rangeInt, rangeInt, rangeInt).forEach { pos ->
375- if (pos distSq player.pos > range * range) return @forEach
376- if (damage.any { info -> info.blockPos == pos }) return @forEach
369+ // Iterate through existing crystals
370+ val crystalBase = BlockPos .Mutable ()
371+ fastEntitySearch<EndCrystalEntity >(range).forEach { crystal ->
372+ crystalBase.set(crystal.x, crystal.y - 0.5 , crystal.z)
373+ damage + = info(crystalBase, target, false , crystal) ? : return @forEach
374+ }
377375
378- damage + = placeInfo(pos, target) ? : return @forEach
379- }
376+ // Iterate through possible place positions and calculate damage information for each
377+ BlockPos .iterateOutwards(player.blockPos.up(), rangeInt, rangeInt, rangeInt).forEach { pos ->
378+ if (pos distSq player.pos > range * range) return @forEach
379+ if (damage.any { info -> info.blockPos == pos }) return @forEach
380380
381- // Map opportunities
382- damage.forEach {
383- blueprint[it.blockPos] = it
384- }
381+ damage + = placeInfo(pos, target) ? : return @forEach
382+ }
383+
384+ // Map opportunities
385+ damage.forEach {
386+ blueprint[it.blockPos] = it
387+ }
385388
386- // Associate by actions
387- blueprint.values.forEach { opportunity ->
388- actionMap.getOrPut(opportunity.actionType, ::mutableListOf) + = opportunity
389+ // Associate by actions
390+ blueprint.values.forEach { opportunity ->
391+ actionMap.getOrPut(opportunity.actionType, ::mutableListOf) + = opportunity
389392
390- if (opportunity.actionType.priority > actionType.priority) {
391- actionType = opportunity.actionType
393+ if (opportunity.actionType.priority > actionType.priority) {
394+ actionType = opportunity.actionType
395+ }
392396 }
393- }
394397
395- // Select best action
396- activeOpportunity = actionMap[actionType]?.maxByOrNull {
397- it.priority
398+ // Select best action
399+ activeOpportunity = actionMap[actionType]?.maxByOrNull {
400+ it.priority
401+ }
398402 }
399- }
400403
401404 private fun resetBlueprint () {
402405 blueprint.clear()
@@ -430,10 +433,10 @@ object CrystalAura : Module(
430433 * Places the crystal on [blockPos]
431434 * @return Whether the delay passed, null if the interaction failed
432435 */
433- fun place () = placeTimer.runSafeIfPassed(placeDelay) {
436+ fun place () = placeTimer.runSafeIfPassed(placeDelay.toDuration( DurationUnit . MILLISECONDS ) ) {
434437 placeInternal(blockPos, Hand .MAIN_HAND )
435438
436- if (prediction.onPlace) predictionTimer.runIfNotPassed(packetLifetime, false ) {
439+ if (prediction.onPlace) predictionTimer.runIfNotPassed(packetLifetime.toDuration( DurationUnit . MILLISECONDS ) , false ) {
437440 val last = lastEntityId
438441
439442 repeat(placePredictions) {
@@ -451,12 +454,13 @@ object CrystalAura : Module(
451454 * Explodes a crystal that is on [blockPos]
452455 * @return Whether the delay passed, null if the interaction failed or no crystal found
453456 */
454- fun explode () = explodeTimer.runSafeIfPassed(explodeDelay) {
455- crystal?.let { crystal ->
456- explodeInternal(crystal.id)
457- explodeTimer.reset()
457+ fun explode () =
458+ explodeTimer.runSafeIfPassed(explodeDelay.toDuration(DurationUnit .MILLISECONDS )) {
459+ crystal?.let { crystal ->
460+ explodeInternal(crystal.id)
461+ explodeTimer.reset()
462+ }
458463 }
459- }
460464
461465 fun buildDebug () {
462466 withVertexTransform(buildWorldProjection(blockPos.crystalPosition, 0.4 , Matrices .ProjRotationMode .TO_CAMERA )) {
0 commit comments