Skip to content

Commit acd6b95

Browse files
emyfopsAvanatiker
andauthored
Fix: KillAura cooldown and swap (#141)
Co-authored-by: Constructor <fractalminds@protonmail.com>
1 parent 59b1071 commit acd6b95

File tree

5 files changed

+96
-108
lines changed

5 files changed

+96
-108
lines changed

src/main/kotlin/com/lambda/config/groups/Targeting.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,33 +60,33 @@ abstract class Targeting(
6060
* The range within which entities can be targeted. This value is configurable and constrained
6161
* between 1.0 and [maxRange].
6262
*/
63-
override val targetingRange by owner.setting("Targeting Range", defaultRange, 1.0..maxRange, 0.05) { predicate() }
63+
override val targetingRange by owner.setting("Targeting Range", defaultRange, 1.0..maxRange, 0.05) { predicate() }.group(baseGroup)
6464

6565
/**
6666
* Whether players are included in the targeting scope.
6767
*/
68-
override val players by owner.setting("Players", true) { predicate() }
68+
override val players by owner.setting("Players", true) { predicate() }.group(baseGroup)
6969

7070
/**
7171
* Whether friends are included in the targeting scope.
7272
* Requires [players] to be true.
7373
*/
74-
override val friends by owner.setting("Friends", false) { predicate() && players }
74+
override val friends by owner.setting("Friends", false) { predicate() && players }.group(baseGroup)
7575

7676
/**
7777
* Whether mobs are included in the targeting scope.
7878
*/
79-
private val mobs by owner.setting("Mobs", true) { predicate() }
79+
private val mobs by owner.setting("Mobs", true) { predicate() }.group(baseGroup)
8080

8181
/**
8282
* Whether hostile mobs are included in the targeting scope
8383
*/
84-
private val hostilesSetting by owner.setting("Hostiles", true) { predicate() && mobs }
84+
private val hostilesSetting by owner.setting("Hostiles", true) { predicate() && mobs }.group(baseGroup)
8585

8686
/**
8787
* Whether passive animals are included in the targeting scope
8888
*/
89-
private val animalsSetting by owner.setting("Animals", true) { predicate() && mobs }
89+
private val animalsSetting by owner.setting("Animals", true) { predicate() && mobs }.group(baseGroup)
9090

9191
/**
9292
* Indicates whether hostile entities are included in the targeting scope.
@@ -101,12 +101,12 @@ abstract class Targeting(
101101
/**
102102
* Whether invisible entities are included in the targeting scope.
103103
*/
104-
override val invisible by owner.setting("Invisible", true) { predicate() }
104+
override val invisible by owner.setting("Invisible", true) { predicate() }.group(baseGroup)
105105

106106
/**
107107
* Whether dead entities are included in the targeting scope.
108108
*/
109-
override val dead by owner.setting("Dead", false) { predicate() }
109+
override val dead by owner.setting("Dead", false) { predicate() }.group(baseGroup)
110110

111111
/**
112112
* Validates whether a given entity is targetable by the player based on current settings.
@@ -144,7 +144,7 @@ abstract class Targeting(
144144
/**
145145
* The field of view limit for targeting entities. Configurable between 5 and 180 degrees.
146146
*/
147-
val fov by owner.setting("FOV Limit", 180, 5..180, 1) { predicate() }.group(baseGroup)
147+
val fov by owner.setting("FOV Limit", 180, 5..180, 1) { predicate() && priority == Priority.FOV }.group(baseGroup)
148148

149149
/**
150150
* The priority used to determine which entity is targeted. Configurable with default set to [Priority.DISTANCE].

src/main/kotlin/com/lambda/interaction/material/StackSelection.kt

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ import kotlin.reflect.KClass
3333
* [StackSelection] is a class that holds a predicate for matching [ItemStack]s.
3434
*/
3535
class StackSelection {
36-
var selector: (ItemStack) -> Boolean = { true }
37-
var comparator: Comparator<ItemStack>? = null
36+
var selector: (ItemStack) -> Boolean = EVERYTHING
37+
var comparator: Comparator<ItemStack> = NO_COMPARE
3838
var count: Int = DEFAULT_AMOUNT
3939
var inShulkerBox: Boolean = false
4040

@@ -48,25 +48,54 @@ class StackSelection {
4848
val optimalStack: ItemStack?
4949
get() = itemStack ?: item?.let { ItemStack(it, count) }
5050

51+
/**
52+
* Filters the given [stacks], sorts them with the [comparator] and returns the first value
53+
*/
54+
fun bestItemMatch(stacks: List<ItemStack>): ItemStack? = stacks.minWithOrNull(comparator)
55+
5156
fun filterStack(stack: ItemStack) =
5257
if (inShulkerBox) stack.shulkerBoxContents.any { selector(it) }
5358
else selector(stack)
5459

55-
fun filterSlot(slot: Slot) = filterStack(slot.stack)
60+
fun filterSlot(slot: Slot): Boolean = filterStack(slot.stack)
5661

5762
fun filterStacks(stacks: List<ItemStack>): List<ItemStack> =
58-
stacks.filter(::filterStack).let { filteredStacks ->
59-
comparator?.run {
60-
filteredStacks.sortedWith(this)
61-
} ?: filteredStacks
62-
}
63+
stacks.filter(::filterStack).sortedWith(comparator)
6364

6465
fun filterSlots(slots: List<Slot>): List<Slot> =
65-
slots.filter(::filterSlot).let { filteredSlots ->
66-
comparator?.run {
67-
filteredSlots.sortedWith { slot, slot2 -> compare(slot.stack, slot2.stack) }
68-
} ?: filteredSlots
69-
}
66+
slots.filter(::filterSlot).sortedWith { slot, slot2 -> comparator.compare(slot.stack, slot2.stack) }
67+
68+
@StackSelectionDsl
69+
fun <R : Comparable<R>> sortBy(selector: (ItemStack) -> R?): StackSelection = apply {
70+
comparator = compareBy(selector)
71+
}
72+
73+
@StackSelectionDsl
74+
fun <R : Comparable<R>> sortByDescending(selector: (ItemStack) -> R?): StackSelection = apply {
75+
comparator = compareByDescending(selector)
76+
}
77+
78+
@StackSelectionDsl
79+
fun <R : Comparable<R>> thenBy(selector: (ItemStack) -> R?): StackSelection = apply {
80+
check(comparator != NO_COMPARE) { "No comparator specified" }
81+
comparator = comparator.thenBy(selector)
82+
}
83+
84+
@StackSelectionDsl
85+
fun <R : Comparable<R>> thenByDescending(selector: (ItemStack) -> R?): StackSelection = apply {
86+
check(comparator != NO_COMPARE) { "No comparator specified" }
87+
comparator = comparator.thenByDescending(selector)
88+
}
89+
90+
@StackSelectionDsl
91+
fun sortWith(custom: Comparator<ItemStack>): StackSelection = apply {
92+
comparator = custom
93+
}
94+
95+
@StackSelectionDsl
96+
fun reversed(): StackSelection = apply {
97+
comparator = comparator.reversed()
98+
}
7099

71100
/**
72101
* returns a function that finds a shulker box to push matching items into.
@@ -235,14 +264,12 @@ class StackSelection {
235264
annotation class StackSelectionDsl
236265

237266
const val DEFAULT_AMOUNT = 1
238-
val FULL_SHULKERS: (ItemStack) -> Boolean = { stack ->
239-
stack.shulkerBoxContents.none { it.isEmpty }
240-
}
241-
val EMPTY_SHULKERS: (ItemStack) -> Boolean = { stack ->
242-
stack.shulkerBoxContents.all { it.isEmpty }
243-
}
267+
268+
val FULL_SHULKERS: (ItemStack) -> Boolean = { stack -> stack.shulkerBoxContents.none { it.isEmpty } }
269+
val EMPTY_SHULKERS: (ItemStack) -> Boolean = { stack -> stack.shulkerBoxContents.all { it.isEmpty } }
244270
val EVERYTHING: (ItemStack) -> Boolean = { true }
245271
val NOTHING: (ItemStack) -> Boolean = { false }
272+
val NO_COMPARE: Comparator<ItemStack> = Comparator { _, _ -> 0 }
246273

247274
@StackSelectionDsl
248275
fun Item.select() = selectStack { isItem(this@select) }
@@ -261,29 +288,12 @@ class StackSelection {
261288
@StackSelectionDsl
262289
fun ((ItemStack) -> Boolean).select() = selectStack { this@select }
263290

264-
/**
265-
* Builds a [StackSelection] with the given parameters.
266-
* @param count The count of items to be selected.
267-
* @param block The predicate to be used to select the items.
268-
* @return A [StackSelection] with the given parameters.
269-
*/
270-
@StackSelectionDsl
271-
fun selectStack(
272-
count: Int = DEFAULT_AMOUNT,
273-
inShulkerBox: Boolean = false,
274-
block: StackSelection.() -> (ItemStack) -> Boolean,
275-
) = StackSelection().apply {
276-
selector = block()
277-
this.count = count
278-
this.inShulkerBox = inShulkerBox
279-
}
280-
281291
@StackSelectionDsl
282292
fun selectStack(
283293
count: Int = DEFAULT_AMOUNT,
284294
inShulkerBox: Boolean = false,
285-
sorter: Comparator<ItemStack>? = null,
286-
block: StackSelection.() -> (ItemStack) -> Boolean,
295+
sorter: Comparator<ItemStack> = NO_COMPARE,
296+
block: StackSelection.() -> (ItemStack) -> Boolean = { EVERYTHING },
287297
) = StackSelection().apply {
288298
selector = block()
289299
comparator = sorter

src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ import com.lambda.task.RootTask.run
3636
import com.lambda.util.NamedEnum
3737
import com.lambda.util.item.ItemStackUtils.attackDamage
3838
import com.lambda.util.item.ItemStackUtils.attackSpeed
39+
import com.lambda.util.item.ItemStackUtils.equal
3940
import com.lambda.util.math.random
41+
import com.lambda.util.player.SlotUtils.hotbarAndStorage
4042
import com.lambda.util.world.raycast.InteractionMask
4143
import com.lambda.util.world.raycast.RayCastUtils.entityResult
4244
import net.minecraft.entity.LivingEntity
45+
import net.minecraft.entity.attribute.EntityAttributes
4346
import net.minecraft.registry.tag.ItemTags
4447
import net.minecraft.util.Hand
4548
import net.minecraft.util.math.Vec3d
@@ -52,7 +55,7 @@ object KillAura : Module(
5255
// Interact
5356
private val interactionSettings = InteractionSettings(this, Group.Interaction, InteractionMask.Entity)
5457
private val interactSettings = InteractSettings(this, listOf(Group.Interact))
55-
private val swap by setting("Swap", true, "Swap to the item with the highest damage")
58+
private val swap by setting("Swap", true, "Swap to the item with the highest damage").group(Group.Interact)
5659
private val attackMode by setting("Attack Mode", AttackMode.Cooldown).group(Group.Interact)
5760
private val cooldownOffset by setting("Cooldown Offset", 0, -5..5, 1) { attackMode == AttackMode.Cooldown }.group(Group.Interact)
5861
private val hitDelay1 by setting("Hit Delay 1", 2.0, 0.0..20.0, 1.0) { attackMode == AttackMode.Delay }.group(Group.Interact)
@@ -101,20 +104,10 @@ object KillAura : Module(
101104
listen<TickEvent.Pre> {
102105
target?.let { entity ->
103106
if (swap) {
104-
val selection = selectStack(
105-
sorter = compareByDescending { attackDamage(stack = it) }
106-
) { isTag(ItemTags.SWORDS) }
107+
val selection = selectStack().sortByDescending { player.attackDamage(stack = it) }
107108

108-
109-
if (!selection.selector(player.mainHandStack)) {
110-
selection.transfer(MainHandContainer)
111-
?.finally {
112-
// Wait until the rotation has a hit result on the entity
113-
if (lookAtEntity(entity).requestBy(rotation).done) runAttack(entity)
114-
}?.run()
115-
116-
return@listen
117-
}
109+
if (!selection.bestItemMatch(player.hotbarAndStorage).equal(player.mainHandStack))
110+
selection.transfer(MainHandContainer)?.run()
118111
}
119112

120113
// Wait until the rotation has a hit result on the entity
@@ -129,18 +122,12 @@ object KillAura : Module(
129122
private fun SafeContext.runAttack(target: LivingEntity) {
130123
// Cooldown check
131124
when (attackMode) {
132-
AttackMode.Cooldown -> {
133-
if (player.lastAttackedTicks < 20 / player.attackSpeed() + cooldownOffset) return
134-
}
135-
136-
AttackMode.Delay -> {
137-
if (System.currentTimeMillis() - lastAttackTime < hitDelay) return
138-
}
125+
AttackMode.Cooldown -> if (player.lastAttackedTicks < 1 / player.attackSpeed() * 20 + cooldownOffset) return
126+
AttackMode.Delay -> if (System.currentTimeMillis() - lastAttackTime < hitDelay) return
139127
}
140128

141129
// Rotation check
142-
run {
143-
if (!rotate) return@run
130+
if (rotate) {
144131
val angle = RotationManager.activeRotation
145132

146133
if (interactionSettings.strictRayCast) {

src/main/kotlin/com/lambda/util/item/ItemStackUtils.kt

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,69 +17,59 @@
1717

1818
package com.lambda.util.item
1919

20-
import com.lambda.context.SafeContext
2120
import com.lambda.util.collections.Cacheable.Companion.cacheable
2221
import net.minecraft.component.DataComponentTypes
2322
import net.minecraft.component.type.AttributeModifiersComponent
23+
import net.minecraft.entity.EquipmentSlot
2424
import net.minecraft.entity.LivingEntity
25+
import net.minecraft.entity.attribute.EntityAttribute
26+
import net.minecraft.entity.attribute.EntityAttributeModifier
2527
import net.minecraft.entity.attribute.EntityAttributes
2628
import net.minecraft.item.ItemStack
29+
import net.minecraft.registry.entry.RegistryEntry
2730

2831
object ItemStackUtils {
2932
// FixMe: Change this fucking retarded stuff when mojang wake up from their coma and realize they fucked this shit up
3033
// - The client and the server entity attributes are not synced,
3134
// - Enchantments do not change attributes,
3235
// - All enchantment utils are bound to the server
3336

34-
/**
35-
* Returns the attack damage for the given [stack], the value is affected by potion effects and enchantments
36-
*/
37-
fun SafeContext.attackDamage(entity: LivingEntity = player, stack: ItemStack = entity.mainHandStack) =
38-
entity.attackDamage(stack)
37+
fun LivingEntity.attributeBaseValue(attribute: RegistryEntry<EntityAttribute>) =
38+
if (attributes.hasAttribute(attribute)) getAttributeBaseValue(attribute) else 0.0
39+
40+
fun AttributeModifiersComponent.filteredApply(base: Double, slot: EquipmentSlot, vararg attributes: RegistryEntry<EntityAttribute>): Double =
41+
modifiers.filter { attributes.contains(it.attribute) && it.slot.matches(slot) }
42+
.foldRight(base) { entry, acc ->
43+
val v = entry.modifier.value
44+
45+
acc + when (entry.modifier.operation) {
46+
EntityAttributeModifier.Operation.ADD_VALUE -> v
47+
EntityAttributeModifier.Operation.ADD_MULTIPLIED_BASE -> v * base
48+
EntityAttributeModifier.Operation.ADD_MULTIPLIED_TOTAL -> v * acc
49+
}
50+
}
51+
3952

4053
/**
4154
* Returns the attack damage for the given [stack], the value is affected by potion effects and enchantments
4255
*/
4356
fun LivingEntity.attackDamage(stack: ItemStack = mainHandStack) =
44-
(stack.getOrDefault(DataComponentTypes.ATTRIBUTE_MODIFIERS, AttributeModifiersComponent.DEFAULT)
45-
.modifiers.find { it.attribute == EntityAttributes.ATTACK_DAMAGE }?.modifier?.value ?: 0.0) +
46-
getAttributeValue(EntityAttributes.ATTACK_DAMAGE)
57+
stack.getOrDefault(DataComponentTypes.ATTRIBUTE_MODIFIERS, AttributeModifiersComponent.DEFAULT)
58+
.filteredApply(attributeBaseValue(EntityAttributes.ATTACK_DAMAGE), EquipmentSlot.MAINHAND, EntityAttributes.ATTACK_DAMAGE)
4759

4860
/**
4961
* Returns the attack speed for the given [stack], the value is affected by potion effects
5062
*
5163
* The value represents the number of attacks-per-tick
52-
*/
53-
fun SafeContext.attackSpeed(entity: LivingEntity = player, stack: ItemStack = entity.mainHandStack) =
54-
entity.attackSpeed(stack)
55-
56-
/**
57-
* Returns the attack speed for the given [stack], the value is affected by potion effects
5864
*
59-
* The value represents the number of attacks-per-tick
65+
* To get the number of ticks per attack do the following:
66+
* ```
67+
* ticks = 1 / speed * 20
68+
* ```
6069
*/
6170
fun LivingEntity.attackSpeed(stack: ItemStack = mainHandStack) =
62-
(stack.getOrDefault(DataComponentTypes.ATTRIBUTE_MODIFIERS, AttributeModifiersComponent.DEFAULT)
63-
.modifiers.find { it.attribute == EntityAttributes.ATTACK_SPEED }?.modifier?.value ?: 0.0) +
64-
getAttributeValue(EntityAttributes.ATTACK_SPEED)
65-
66-
/**
67-
* Returns the mining speed for the given [stack], the value is affected by potion effects and enchantments
68-
*/
69-
fun SafeContext.miningSpeed(entity: LivingEntity = player, stack: ItemStack = entity.mainHandStack) =
70-
entity.miningSpeed(stack)
71-
72-
/**
73-
* Returns the mining speed for the given [stack], the value is affected by potion effects and enchantments
74-
*/
75-
fun LivingEntity.miningSpeed(stack: ItemStack = mainHandStack) =
76-
(stack.getOrDefault(DataComponentTypes.ATTRIBUTE_MODIFIERS, AttributeModifiersComponent.DEFAULT)
77-
.modifiers.find {
78-
it.attribute == EntityAttributes.MINING_EFFICIENCY ||
79-
it.attribute == EntityAttributes.SUBMERGED_MINING_SPEED
80-
}?.modifier?.value ?: 0.0) +
81-
if (isSubmergedInWater) getAttributeValue(EntityAttributes.SUBMERGED_MINING_SPEED)
82-
else getAttributeValue(EntityAttributes.MINING_EFFICIENCY)
71+
stack.getOrDefault(DataComponentTypes.ATTRIBUTE_MODIFIERS, AttributeModifiersComponent.DEFAULT)
72+
.filteredApply(attributeBaseValue(EntityAttributes.ATTACK_SPEED), EquipmentSlot.MAINHAND, EntityAttributes.ATTACK_SPEED)
8373

8474
val ItemStack.spaceLeft get() = maxCount - count
8575
val ItemStack.hasSpace get() = spaceLeft > 0

src/main/kotlin/com/lambda/util/math/Linear.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import net.minecraft.util.math.Vec3d
2323
import java.awt.Color
2424
import kotlin.math.max
2525
import kotlin.math.min
26+
import kotlin.random.Random
2627
import kotlin.random.Random.Default.nextDouble
2728

2829
/**
@@ -46,7 +47,7 @@ fun ClosedRange<Float>.step(step: Float) = object : FloatIterator() {
4647
/**
4748
* Returns a random number within the range.
4849
*/
49-
fun ClosedRange<Double>.random() = nextDouble(start, endInclusive)
50+
fun ClosedRange<Double>.random(random: Random = Random) = start + (endInclusive - start) * random.nextDouble()
5051

5152
/**
5253
* Converts a value from one range to a normalized value between 0 and 1.

0 commit comments

Comments
 (0)