Skip to content

Commit 29b2a77

Browse files
committed
Open collection settings for typed collections
1 parent 49afd16 commit 29b2a77

File tree

13 files changed

+206
-62
lines changed

13 files changed

+206
-62
lines changed

src/main/kotlin/com/lambda/config/Configurable.kt

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import com.lambda.Lambda.LOG
2424
import com.lambda.config.settings.CharSetting
2525
import com.lambda.config.settings.FunctionSetting
2626
import com.lambda.config.settings.StringSetting
27+
import com.lambda.config.settings.collections.BlockCollectionSetting
2728
import com.lambda.config.settings.collections.CollectionSettings
29+
import com.lambda.config.settings.collections.ItemCollectionSetting
2830
import com.lambda.config.settings.collections.MapSetting
2931
import com.lambda.config.settings.comparable.BooleanSetting
3032
import com.lambda.config.settings.comparable.EnumSetting
@@ -43,6 +45,8 @@ import com.lambda.util.KeyCode
4345
import com.lambda.util.Nameable
4446
import imgui.flag.ImGuiInputTextFlags
4547
import net.minecraft.block.Block
48+
import net.minecraft.item.Item
49+
import net.minecraft.registry.Registries
4650
import net.minecraft.util.math.BlockPos
4751
import net.minecraft.util.math.Vec3d
4852
import java.awt.Color
@@ -122,20 +126,30 @@ abstract class Configurable(
122126
visibility: () -> Boolean = { true },
123127
) = StringSetting(name, defaultValue, multiline, flags, description, visibility).register()
124128

