Skip to content

Commit d4ead6a

Browse files
committed
ToolSaver module
1 parent 9a5f83c commit d4ead6a

File tree

3 files changed

+99
-2
lines changed

3 files changed

+99
-2
lines changed

src/main/kotlin/com/lambda/module/modules/player/AutoArmor.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ object AutoArmor : Module(
4949
) {
5050
private var elytraPriority by setting("Elytra Priority", true, "Prioritizes elytra's over other armor pieces in the chest slot")
5151
private val toggleElytraPriority by setting("Toggle Elytra Priority", Bind.EMPTY)
52-
private val minDurabilityPercentage by setting("Min Durability Percentage", 5, 0..100, 1, "Minimum durability percentage before being swapped for a new piece")
52+
private val minDurabilityPercentage by setting("Min Durability", 5, 0..100, 1, "Minimum durability percentage before being swapped for a new piece", "%")
5353
private val headProtection by setting("Preferred Head Protection", Protection.Protection)
5454
private val chestProtection by setting("Preferred Chest Protection", Protection.Protection)
5555
private val legProtection by setting("Preferred Leg Protection", Protection.BlastProtection)
@@ -123,7 +123,7 @@ object AutoArmor : Module(
123123
swaps.forEach {
124124
pickup(it.first.id)
125125
pickup(it.second.id)
126-
if (it.second.stack !== ItemStack.EMPTY)
126+
if (!it.second.stack.isEmpty)
127127
pickup(it.first.id)
128128
}
129129
}.submit()
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2026 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.module.modules.player
19+
20+
import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig
21+
import com.lambda.config.applyEdits
22+
import com.lambda.event.events.TickEvent
23+
import com.lambda.event.listener.SafeListener.Companion.listen
24+
import com.lambda.interaction.managers.inventory.InventoryRequest.Companion.inventoryRequest
25+
import com.lambda.module.Module
26+
import com.lambda.module.tag.ModuleTag
27+
import com.lambda.util.EnchantmentUtils.forEachEnchantment
28+
import com.lambda.util.EnchantmentUtils.getEnchantment
29+
import com.lambda.util.player.SlotUtils.hotbarSlots
30+
import com.lambda.util.player.SlotUtils.inventorySlots
31+
import net.minecraft.item.BlockItem
32+
import net.minecraft.item.ItemStack
33+
import net.minecraft.screen.slot.Slot
34+
35+
object ToolSaver : Module(
36+
name = "ToolSaver",
37+
description = "Moves tools from your hotbar into your inventory when they get too damaged",
38+
ModuleTag.PLAYER
39+
) {
40+
private val minDurabilityPercentage by setting("Min Durability", 5, 0..100, 1, "Minimum durability percentage before being swapped for a new piece", "%")
41+
private val replace by setting("Replace", true, "Replaces the tool with the one of the same kind")
42+
43+
init {
44+
setDefaultAutomationConfig {
45+
applyEdits {
46+
hideAllGroupsExcept(inventoryConfig)
47+
}
48+
}
49+
50+
listen<TickEvent.Pre> {
51+
val endangeredStacks = player.hotbarSlots.filter { it.stack.isEndangered }
52+
53+
val inventorySlots = player.inventorySlots
54+
val swaps = endangeredStacks
55+
.mapNotNull { endangered ->
56+
val sorter = compareByDescending<Slot> { swapSlot ->
57+
if (!replace) 0
58+
else swapSlot.stack.item == endangered.stack.item
59+
}.thenByDescending { swapSlot ->
60+
if (!replace) return@thenByDescending 0
61+
var matchingEnchantments = 0
62+
endangered.stack.forEachEnchantment { enchantment, level ->
63+
val swapEnchantmentLevel = swapSlot.stack.getEnchantment(enchantment)
64+
if (swapEnchantmentLevel != 0 && swapEnchantmentLevel == level) matchingEnchantments++
65+
}
66+
matchingEnchantments
67+
}.thenByDescending {
68+
it.stack.isEmpty
69+
}.thenByDescending {
70+
(it.stack.item as? BlockItem)?.block in inventoryConfig.disposables
71+
it.stack.isStackable
72+
}
73+
val swapWith = inventorySlots
74+
.filter { !it.stack.isEndangered }
75+
.sortedWith(sorter)
76+
.firstOrNull()
77+
?: return@mapNotNull null
78+
endangered to swapWith
79+
}
80+
81+
inventoryRequest {
82+
swaps.forEach {
83+
pickup(it.first.id)
84+
pickup(it.second.id)
85+
if (!it.second.stack.isEmpty)
86+
pickup(it.first.id)
87+
}
88+
}.submit()
89+
}
90+
}
91+
92+
private val ItemStack.isEndangered get() =
93+
isDamageable && 1 - (damage.toFloat() / maxDamage) < minDurabilityPercentage.toFloat() / 100
94+
}

src/main/kotlin/com/lambda/util/EnchantmentUtils.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ object EnchantmentUtils {
4040
fun ItemStack.getEnchantment(key: RegistryKey<Enchantment>) =
4141
enchantments.enchantmentEntries.find { it.key?.matchesKey(key) == true }?.intValue ?: 0
4242

43+
fun ItemStack.getEnchantment(entry: RegistryEntry<Enchantment>) =
44+
enchantments.enchantmentEntries.find { it == entry }?.intValue ?: 0
45+
4346
fun <T> ItemStack.forEachEnchantment(block: (RegistryEntry<Enchantment>, Int) -> T) =
4447
enchantments.enchantmentEntries.map { block(it.key, it.intValue) }
4548

0 commit comments

Comments
 (0)