Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
354 changes: 193 additions & 161 deletions src/main/kotlin/com/lambda/config/groups/Targeting.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ import com.lambda.util.NamedEnum
import com.lambda.util.extension.fullHealth
import com.lambda.util.math.distSq
import com.lambda.util.world.fastEntitySearch
import com.lambda.world.LambdaAngerManagement
import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.client.network.OtherClientPlayerEntity
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.decoration.ArmorStandEntity
import net.minecraft.entity.mob.AmbientEntity
import net.minecraft.entity.mob.Angerable
import net.minecraft.entity.mob.HostileEntity
import net.minecraft.entity.passive.AnimalEntity
import net.minecraft.entity.passive.PassiveEntity
import java.util.*

Expand All @@ -50,166 +54,194 @@ import java.util.*
* @param maxRange The maximum range within which entities can be targeted.
*/
abstract class Targeting(
private val c: Configurable,
baseGroup: NamedEnum,
private val defaultRange: Double,
private val maxRange: Double,
private val c: Configurable,
baseGroup: NamedEnum,
private val defaultRange: Double,
private val maxRange: Double,
) : SettingGroup(c), TargetingConfig {
/**
* The range within which entities can be targeted. This value is configurable and constrained
* between 1.0 and [maxRange].
*/
override val targetingRange by c.setting("Targeting Range", defaultRange, 1.0..maxRange, 0.05).group(baseGroup)

/**
* Whether players are included in the targeting scope.
*/
override val players by c.setting("Players", true).group(baseGroup)

/**
* Whether friends are included in the targeting scope.
* Requires [players] to be true.
*/
override val friends by c.setting("Friends", false) { players }.group(baseGroup)

/**
* Whether mobs are included in the targeting scope.
*/
private val mobs by c.setting("Mobs", true).group(baseGroup)

/**
* Whether hostile mobs are included in the targeting scope
*/
private val hostilesSetting by c.setting("Hostiles", true) { mobs }.group(baseGroup)

/**
* Whether passive animals are included in the targeting scope
*/
private val animalsSetting by c.setting("Animals", true) { mobs }.group(baseGroup)

/**
* Indicates whether hostile entities are included in the targeting scope.
*/
override val hostiles get() = mobs && hostilesSetting

/**
* Indicates whether passive animals are included in the targeting scope.
*/
override val animals get() = mobs && animalsSetting

/**
* Whether invisible entities are included in the targeting scope.
*/
override val invisible by c.setting("Invisible", true).group(baseGroup)

/**
* Whether dead entities are included in the targeting scope.
*/
override val dead by c.setting("Dead", false).group(baseGroup)

/**
* Validates whether a given entity is targetable by the player based on current settings.
*
* @param player The [ClientPlayerEntity] performing the targeting.
* @param entity The [LivingEntity] being evaluated.
* @return `true` if the entity is valid for targeting, `false` otherwise.
*/
open fun validate(player: ClientPlayerEntity, entity: LivingEntity) = when {
!players && entity is OtherClientPlayerEntity -> false
players && entity is OtherClientPlayerEntity && entity.isFriend -> false
!animals && entity is PassiveEntity -> false
!hostiles && entity is HostileEntity -> false
entity is ArmorStandEntity -> false

!invisible && entity.isInvisibleTo(player) -> false
!dead && entity.isDead -> false

else -> true
}

/**
* Subclass for targeting entities specifically for combat purposes.
*
* @property fov The field of view limit within which entities are considered for targeting. Configurable.
* @property priority The priority used to determine which entity is targeted when multiple candidates are available.
*/
class Combat(
c: Configurable,
baseGroup: NamedEnum,
defaultRange: Double = 5.0,
maxRange: Double = 16.0,
) : Targeting(c, baseGroup, defaultRange, maxRange) {

/**
* The field of view limit for targeting entities. Configurable between 5 and 180 degrees.
*/
val fov by c.setting("FOV Limit", 180, 5..180, 1) { priority == Priority.Fov }.group(baseGroup)

/**
* The priority used to determine which entity is targeted. Configurable with default set to [Priority.Distance].
*/
val priority by c.setting("Priority", Priority.Distance).group(baseGroup)

/**
* Validates whether a given entity is targetable for combat based on the field of view limit and other settings.
*
* @param player The [ClientPlayerEntity] performing the targeting.
* @param entity The [LivingEntity] being evaluated.
* @return `true` if the entity is valid for targeting, `false` otherwise.
*/
override fun validate(player: ClientPlayerEntity, entity: LivingEntity): Boolean {
if (fov < 180 && player.rotation dist player.eyePos.rotationTo(entity.pos) > fov) return false
if (entity.uuid in illegalTargets) return false
return super.validate(player, entity)
}

/**
* Gets the best target for combat based on the current settings and priority.
*
* @return The best [LivingEntity] target, or `null` if no valid target is found.
*/
fun target(): LivingEntity? = runSafe {
return@runSafe fastEntitySearch<LivingEntity>(targetingRange) {
validate(player, it)
}.minByOrNull {
priority.factor(this, it)
}
}

private val illegalTargets = setOf(
UUID(5706954458220675710, -6736729783554821869),
UUID(-2945922493004570036, -7599209072395336449)
)
}

/**
* Subclass for targeting entities for ESP (Extrasensory Perception) purposes.
*/
class ESP(
c: Configurable,
baseGroup: NamedEnum,
) : Targeting(c, baseGroup, 128.0, 1024.0)

/**
* Enum representing the different priority factors used for determining the best target.
*
* @property factor A lambda function that calculates the priority factor for a given [LivingEntity].
*/
@Suppress("Unused")
enum class Priority(val factor: SafeContext.(LivingEntity) -> Double) {
/**
* Prioritizes entities based on their distance from the player.
*/
Distance({ player.pos distSq it.pos }),

/**
* Prioritizes entities based on their health.
*/
Health({ it.fullHealth }),

/**
* Prioritizes entities based on their angle relative to the player's field of view.
*/
Fov({ player.rotation dist player.eyePos.rotationTo(it.pos) })
}
/**
* The range within which entities can be targeted. This value is configurable and constrained
* between 1.0 and [maxRange].
*/
override val targetingRange by c.setting("Targeting Range", defaultRange, 1.0..maxRange, 0.05).group(baseGroup)

/**
* Whether players are included in the targeting scope.
*/
override val players by c.setting("Players", true).group(baseGroup)

/**
* Whether friends are included in the targeting scope.
* Requires [players] to be true.
*/
override val friends by c.setting("Friends", false) { players }.group(baseGroup)

/**
* Whether mobs are included in the targeting scope.
*/
private val mobs by c.setting("Mobs", true).group(baseGroup)

/**
* Whether hostile mobs are included in the targeting scope
*/
private val hostilesSetting by c.setting("Hostiles", true) { mobs }.group(baseGroup)

/**
* Whether hostile entities should be only attacked when they are angry
*/
private val hostileOnlyAngrySetting by c.setting(
"Hostiles Only Angry", true,
"Only attacks angerable entities if they are angered. This does not affect for example zombies but does affect endermen."
) { hostilesSetting }.group(baseGroup)

/**
* Whether passive entities are included in the targeting scope
*/
private val passivesSetting by c.setting("Passives", false) { mobs }.group(baseGroup)

/**
* Whether animals are included in the targeting scope
*/
private val animalsSetting by c.setting("Animals", true) { mobs }.group(baseGroup)

/**
* Indicates whether hostile entities are included in the targeting scope.
*/
override val hostiles get() = mobs && hostilesSetting

override val hostilesOnlyAngry: Boolean
get() = mobs && hostilesSetting && hostileOnlyAngrySetting

/**
* Indicates whether passive entities are included in the targeting scope.
*/
override val passives get() = mobs && passivesSetting

/**
* Indicates whether animals are included in the targeting scope.
*/
override val animals get() = mobs && animalsSetting

/**
* Whether invisible entities are included in the targeting scope.
*/
override val invisible by c.setting("Invisible", true).group(baseGroup)

/**
* Whether dead entities are included in the targeting scope.
*/
override val dead by c.setting("Dead", false).group(baseGroup)

/**
* Validates whether a given entity is targetable by the player based on current settings.
*
* @param player The [ClientPlayerEntity] performing the targeting.
* @param entity The [LivingEntity] being evaluated.
* @return `true` if the entity is valid for targeting, `false` otherwise.
*/
open fun validate(player: ClientPlayerEntity, entity: LivingEntity) = when {
players && entity is OtherClientPlayerEntity -> true
!players && entity is OtherClientPlayerEntity && entity.isFriend -> true
animals && (entity is AnimalEntity || entity is AmbientEntity) -> true
passives && entity is PassiveEntity -> true
hostiles && entity is HostileEntity -> {
if (hostilesOnlyAngry && entity is Angerable) {
LambdaAngerManagement.isEntityAngry(entity.uuid)
} else {
true
}
}
entity is ArmorStandEntity -> false

invisible && entity.isInvisibleTo(player) -> true
dead && entity.isDead -> true

else -> false
}

/**
* Subclass for targeting entities specifically for combat purposes.
*
* @property fov The field of view limit within which entities are considered for targeting. Configurable.
* @property priority The priority used to determine which entity is targeted when multiple candidates are available.
*/
class Combat(
c: Configurable,
baseGroup: NamedEnum,
defaultRange: Double = 5.0,
maxRange: Double = 16.0,
) : Targeting(c, baseGroup, defaultRange, maxRange) {

/**
* The field of view limit for targeting entities. Configurable between 5 and 180 degrees.
*/
val fov by c.setting("FOV Limit", 180, 5..180, 1) { priority == Priority.Fov }.group(baseGroup)

/**
* The priority used to determine which entity is targeted. Configurable with default set to [Priority.Distance].
*/
val priority by c.setting("Priority", Priority.Distance).group(baseGroup)

/**
* Validates whether a given entity is targetable for combat based on the field of view limit and other settings.
*
* @param player The [ClientPlayerEntity] performing the targeting.
* @param entity The [LivingEntity] being evaluated.
* @return `true` if the entity is valid for targeting, `false` otherwise.
*/
override fun validate(player: ClientPlayerEntity, entity: LivingEntity): Boolean {
if (fov < 180 && player.rotation dist player.eyePos.rotationTo(entity.pos) > fov) return false
if (entity.uuid in illegalTargets) return false
return super.validate(player, entity)
}

/**
* Gets the best target for combat based on the current settings and priority.
*
* @return The best [LivingEntity] target, or `null` if no valid target is found.
*/
fun target(): LivingEntity? = runSafe {
return@runSafe fastEntitySearch<LivingEntity>(targetingRange) {
validate(player, it)
}.minByOrNull {
priority.factor(this, it)
}
}

private val illegalTargets = setOf(
UUID(5706954458220675710, -6736729783554821869),
UUID(-2945922493004570036, -7599209072395336449)
)
}

/**
* Subclass for targeting entities for ESP (Extrasensory Perception) purposes.
*/
class ESP(
c: Configurable,
baseGroup: NamedEnum,
) : Targeting(c, baseGroup, 128.0, 1024.0)

/**
* Enum representing the different priority factors used for determining the best target.
*
* @property factor A lambda function that calculates the priority factor for a given [LivingEntity].
*/
@Suppress("Unused")
enum class Priority(val factor: SafeContext.(LivingEntity) -> Double) {
/**
* Prioritizes entities based on their distance from the player.
*/
Distance({ player.pos distSq it.pos }),

/**
* Prioritizes entities based on their health.
*/
Health({ it.fullHealth }),

/**
* Prioritizes entities based on their angle relative to the player's field of view.
*/
Fov({ player.rotation dist player.eyePos.rotationTo(it.pos) })
}
}
2 changes: 2 additions & 0 deletions src/main/kotlin/com/lambda/config/groups/TargetingConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ interface TargetingConfig {
val players: Boolean
val friends: Boolean
val hostiles: Boolean
val hostilesOnlyAngry: Boolean
val passives: Boolean
val animals: Boolean

val invisible: Boolean
Expand Down
Loading
Loading