125-
inline fun <reified T : Any> setting(
126-
name: String,
127-
immutableList: Collection<T>,
128-
defaultValue: Collection<T> = immutableList,
129-
description: String = "",
130-
serializer: Stringifiable<T>,
131-
noinline visibility: () -> Boolean = { true },
132-
) = CollectionSettings(
129+
130+
fun setting(
131+
name: String,
132+
defaultValue: Collection<Block>,
133+
description: String = "",
134+
visibility: () -> Boolean = { true },
135+
) = BlockCollectionSetting(
133136
name,
134-
immutableList,
137+
Registries.BLOCK.toList(),
138+
defaultValue.toMutableList(),
139+
description,
140+
visibility,
141+
).register()
142+
143+
fun setting(
144+
name: String,
145+
defaultValue: Collection<Item>,
146+
description: String = "",
147+
visibility: () -> Boolean = { true },
148+
) = ItemCollectionSetting(
149+
name,
150+
Registries.ITEM.toList(),
135151
defaultValue.toMutableList(),
136-
TypeToken.getParameterized(MutableList::class.java, T::class.java).type,
137152
description,
138-
serializer,
139153
visibility,
140154
).register()
141155

@@ -144,15 +158,13 @@ abstract class Configurable(
144158
immutableList: Collection<T>,
145159
defaultValue: Collection<T> = immutableList,
146160
description: String = "",
147-
crossinline serializer: (T) -> String = { if (it::class.java.isPrimitive) it.toString() else it::class.java.simpleName },
148161
noinline visibility: () -> Boolean = { true },
149162
) = CollectionSettings(
150163
name,
151164
immutableList,
152165
defaultValue.toMutableList(),
153166
TypeToken.getParameterized(Collection::class.java, T::class.java).type,
154167
description,
155-
object : Stringifiable<T> { override fun stringify(value: T) = serializer(value) },
156168
visibility,
157169
).register()
158170

src/main/kotlin/com/lambda/config/Configuration.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ abstract class Configuration : Jsonable, Loadable {
100100
private fun save() = runCatching {
101101
primary.createIfNotExists()
102102
.let {
103-
it.writeText(gson.toJson(toJson()))
103+
it.writeText(toJson().toString())
104104
it.copyTo(backup, true)
105105
}
106106
}

src/main/kotlin/com/lambda/config/UserAutomationConfig.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@
1818
package com.lambda.config
1919

2020
import com.lambda.config.configurations.UserAutomationConfigs
21-
import com.lambda.config.serializer.ItemCodec
22-
import com.lambda.module.Module
2321
import com.lambda.module.ModuleRegistry.moduleNameMap
2422

2523
class UserAutomationConfig(override val name: String) : AutomationConfig(name, UserAutomationConfigs) {
26-
val linkedModules = setting<String>("Linked Modules", moduleNameMap.filter { it.value.defaultAutomationConfig != Companion.DEFAULT }.keys, emptySet(), serializer = { it })
24+
val linkedModules = setting<String>("Linked Modules", moduleNameMap.filter { it.value.defaultAutomationConfig != Companion.DEFAULT }.keys, emptySet())
2725
.onSelect { module -> moduleNameMap[module]?.automationConfig = this@UserAutomationConfig }
2826
.onDeselect { module ->
2927
moduleNameMap[module]?.let { module ->

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package com.lambda.config.groups
1919

2020
import com.lambda.config.Configurable
2121
import com.lambda.config.SettingGroup
22-
import com.lambda.config.serializer.ItemCodec
2322
import com.lambda.util.NamedEnum
2423
import net.minecraft.item.Item
2524
import net.minecraft.item.Items
@@ -36,13 +35,13 @@ class EatSettings(
3635
override val eatOnHunger by c.setting("Eat On Hunger", true, "Whether to eat when hungry").group(baseGroup).index()
3736
override val minFoodLevel by c.setting("Minimum Food Level", 6, 0..20, 1, "The minimum food level to eat food", " food level") { eatOnHunger }.group(baseGroup).index()
3837
override val saturated by c.setting("Saturated", EatConfig.Saturation.EatSmart, "When to stop eating") { eatOnHunger }.group(baseGroup).index()
39-
override val nutritiousFood by c.setting<Item>("Nutritious Food", nutritiousFoodDefaults, nutritiousFoodDefaults, "Items that are be considered nutritious", ItemCodec) { eatOnHunger }.group(baseGroup).index()
38+
override val nutritiousFood by c.setting("Nutritious Food", nutritiousFoodDefaults, description = "Items that are be considered nutritious") { eatOnHunger }.group(baseGroup).index()
4039
override val selectionPriority by c.setting("Selection Priority", EatConfig.SelectionPriority.MostNutritious, "The priority for selecting food items") { eatOnHunger }.group(baseGroup).index()
4140
override val eatOnFire by c.setting("Eat On Fire", true, "Whether to eat when on fire").group(baseGroup).index()
42-
override val resistanceFood by c.setting<Item>("Resistance Food", resistanceFoodDefaults, resistanceFoodDefaults, "Items that give Fire Resistance", ItemCodec) { eatOnFire }.group(baseGroup).index()
41+
override val resistanceFood by c.setting("Resistance Food", resistanceFoodDefaults, description = "Items that give Fire Resistance") { eatOnFire }.group(baseGroup).index()
4342
override val eatOnDamage by c.setting("Eat On Damage", true, "Whether to eat when damaged").group(baseGroup).index()
4443
override val minDamage by c.setting("Minimum Damage", 10, 0..20, 1, "The minimum damage threshold to trigger eating") { eatOnDamage }.group(baseGroup).index()
45-
override val regenerationFood by c.setting<Item>("Regeneration Food", regenerationFoodDefaults, regenerationFoodDefaults, "Items that give Regeneration", ItemCodec) { eatOnDamage }.group(baseGroup).index()
44+
override val regenerationFood by c.setting("Regeneration Food", regenerationFoodDefaults, description = "Items that give Regeneration") { eatOnDamage }.group(baseGroup).index()
4645
override val ignoreBadFood by c.setting("Ignore Bad Food", true, "Whether to eat when the food is bad").group(baseGroup).index()
47-
override val badFood by c.setting<Item>("Bad Food", negativeFoodDefaults, negativeFoodDefaults, "Items that are considered bad food", ItemCodec) { ignoreBadFood }.group(baseGroup).index()
46+
override val badFood by c.setting("Bad Food", negativeFoodDefaults, description = "Items that are considered bad food") { ignoreBadFood }.group(baseGroup).index()
4847
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class InventorySettings(
3636

3737
override val actionsPerSecond by c.setting("Actions Per Second", 100, 0..100, 1, "How many inventory actions can be performed per tick").group(baseGroup, Group.General).index()
3838
override val tickStageMask by c.setting("Inventory Stage Mask", setOf(TickEvent.Pre, TickEvent.Input.Pre, TickEvent.Input.Post, TickEvent.Player.Post), description = "The sub-tick timing at which inventory actions are performed").group(baseGroup, Group.General).index()
39-
override val disposables by c.setting("Disposables", ItemUtils.defaultDisposables, ItemUtils.defaultDisposables, "Items that will be ignored when checking for a free slot").group(baseGroup, Group.Container).index()
39+
override val disposables by c.setting("Disposables", ItemUtils.defaultDisposables, description = "Items that will be ignored when checking for a free slot").group(baseGroup, Group.Container).index()
4040
override val swapWithDisposables by c.setting("Swap With Disposables", true, "Swap items with disposable ones").group(baseGroup, Group.Container).index()
4141
override val providerPriority by c.setting("Provider Priority", InventoryConfig.Priority.WithMinItems, "What container to prefer when retrieving the item from").group(baseGroup, Group.Container).index()
4242
override val storePriority by c.setting("Store Priority", InventoryConfig.Priority.WithMinItems, "What container to prefer when storing the item to").group(baseGroup, Group.Container).index()
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2025 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.config.settings.collections
19+
20+
import com.lambda.config.serializer.BlockCodec
21+
import com.lambda.gui.dsl.ImGuiBuilder
22+
import imgui.flag.ImGuiSelectableFlags.DontClosePopups
23+
import net.minecraft.block.Block
24+
25+
class BlockCollectionSetting(
26+
override var name: String,
27+
private val immutableCollection: Collection<Block>,
28+
defaultValue: MutableCollection<Block>,
29+
description: String,
30+
visibility: () -> Boolean,
31+
) : CollectionSettings<Block>(
32+
name,
33+
immutableCollection,
34+
defaultValue,
35+
Block::class.java,
36+
description,
37+
visibility,
38+
) {
39+
override fun ImGuiBuilder.buildLayout() {
40+
val text = if (value.size == 1) "block" else "blocks"
41+
42+
combo("##$name", "$name: ${value.size} $text") {
43+
value.toMutableList() // Copy the list instead of iterating the immutable one
44+
.forEach {
45+
selectable(
46+
label = BlockCodec.stringify(it),
47+
selected = true,
48+
flags = DontClosePopups
49+
) { value.remove(it) }
50+
}
51+
}
52+
53+
button("Add") { openPopup("Blocks") }
54+
55+
popup("Blocks") {
56+
filter("Search for blocks") { filter ->
57+
immutableCollection
58+
.filter {
59+
//filter.inputBuffer.levenshteinDistance(ItemCodec.stringify(it)) < 3 &&
60+
!value.contains(it)
61+
}
62+
.forEach {
63+
text(BlockCodec.stringify(it))
64+
sameLine()
65+
button("Add") { value.add(it) }
66+
}
67+
}
68+
}
69+
}
70+
}

src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,20 @@ import com.google.gson.JsonElement
2121
import com.lambda.Lambda.gson
2222
import com.lambda.config.AbstractSetting
2323
import com.lambda.config.AutomationConfig
24-
import com.lambda.config.Stringifiable
2524
import com.lambda.context.SafeContext
2625
import com.lambda.gui.dsl.ImGuiBuilder
27-
import com.lambda.threading.runSafe
2826
import imgui.flag.ImGuiSelectableFlags.DontClosePopups
2927
import java.lang.reflect.Type
3028

3129
/**
3230
* @see [com.lambda.config.Configurable]
3331
*/
34-
class CollectionSettings<T : Any>(
32+
open class CollectionSettings<T : Any>(
3533
override var name: String,
3634
private var immutableCollection: Collection<T>,
3735
defaultValue: MutableCollection<T>,
3836
type: Type,
3937
description: String,
40-
private val serializer: Stringifiable<T>,
4138
visibility: () -> Boolean,
4239
) : AbstractSetting<MutableCollection<T>>(
4340
name,
@@ -49,43 +46,37 @@ class CollectionSettings<T : Any>(
4946
private val selectListeners = mutableListOf<SafeContext.(T) -> Unit>()
5047
private val deselectListeners = mutableListOf<SafeContext.(T) -> Unit>()
5148

49+
fun onSelect(block: SafeContext.(T) -> Unit) = apply {
50+
selectListeners.add(block)
51+
}
52+
53+
fun onDeselect(block: SafeContext.(T) -> Unit) = apply {
54+
deselectListeners.add(block)
55+
}
56+
5257
override fun ImGuiBuilder.buildLayout() {
5358
combo("##$name", "$name: ${value.size} item(s)") {
5459
immutableCollection
5560
.forEach {
5661
val isSelected = value.contains(it)
5762

5863
selectable(
59-
serializer.stringify(it), isSelected,
60-
flags = DontClosePopups
64+
label = it.toString(),
65+
selected = isSelected,
66+
flags = DontClosePopups,
6167
) {
62-
if (isSelected) {
63-
value.remove(it)
64-
runSafe { deselectListeners.forEach { listener -> listener(it) } }
65-
} else {
66-
value.add(it)
67-
runSafe { selectListeners.forEach { listener -> listener(it) } }
68-
}
68+
if (isSelected) value.remove(it)
69+
else value.add(it)
6970
}
7071
}
7172
}
7273
}
7374

74-
override fun toJson(): JsonElement = gson.toJsonTree(value)
75-
7675
override fun loadFromJson(serialized: JsonElement) {
77-
value = gson.fromJson<MutableList<T>>(serialized, type)
76+
value = gson.fromJson<Collection<T>>(serialized, type)
7877
.toMutableList()
7978
}
8079

81-
fun onSelect(block: SafeContext.(T) -> Unit) = apply {
82-
selectListeners.add(block)
83-
}
84-
85-
fun onDeselect(block: SafeContext.(T) -> Unit) = apply {
86-
deselectListeners.add(block)
87-
}
88-
8980
companion object {
9081
@AutomationConfig.SettingEditorDsl
9182
@Suppress("unchecked_cast")
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2025 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.config.settings.collections
19+
20+
import com.lambda.config.serializer.ItemCodec
21+
import com.lambda.gui.dsl.ImGuiBuilder
22+
import imgui.flag.ImGuiSelectableFlags.DontClosePopups
23+
import net.minecraft.item.Item
24+
25+
class ItemCollectionSetting(
26+
override var name: String,
27+
private val immutableCollection: Collection<Item>,
28+
defaultValue: MutableCollection<Item>,
29+
description: String,
30+
visibility: () -> Boolean,
31+
) : CollectionSettings<Item>(
32+
name,
33+
immutableCollection,
34+
defaultValue,
35+
Item::class.java,
36+
description,
37+
visibility,
38+
) {
39+
override fun ImGuiBuilder.buildLayout() {
40+
val text = if (value.size == 1) "item" else "items"
41+
42+
combo("##$name", "$name: ${value.size} $text") {
43+
value.toMutableList() // Copy the list instead of iterating the immutable one
44+
.forEach {
45+
selectable(
46+
label = ItemCodec.stringify(it),
47+
selected = true,
48+
flags = DontClosePopups
49+
) { value.remove(it) }
50+
}
51+
}
52+
53+
button("Add") { openPopup("Items") }
54+
55+
popup("Items") {
56+
filter("Search for items") { filter ->
57+
immutableCollection
58+
.filter {
59+
//filter.inputBuffer.levenshteinDistance(ItemCodec.stringify(it)) < 3 &&
60+
!value.contains(it)
61+
}
62+
.forEach {
63+
text(ItemCodec.stringify(it))
64+
sameLine()
65+
button("Add") { value.add(it) }
66+
}
67+
}
68+
}
69+
}
70+
}

src/main/kotlin/com/lambda/friend/FriendManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import java.util.*
4242
// - Improve save file structure.
4343
object FriendManager : Configurable(FriendConfig), Loadable {
4444
override val name = "friends"
45-
val friends by setting("friends", emptySet(), setOf(), serializer = GameProfileCodec)
45+
val friends by setting("friends", emptySet<GameProfile>())
4646

4747
fun befriend(profile: GameProfile) = friends.add(profile)
4848
fun unfriend(profile: GameProfile): Boolean = friends.remove(profile)

src/main/kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,15 +1583,19 @@ object ImGuiBuilder {
15831583
lambdaTooltip(description())
15841584
}
15851585

1586+
@ImGuiDsl
1587+
fun openPopup(strId: String, flags: Int = ImGuiPopupFlags.None) =
1588+
ImGui.openPopup(strId, flags)
1589+
15861590
/**
1587-
* Creates a popup.
1591+
* Creates a popup. You must first call [openPopup] with the same [strId]
15881592
*
15891593
* @param strId Unique identifier
15901594
* @param flags Popup flags
15911595
* @param block Content of the popup
15921596
*/
15931597
@ImGuiDsl
1594-
inline fun popup(strId: String, flags: Int = ImGuiPopupFlags.None, block: ProcedureBlock) {
1598+
inline fun popup(strId: String, flags: Int = ImGuiPopupFlags.AnyPopup, block: ProcedureBlock) {
15951599
if (beginPopup(strId, flags)) {
15961600
block()
15971601
endPopup()

0 commit comments

Comments
 (0)