diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/CrystalAuraDamageOptions.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/CrystalAuraDamageOptions.kt index f9176123b77..7940919882c 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/CrystalAuraDamageOptions.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/CrystalAuraDamageOptions.kt @@ -18,6 +18,8 @@ */ package net.ccbluex.liquidbounce.features.module.modules.combat.crystalaura +import it.unimi.dsi.fastutil.floats.FloatFloatImmutablePair +import it.unimi.dsi.fastutil.floats.FloatFloatPair import net.ccbluex.liquidbounce.config.types.Configurable import net.ccbluex.liquidbounce.features.misc.FriendManager import net.ccbluex.liquidbounce.features.module.modules.combat.crystalaura.ModuleCrystalAura.currentTarget @@ -56,9 +58,11 @@ object CrystalAuraDamageOptions : Configurable("Damage") { val cacheMap = LruCache(64) /** - * Approximates how favorable an explosion of a crystal at [pos] in a given [world] would be - */ // TODO by equal positions take self min damage - internal fun approximateExplosionDamage(pos: Vec3d, requestingSubmodule: RequestingSubmodule): Float? { + * Approximates how favorable an explosion of a crystal at [pos] in a given [world] would be. + * + * The first float is the self-damage, the second is the enemy damage. + */ + internal fun approximateExplosionDamage(pos: Vec3d, requestingSubmodule: RequestingSubmodule): FloatFloatPair? { val target = currentTarget ?: return null val damageToTarget = target.getDamage(pos, requestingSubmodule, CheckedEntity.TARGET) val notEnoughDamage = damageToTarget.isSmallerThan(minEnemyDamage) @@ -92,7 +96,7 @@ object CrystalAuraDamageOptions : Configurable("Damage") { return null } - return damageToTarget.getFixed() + return FloatFloatImmutablePair(selfDamage.getFixed(), damageToTarget.getFixed()) } private fun LivingEntity.getDamage( diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/destroy/CrystalAuraDestroyTargetFactory.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/destroy/CrystalAuraDestroyTargetFactory.kt index 91e400ed412..6e8d4693540 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/destroy/CrystalAuraDestroyTargetFactory.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/destroy/CrystalAuraDestroyTargetFactory.kt @@ -18,7 +18,6 @@ */ package net.ccbluex.liquidbounce.features.module.modules.combat.crystalaura.destroy -import it.unimi.dsi.fastutil.objects.ObjectFloatImmutablePair import net.ccbluex.liquidbounce.features.module.MinecraftShortcuts import net.ccbluex.liquidbounce.features.module.modules.combat.crystalaura.CrystalAuraDamageOptions import net.ccbluex.liquidbounce.features.module.modules.combat.crystalaura.destroy.SubmoduleCrystalDestroyer.getMaxRange @@ -50,8 +49,8 @@ object CrystalAuraDestroyTargetFactory : MinecraftShortcuts { val damage = dealsEnoughDamage(it) ?: return@mapNotNull null - ObjectFloatImmutablePair(it as EndCrystalEntity, damage) - }.maxByOrNull { it.secondFloat() }?.first() + ComparisonListEntry(it as EndCrystalEntity, damage.firstFloat(), damage.secondFloat()) + }.maxOrNull()?.crystalEntity } /** @@ -88,4 +87,25 @@ object CrystalAuraDestroyTargetFactory : MinecraftShortcuts { wallsRange = wallsRange.toDouble() ) + private class ComparisonListEntry( + val crystalEntity: EndCrystalEntity, + val selfDamage: Float, + val enemyDamage: Float + ) : Comparable { + + override fun compareTo(other: ComparisonListEntry): Int { + // coarse sorting + val enemyDamageComparison = this.enemyDamage.compareTo(other.enemyDamage) + + // not equal + if (enemyDamageComparison != 0) { + return enemyDamageComparison + } + + // equal -> fine sorting + return other.selfDamage.compareTo(this.selfDamage) + } + + } + } diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/place/CrystalAuraPlaceTargetFactory.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/place/CrystalAuraPlaceTargetFactory.kt index c54c3f2c8ae..5d161e2cbe7 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/place/CrystalAuraPlaceTargetFactory.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/place/CrystalAuraPlaceTargetFactory.kt @@ -126,12 +126,12 @@ object CrystalAuraPlaceTargetFactory : MinecraftShortcuts { currentBasePlaceTarget: PlacementPositionCandidate? ): PlacementPositionCandidate? { // choose the target with the maximum damage - var bestTarget = finalPositions.maxByOrNull { it.explosionDamage!! } ?: return null + var bestTarget = finalPositions.maxOrNull() ?: return null // find a target position that will not require base place if possible if (bestTarget.requiresBasePlace) { - finalPositions.filterNot { it.requiresBasePlace }.maxByOrNull { it.explosionDamage!! }?.let { - if (it.explosionDamage!! - bestTarget.explosionDamage!! >= SubmoduleBasePlace.minAdvantage) { + finalPositions.filterNot { it.requiresBasePlace }.maxOrNull()?.let { + if (it.enemyDamage!! - bestTarget.enemyDamage!! >= SubmoduleBasePlace.minAdvantage) { bestTarget = it } } @@ -141,7 +141,7 @@ object CrystalAuraPlaceTargetFactory : MinecraftShortcuts { currentBasePlaceTarget?.let { it.calculate() if (it.isNotInvalid() && - it.explosionDamage!! - bestTarget.explosionDamage!! >= SubmoduleBasePlace.minAdvantage + it.enemyDamage!! - bestTarget.enemyDamage!! >= SubmoduleBasePlace.minAdvantage ) { bestTarget = it } diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/place/PlacementPositionCandidate.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/place/PlacementPositionCandidate.kt index a0dc371f6a1..07b6b2959cb 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/place/PlacementPositionCandidate.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/crystalaura/place/PlacementPositionCandidate.kt @@ -19,6 +19,7 @@ package net.ccbluex.liquidbounce.features.module.modules.combat.crystalaura.place import net.ccbluex.liquidbounce.features.module.modules.combat.crystalaura.CrystalAuraDamageOptions +import net.ccbluex.liquidbounce.utils.client.player import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Vec3d @@ -26,12 +27,22 @@ class PlacementPositionCandidate( val pos: BlockPos, // the block the crystal should be placed on val notBlockedByCrystal: Boolean, val requiresBasePlace: Boolean -) { +) : Comparable { /** - * The damage a crystal at the specific position would deal. + * The damage a crystal at the specific position would deal to the enemy. */ - var explosionDamage: Float? = null + var enemyDamage: Float? = null + + /** + * The damage a crystal at the specific position would deal to the enemy. + */ + private var selfDamage: Float? = null + + /** + * The distance to us. + */ + private val distanceSq by lazy { pos.getSquaredDistance(player.pos) } init { calculate() @@ -42,7 +53,7 @@ class PlacementPositionCandidate( */ fun calculate() { val damageSourceLoc = Vec3d.of(pos).add(0.5, 1.0, 0.5) - explosionDamage = CrystalAuraDamageOptions.approximateExplosionDamage( + val explosionDamage = CrystalAuraDamageOptions.approximateExplosionDamage( damageSourceLoc, if (requiresBasePlace) { CrystalAuraDamageOptions.RequestingSubmodule.BASE_PLACE @@ -50,9 +61,38 @@ class PlacementPositionCandidate( CrystalAuraDamageOptions.RequestingSubmodule.PLACE } ) + + explosionDamage?.let { + selfDamage = it.firstFloat() + enemyDamage = it.secondFloat() + } ?: run { + selfDamage = null + enemyDamage = null + } } - fun isNotInvalid() = explosionDamage != null + fun isNotInvalid() = enemyDamage != null + + override fun compareTo(other: PlacementPositionCandidate): Int { + // coarse sorting + val enemyDamageComparison = this.enemyDamage!!.compareTo(other.enemyDamage!!) + + // not equal + if (enemyDamageComparison != 0) { + return enemyDamageComparison + } + + // equal -> fine sorting 1 + val selfDamageComparison = other.selfDamage!!.compareTo(this.selfDamage!!) + + // not equal + if (selfDamageComparison != 0) { + return selfDamageComparison + } + + // equal -> fine sorting 2 + return other.distanceSq.compareTo(this.distanceSq) + } override fun equals(other: Any?): Boolean { if (this === other) return true