Skip to content

Commit 0fbd682

Browse files
committed
Accurate Timer with duration type
1 parent bc19659 commit 0fbd682

File tree

2 files changed

+152
-150
lines changed

2 files changed

+152
-150
lines changed

common/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt

Lines changed: 116 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import com.lambda.module.tag.ModuleTag
3838
import com.lambda.threading.runSafe
3939
import com.lambda.threading.runSafeGameScheduled
4040
import com.lambda.util.BlockUtils.blockState
41-
import com.lambda.util.SimpleTimer
41+
import com.lambda.util.Timer
4242
import com.lambda.util.combat.CombatUtils.crystalDamage
4343
import com.lambda.util.math.*
4444
import com.lambda.util.math.MathUtils.ceilToInt
@@ -55,6 +55,8 @@ import net.minecraft.util.hit.BlockHitResult
5555
import net.minecraft.util.math.*
5656
import kotlin.concurrent.fixedRateTimer
5757
import kotlin.math.max
58+
import kotlin.time.DurationUnit
59+
import kotlin.time.toDuration
5860

5961
object 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

Comments
 (0)