Skip to content

Commit ffddc8b

Browse files
emyfopsbeanbag44
andauthored
Ref: Better handling of collection settings (#171)
This pull request changes the way we store and display collection settings by introducing two new classes being `CollectionSetting` and `ClassCollectionSetting`. The former is a generic setting that codec's comparable values by their `toString` function while the latter codec's non-comparable values (classes, any, etc) by their qualified name minus the package location. This allow for fine grained control over how custom collection settings are stored and displayed. --------- Co-authored-by: beanbag44 <pidgeonmaster64@gmail.com>
1 parent d27fa5c commit ffddc8b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+541
-377
lines changed

src/main/kotlin/com/lambda/Lambda.kt

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ package com.lambda
1919

2020
import com.google.gson.Gson
2121
import com.google.gson.GsonBuilder
22-
import com.lambda.config.serializer.BlockPosSerializer
23-
import com.lambda.config.serializer.BlockSerializer
22+
import com.lambda.config.serializer.BlockPosCodec
23+
import com.lambda.config.serializer.BlockCodec
2424
import com.lambda.config.serializer.ColorSerializer
25-
import com.lambda.config.serializer.GameProfileSerializer
26-
import com.lambda.config.serializer.ItemStackSerializer
27-
import com.lambda.config.serializer.KeyCodeSerializer
28-
import com.lambda.config.serializer.OptionalSerializer
25+
import com.lambda.config.serializer.GameProfileCodec
26+
import com.lambda.config.serializer.ItemCodec
27+
import com.lambda.config.serializer.ItemStackCodec
28+
import com.lambda.config.serializer.KeyCodeCodec
29+
import com.lambda.config.serializer.OptionalCodec
2930
import com.lambda.core.Loader
3031
import com.lambda.event.events.ClientEvent
3132
import com.lambda.event.listener.UnsafeListener.Companion.listenOnceUnsafe
@@ -37,7 +38,12 @@ import net.fabricmc.api.ClientModInitializer
3738
import net.fabricmc.loader.api.FabricLoader
3839
import net.minecraft.block.Block
3940
import net.minecraft.client.MinecraftClient
41+
import net.minecraft.item.ArrowItem
42+
import net.minecraft.item.BlockItem
43+
import net.minecraft.item.Item
4044
import net.minecraft.item.ItemStack
45+
import net.minecraft.item.PotionItem
46+
import net.minecraft.item.RangedWeaponItem
4147
import net.minecraft.registry.DynamicRegistryManager
4248
import net.minecraft.text.Text
4349
import net.minecraft.util.math.BlockPos
@@ -66,14 +72,19 @@ object Lambda : ClientModInitializer {
6672

6773
val gson: Gson = GsonBuilder()
6874
.setPrettyPrinting()
69-
.registerTypeAdapter(KeyCode::class.java, KeyCodeSerializer)
75+
.registerTypeAdapter(KeyCode::class.java, KeyCodeCodec)
7076
.registerTypeAdapter(Color::class.java, ColorSerializer)
71-
.registerTypeAdapter(BlockPos::class.java, BlockPosSerializer)
72-
.registerTypeAdapter(Block::class.java, BlockSerializer)
73-
.registerTypeAdapter(GameProfile::class.java, GameProfileSerializer)
74-
.registerTypeAdapter(Optional::class.java, OptionalSerializer)
75-
.registerTypeAdapter(ItemStack::class.java, ItemStackSerializer)
77+
.registerTypeAdapter(BlockPos::class.java, BlockPosCodec)
78+
.registerTypeAdapter(Block::class.java, BlockCodec)
79+
.registerTypeAdapter(GameProfile::class.java, GameProfileCodec)
80+
.registerTypeAdapter(Optional::class.java, OptionalCodec)
81+
.registerTypeAdapter(ItemStack::class.java, ItemStackCodec)
7682
.registerTypeAdapter(Text::class.java, Text.Serializer(DynamicRegistryManager.EMPTY))
83+
.registerTypeAdapter(Item::class.java, ItemCodec)
84+
.registerTypeAdapter(BlockItem::class.java, ItemCodec)
85+
.registerTypeAdapter(ArrowItem::class.java, ItemCodec)
86+
.registerTypeAdapter(PotionItem::class.java, ItemCodec)
87+
.registerTypeAdapter(RangedWeaponItem::class.java, ItemCodec)
7788
.create()
7889

7990
override fun onInitializeClient() {} // nop
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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
19+
20+
import com.google.gson.JsonDeserializer
21+
import com.google.gson.JsonSerializer
22+
23+
interface Stringifiable<T> { fun stringify(value: T): String }
24+
25+
interface Codec<T> : JsonSerializer<T>, JsonDeserializer<T>

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

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ 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.ListSetting
27+
import com.lambda.config.settings.collections.BlockCollectionSetting
28+
import com.lambda.config.settings.collections.ClassCollectionSetting
29+
import com.lambda.config.settings.collections.CollectionSetting
30+
import com.lambda.config.settings.collections.ItemCollectionSetting
2831
import com.lambda.config.settings.collections.MapSetting
29-
import com.lambda.config.settings.collections.SetSetting
3032
import com.lambda.config.settings.comparable.BooleanSetting
3133
import com.lambda.config.settings.comparable.EnumSetting
3234
import com.lambda.config.settings.complex.Bind
@@ -44,6 +46,8 @@ import com.lambda.util.KeyCode
4446
import com.lambda.util.Nameable
4547
import imgui.flag.ImGuiInputTextFlags
4648
import net.minecraft.block.Block
49+
import net.minecraft.item.Item
50+
import net.minecraft.registry.Registries
4751
import net.minecraft.util.math.BlockPos
4852
import net.minecraft.util.math.Vec3d
4953
import java.awt.Color
@@ -124,49 +128,76 @@ abstract class Configurable(
124128
visibility: () -> Boolean = { true },
125129
) = StringSetting(name, defaultValue, multiline, flags, description, visibility).register()
126130

127-
inline fun <reified T : Any> setting(
131+
132+
fun setting(
128133
name: String,
129-
immutableList: List<T>,
130-
defaultValue: List<T>,
134+
defaultValue: Collection<Block>,
131135
description: String = "",
132-
noinline visibility: () -> Boolean = { true },
133-
) = ListSetting(
136+
visibility: () -> Boolean = { true },
137+
) = BlockCollectionSetting(
134138
name,
135-
immutableList,
139+
Registries.BLOCK.toList(),
136140
defaultValue.toMutableList(),
137-
TypeToken.getParameterized(MutableList::class.java, T::class.java).type,
138141
description,
139142
visibility,
140143
).register()
141144

142-
inline fun <reified K : Any, reified V : Any> setting(
145+
fun setting(
143146
name: String,
144-
defaultValue: Map<K, V>,
147+
defaultValue: Collection<Item>,
148+
description: String = "",
149+
visibility: () -> Boolean = { true },
150+
) = ItemCollectionSetting(
151+
name,
152+
Registries.ITEM.toList(),
153+
defaultValue.toMutableList(),
154+
description,
155+
visibility,
156+
).register()
157+
158+
inline fun <reified T : Comparable<T>> setting(
159+
name: String,
160+
immutableList: Collection<T>,
161+
defaultValue: Collection<T> = immutableList,
145162
description: String = "",
146163
noinline visibility: () -> Boolean = { true },
147-
) = MapSetting(
164+
) = CollectionSetting(
148165
name,
149-
defaultValue.toMutableMap(),
150-
TypeToken.getParameterized(MutableMap::class.java, K::class.java, V::class.java).type,
166+
immutableList,
167+
defaultValue.toMutableList(),
168+
TypeToken.getParameterized(Collection::class.java, T::class.java).type,
151169
description,
152-
visibility
170+
visibility,
153171
).register()
154172

155173
inline fun <reified T : Any> setting(
156174
name: String,
157-
immutableList: Set<T>,
158-
defaultValue: Set<T> = immutableList,
175+
immutableList: Collection<T>,
176+
defaultValue: Collection<T> = immutableList,
159177
description: String = "",
160178
noinline visibility: () -> Boolean = { true },
161-
) = SetSetting(
179+
) = ClassCollectionSetting(
162180
name,
163181
immutableList,
164-
defaultValue.toMutableSet(),
165-
TypeToken.getParameterized(MutableSet::class.java, T::class.java).type,
182+
defaultValue.toMutableList(),
166183
description,
167184
visibility,
168185
).register()
169186

187+
// ToDo: Actually implement maps
188+
inline fun <reified K : Any, reified V : Any> setting(
189+
name: String,
190+
defaultValue: Map<K, V>,
191+
description: String = "",
192+
noinline visibility: () -> Boolean = { true },
193+
) = MapSetting(
194+
name,
195+
defaultValue.toMutableMap(),
196+
TypeToken.getParameterized(MutableMap::class.java, K::class.java, V::class.java).type,
197+
description,
198+
visibility
199+
).register()
200+
170201
fun setting(
171202
name: String,
172203
defaultValue: Double,

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,17 @@ abstract class Configuration : Jsonable, Loadable {
135135
LOG.info(message)
136136
info(message)
137137
}
138-
.onFailure {
139-
var message: String
138+
.onFailure { primaryError ->
139+
LOG.error(primaryError)
140+
140141
runCatching { load(backup) }
141142
.onSuccess {
142-
message = "${configName.capitalize()} config loaded from backup"
143+
val message = "${configName.capitalize()} config loaded from backup"
143144
LOG.info(message)
144145
info(message)
145146
}
146147
.onFailure { error ->
147-
message = "Failed to load ${configName.capitalize()} config from backup, unrecoverable error"
148+
val message = "Failed to load ${configName.capitalize()} config from backup, unrecoverable error"
148149
LOG.error(message, error)
149150
logError(message)
150151
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import com.lambda.config.configurations.UserAutomationConfigs
2121
import com.lambda.module.ModuleRegistry.moduleNameMap
2222

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import com.lambda.util.NamedEnum
2323

2424
interface ActionConfig {
2525
val sorter: SortMode
26-
val tickStageMask: Set<TickEvent>
26+
val tickStageMask: Collection<TickEvent>
2727

2828
enum class SortMode(
2929
override val displayName: String,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package com.lambda.config.groups
2020
import com.lambda.config.Configurable
2121
import com.lambda.config.SettingGroup
2222
import com.lambda.event.events.TickEvent
23+
import com.lambda.event.events.TickEvent.Companion.ALL_STAGES
2324
import com.lambda.interaction.request.breaking.BreakConfig
2425
import com.lambda.interaction.request.breaking.BreakConfig.AnimationMode
2526
import com.lambda.interaction.request.breaking.BreakConfig.BreakConfirmationMode
@@ -56,7 +57,7 @@ open class BreakSettings(
5657
override val breakDelay by c.setting("Break Delay", 0, 0..6, 1, "The delay between breaking blocks", " tick(s)").group(baseGroup, Group.General).index()
5758

5859
// Timing
59-
override val tickStageMask by c.setting("Break Stage Mask", setOf<TickEvent>(TickEvent.Input.Post), description = "The sub-tick timing at which break actions can be performed").group(baseGroup, Group.General).index()
60+
override val tickStageMask by c.setting("Break Stage Mask", ALL_STAGES.toSet(), setOf(TickEvent.Input.Post), description = "The sub-tick timing at which break actions can be performed").group(baseGroup, Group.General).index()
6061

6162
// Swap
6263
override val swapMode by c.setting("Swap Mode", BreakConfig.SwapMode.End, "Decides when to swap to the best suited tool when breaking a block").group(baseGroup, Group.General).index()

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,19 @@ import net.minecraft.item.ItemStack
3232
interface EatConfig : ISettingGroup {
3333
val eatOnHunger: Boolean
3434
val minFoodLevel: Int
35-
val nutritiousFood: List<Item>
35+
val nutritiousFood: Collection<Item>
3636
val saturated: Saturation
3737

3838
val eatOnFire: Boolean
39-
val resistanceFood: List<Item>
39+
val resistanceFood: Collection<Item>
4040

4141
val eatOnDamage: Boolean
4242
val minDamage: Int
43-
val regenerationFood: List<Item>
43+
val regenerationFood: Collection<Item>
4444

4545
val selectionPriority: SelectionPriority
4646
val ignoreBadFood: Boolean
47-
val badFood: List<Item>
47+
val badFood: Collection<Item>
4848

4949
enum class Saturation(
5050
override val displayName: String,

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package com.lambda.config.groups
2020
import com.lambda.config.Configurable
2121
import com.lambda.config.SettingGroup
2222
import com.lambda.util.NamedEnum
23+
import net.minecraft.item.Item
2324
import net.minecraft.item.Items
2425

2526
class EatSettings(
@@ -34,13 +35,13 @@ class EatSettings(
3435
override val eatOnHunger by c.setting("Eat On Hunger", true, "Whether to eat when hungry").group(baseGroup).index()
3536
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()
3637
override val saturated by c.setting("Saturated", EatConfig.Saturation.EatSmart, "When to stop eating") { eatOnHunger }.group(baseGroup).index()
37-
override val nutritiousFood by c.setting("Nutritious Food", nutritiousFoodDefaults, nutritiousFoodDefaults, "Items that are be considered nutritious") { 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()
3839
override val selectionPriority by c.setting("Selection Priority", EatConfig.SelectionPriority.MostNutritious, "The priority for selecting food items") { eatOnHunger }.group(baseGroup).index()
3940
override val eatOnFire by c.setting("Eat On Fire", true, "Whether to eat when on fire").group(baseGroup).index()
40-
override val resistanceFood by c.setting("Resistance Food", resistanceFoodDefaults, resistanceFoodDefaults, "Items that give Fire Resistance") { eatOnFire }.group(baseGroup).index()
41+
override val resistanceFood by c.setting("Resistance Food", resistanceFoodDefaults, description = "Items that give Fire Resistance") { eatOnFire }.group(baseGroup).index()
4142
override val eatOnDamage by c.setting("Eat On Damage", true, "Whether to eat when damaged").group(baseGroup).index()
4243
override val minDamage by c.setting("Minimum Damage", 10, 0..20, 1, "The minimum damage threshold to trigger eating") { eatOnDamage }.group(baseGroup).index()
43-
override val regenerationFood by c.setting("Regeneration Food", regenerationFoodDefaults, regenerationFoodDefaults, "Items that give Regeneration") { eatOnDamage }.group(baseGroup).index()
44+
override val regenerationFood by c.setting("Regeneration Food", regenerationFoodDefaults, description = "Items that give Regeneration") { eatOnDamage }.group(baseGroup).index()
4445
override val ignoreBadFood by c.setting("Ignore Bad Food", true, "Whether to eat when the food is bad").group(baseGroup).index()
45-
override val badFood by c.setting("Bad Food", negativeFoodDefaults, negativeFoodDefaults, "Items that are considered bad food") { 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()
4647
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package com.lambda.config.groups
2020
import com.lambda.config.Configurable
2121
import com.lambda.config.SettingGroup
2222
import com.lambda.event.events.TickEvent
23+
import com.lambda.event.events.TickEvent.Companion.ALL_STAGES
2324
import com.lambda.interaction.request.hotbar.HotbarConfig
2425
import com.lambda.util.NamedEnum
2526

@@ -31,5 +32,5 @@ class HotbarSettings(
3132
override val swapDelay by c.setting("Swap Delay", 0, 0..3, 1, "The number of ticks delay before allowing another hotbar selection swap", " ticks").group(baseGroup).index()
3233
override val swapsPerTick by c.setting("Swaps Per Tick", 3, 1..10, 1, "The number of hotbar selection swaps that can take place each tick") { swapDelay <= 0 }.group(baseGroup).index()
3334
override val swapPause by c.setting("Swap Pause", 0, 0..20, 1, "The delay in ticks to pause actions after switching to the slot", " ticks").group(baseGroup).index()
34-
override val tickStageMask by c.setting("Hotbar Stage Mask", setOf<TickEvent>(TickEvent.Input.Post), description = "The sub-tick timing at which hotbar actions are performed").group(baseGroup).index()
35+
override val tickStageMask by c.setting("Hotbar Stage Mask", ALL_STAGES.toSet(), setOf(TickEvent.Input.Post), description = "The sub-tick timing at which hotbar actions are performed").group(baseGroup).index()
3536
}

0 commit comments

Comments
 (0)