Skip to content
35 changes: 23 additions & 12 deletions src/main/kotlin/com/lambda/Lambda.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ package com.lambda

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.lambda.config.serializer.BlockPosSerializer
import com.lambda.config.serializer.BlockSerializer
import com.lambda.config.serializer.BlockPosCodec
import com.lambda.config.serializer.BlockCodec
import com.lambda.config.serializer.ColorSerializer
import com.lambda.config.serializer.GameProfileSerializer
import com.lambda.config.serializer.ItemStackSerializer
import com.lambda.config.serializer.KeyCodeSerializer
import com.lambda.config.serializer.OptionalSerializer
import com.lambda.config.serializer.GameProfileCodec
import com.lambda.config.serializer.ItemCodec
import com.lambda.config.serializer.ItemStackCodec
import com.lambda.config.serializer.KeyCodeCodec
import com.lambda.config.serializer.OptionalCodec
import com.lambda.core.Loader
import com.lambda.event.events.ClientEvent
import com.lambda.event.listener.UnsafeListener.Companion.listenOnceUnsafe
Expand All @@ -37,7 +38,12 @@ import net.fabricmc.api.ClientModInitializer
import net.fabricmc.loader.api.FabricLoader
import net.minecraft.block.Block
import net.minecraft.client.MinecraftClient
import net.minecraft.item.ArrowItem
import net.minecraft.item.BlockItem
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.PotionItem
import net.minecraft.item.RangedWeaponItem
import net.minecraft.registry.DynamicRegistryManager
import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos
Expand Down Expand Up @@ -66,14 +72,19 @@ object Lambda : ClientModInitializer {

val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(KeyCode::class.java, KeyCodeSerializer)
.registerTypeAdapter(KeyCode::class.java, KeyCodeCodec)
.registerTypeAdapter(Color::class.java, ColorSerializer)
.registerTypeAdapter(BlockPos::class.java, BlockPosSerializer)
.registerTypeAdapter(Block::class.java, BlockSerializer)
.registerTypeAdapter(GameProfile::class.java, GameProfileSerializer)
.registerTypeAdapter(Optional::class.java, OptionalSerializer)
.registerTypeAdapter(ItemStack::class.java, ItemStackSerializer)
.registerTypeAdapter(BlockPos::class.java, BlockPosCodec)
.registerTypeAdapter(Block::class.java, BlockCodec)
.registerTypeAdapter(GameProfile::class.java, GameProfileCodec)
.registerTypeAdapter(Optional::class.java, OptionalCodec)
.registerTypeAdapter(ItemStack::class.java, ItemStackCodec)
.registerTypeAdapter(Text::class.java, Text.Serializer(DynamicRegistryManager.EMPTY))
.registerTypeAdapter(Item::class.java, ItemCodec)
.registerTypeAdapter(BlockItem::class.java, ItemCodec)
.registerTypeAdapter(ArrowItem::class.java, ItemCodec)
.registerTypeAdapter(PotionItem::class.java, ItemCodec)
.registerTypeAdapter(RangedWeaponItem::class.java, ItemCodec)
.create()

override fun onInitializeClient() {} // nop
Expand Down
25 changes: 25 additions & 0 deletions src/main/kotlin/com/lambda/config/Codec.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2025 Lambda
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.lambda.config

import com.google.gson.JsonDeserializer
import com.google.gson.JsonSerializer

interface Stringifiable<T> { fun stringify(value: T): String }

interface Codec<T> : JsonSerializer<T>, JsonDeserializer<T>
71 changes: 51 additions & 20 deletions src/main/kotlin/com/lambda/config/Configurable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import com.lambda.Lambda.LOG
import com.lambda.config.settings.CharSetting
import com.lambda.config.settings.FunctionSetting
import com.lambda.config.settings.StringSetting
import com.lambda.config.settings.collections.ListSetting
import com.lambda.config.settings.collections.BlockCollectionSetting
import com.lambda.config.settings.collections.ClassCollectionSetting
import com.lambda.config.settings.collections.CollectionSetting
import com.lambda.config.settings.collections.ItemCollectionSetting
import com.lambda.config.settings.collections.MapSetting
import com.lambda.config.settings.collections.SetSetting
import com.lambda.config.settings.comparable.BooleanSetting
import com.lambda.config.settings.comparable.EnumSetting
import com.lambda.config.settings.complex.Bind
Expand All @@ -44,6 +46,8 @@ import com.lambda.util.KeyCode
import com.lambda.util.Nameable
import imgui.flag.ImGuiInputTextFlags
import net.minecraft.block.Block
import net.minecraft.item.Item
import net.minecraft.registry.Registries
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d
import java.awt.Color
Expand Down Expand Up @@ -124,49 +128,76 @@ abstract class Configurable(
visibility: () -> Boolean = { true },
) = StringSetting(name, defaultValue, multiline, flags, description, visibility).register()

inline fun <reified T : Any> setting(

fun setting(
name: String,
immutableList: List<T>,
defaultValue: List<T>,
defaultValue: Collection<Block>,
description: String = "",
noinline visibility: () -> Boolean = { true },
) = ListSetting(
visibility: () -> Boolean = { true },
) = BlockCollectionSetting(
name,
immutableList,
Registries.BLOCK.toList(),
defaultValue.toMutableList(),
TypeToken.getParameterized(MutableList::class.java, T::class.java).type,
description,
visibility,
).register()

inline fun <reified K : Any, reified V : Any> setting(
fun setting(
name: String,
defaultValue: Map<K, V>,
defaultValue: Collection<Item>,
description: String = "",
visibility: () -> Boolean = { true },
) = ItemCollectionSetting(
name,
Registries.ITEM.toList(),
defaultValue.toMutableList(),
description,
visibility,
).register()

inline fun <reified T : Comparable<T>> setting(
name: String,
immutableList: Collection<T>,
defaultValue: Collection<T> = immutableList,
description: String = "",
noinline visibility: () -> Boolean = { true },
) = MapSetting(
) = CollectionSetting(
name,
defaultValue.toMutableMap(),
TypeToken.getParameterized(MutableMap::class.java, K::class.java, V::class.java).type,
immutableList,
defaultValue.toMutableList(),
TypeToken.getParameterized(Collection::class.java, T::class.java).type,
description,
visibility
visibility,
).register()

inline fun <reified T : Any> setting(
name: String,
immutableList: Set<T>,
defaultValue: Set<T> = immutableList,
immutableList: Collection<T>,
defaultValue: Collection<T> = immutableList,
description: String = "",
noinline visibility: () -> Boolean = { true },
) = SetSetting(
) = ClassCollectionSetting(
name,
immutableList,
defaultValue.toMutableSet(),
TypeToken.getParameterized(MutableSet::class.java, T::class.java).type,
defaultValue.toMutableList(),
description,
visibility,
).register()

// ToDo: Actually implement maps
inline fun <reified K : Any, reified V : Any> setting(
name: String,
defaultValue: Map<K, V>,
description: String = "",
noinline visibility: () -> Boolean = { true },
) = MapSetting(
name,
defaultValue.toMutableMap(),
TypeToken.getParameterized(MutableMap::class.java, K::class.java, V::class.java).type,
description,
visibility
).register()

fun setting(
name: String,
defaultValue: Double,
Expand Down
9 changes: 5 additions & 4 deletions src/main/kotlin/com/lambda/config/Configuration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,17 @@ abstract class Configuration : Jsonable, Loadable {
LOG.info(message)
info(message)
}
.onFailure {
var message: String
.onFailure { primaryError ->
LOG.error(primaryError)

runCatching { load(backup) }
.onSuccess {
message = "${configName.capitalize()} config loaded from backup"
val message = "${configName.capitalize()} config loaded from backup"
LOG.info(message)
info(message)
}
.onFailure { error ->
message = "Failed to load ${configName.capitalize()} config from backup, unrecoverable error"
val message = "Failed to load ${configName.capitalize()} config from backup, unrecoverable error"
LOG.error(message, error)
logError(message)
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/lambda/config/UserAutomationConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import com.lambda.config.configurations.UserAutomationConfigs
import com.lambda.module.ModuleRegistry.moduleNameMap

class UserAutomationConfig(override val name: String) : AutomationConfig(name, UserAutomationConfigs) {
val linkedModules = setting("Linked Modules", moduleNameMap.filter { it.value.defaultAutomationConfig != Companion.DEFAULT }.keys, emptySet())
val linkedModules = setting<String>("Linked Modules", moduleNameMap.filter { it.value.defaultAutomationConfig != Companion.DEFAULT }.keys, emptySet())
.onSelect { module -> moduleNameMap[module]?.automationConfig = this@UserAutomationConfig }
.onDeselect { module ->
moduleNameMap[module]?.let { module ->
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/lambda/config/groups/ActionConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import com.lambda.util.NamedEnum

interface ActionConfig {
val sorter: SortMode
val tickStageMask: Set<TickEvent>
val tickStageMask: Collection<TickEvent>

enum class SortMode(
override val displayName: String,
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/com/lambda/config/groups/BreakSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.lambda.config.groups
import com.lambda.config.Configurable
import com.lambda.config.SettingGroup
import com.lambda.event.events.TickEvent
import com.lambda.event.events.TickEvent.Companion.ALL_STAGES
import com.lambda.interaction.request.breaking.BreakConfig
import com.lambda.interaction.request.breaking.BreakConfig.AnimationMode
import com.lambda.interaction.request.breaking.BreakConfig.BreakConfirmationMode
Expand Down Expand Up @@ -56,7 +57,7 @@ open class BreakSettings(
override val breakDelay by c.setting("Break Delay", 0, 0..6, 1, "The delay between breaking blocks", " tick(s)").group(baseGroup, Group.General).index()

// Timing
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()
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()

// Swap
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()
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/com/lambda/config/groups/EatConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ import net.minecraft.item.ItemStack
interface EatConfig : ISettingGroup {
val eatOnHunger: Boolean
val minFoodLevel: Int
val nutritiousFood: List<Item>
val nutritiousFood: Collection<Item>
val saturated: Saturation

val eatOnFire: Boolean
val resistanceFood: List<Item>
val resistanceFood: Collection<Item>

val eatOnDamage: Boolean
val minDamage: Int
val regenerationFood: List<Item>
val regenerationFood: Collection<Item>

val selectionPriority: SelectionPriority
val ignoreBadFood: Boolean
val badFood: List<Item>
val badFood: Collection<Item>

enum class Saturation(
override val displayName: String,
Expand Down
9 changes: 5 additions & 4 deletions src/main/kotlin/com/lambda/config/groups/EatSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.lambda.config.groups
import com.lambda.config.Configurable
import com.lambda.config.SettingGroup
import com.lambda.util.NamedEnum
import net.minecraft.item.Item
import net.minecraft.item.Items

class EatSettings(
Expand All @@ -34,13 +35,13 @@ class EatSettings(
override val eatOnHunger by c.setting("Eat On Hunger", true, "Whether to eat when hungry").group(baseGroup).index()
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()
override val saturated by c.setting("Saturated", EatConfig.Saturation.EatSmart, "When to stop eating") { eatOnHunger }.group(baseGroup).index()
override val nutritiousFood by c.setting("Nutritious Food", nutritiousFoodDefaults, nutritiousFoodDefaults, "Items that are be considered nutritious") { eatOnHunger }.group(baseGroup).index()
override val nutritiousFood by c.setting("Nutritious Food", nutritiousFoodDefaults, description = "Items that are be considered nutritious") { eatOnHunger }.group(baseGroup).index()
override val selectionPriority by c.setting("Selection Priority", EatConfig.SelectionPriority.MostNutritious, "The priority for selecting food items") { eatOnHunger }.group(baseGroup).index()
override val eatOnFire by c.setting("Eat On Fire", true, "Whether to eat when on fire").group(baseGroup).index()
override val resistanceFood by c.setting("Resistance Food", resistanceFoodDefaults, resistanceFoodDefaults, "Items that give Fire Resistance") { eatOnFire }.group(baseGroup).index()
override val resistanceFood by c.setting("Resistance Food", resistanceFoodDefaults, description = "Items that give Fire Resistance") { eatOnFire }.group(baseGroup).index()
override val eatOnDamage by c.setting("Eat On Damage", true, "Whether to eat when damaged").group(baseGroup).index()
override val minDamage by c.setting("Minimum Damage", 10, 0..20, 1, "The minimum damage threshold to trigger eating") { eatOnDamage }.group(baseGroup).index()
override val regenerationFood by c.setting("Regeneration Food", regenerationFoodDefaults, regenerationFoodDefaults, "Items that give Regeneration") { eatOnDamage }.group(baseGroup).index()
override val regenerationFood by c.setting("Regeneration Food", regenerationFoodDefaults, description = "Items that give Regeneration") { eatOnDamage }.group(baseGroup).index()
override val ignoreBadFood by c.setting("Ignore Bad Food", true, "Whether to eat when the food is bad").group(baseGroup).index()
override val badFood by c.setting("Bad Food", negativeFoodDefaults, negativeFoodDefaults, "Items that are considered bad food") { ignoreBadFood }.group(baseGroup).index()
override val badFood by c.setting("Bad Food", negativeFoodDefaults, description = "Items that are considered bad food") { ignoreBadFood }.group(baseGroup).index()
}
3 changes: 2 additions & 1 deletion src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.lambda.config.groups
import com.lambda.config.Configurable
import com.lambda.config.SettingGroup
import com.lambda.event.events.TickEvent
import com.lambda.event.events.TickEvent.Companion.ALL_STAGES
import com.lambda.interaction.request.hotbar.HotbarConfig
import com.lambda.util.NamedEnum

Expand All @@ -31,5 +32,5 @@ class HotbarSettings(
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()
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()
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()
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()
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()
}
3 changes: 2 additions & 1 deletion src/main/kotlin/com/lambda/config/groups/InteractSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.lambda.config.groups
import com.lambda.config.Configurable
import com.lambda.config.SettingGroup
import com.lambda.event.events.TickEvent
import com.lambda.event.events.TickEvent.Companion.ALL_STAGES
import com.lambda.interaction.request.interacting.InteractConfig
import com.lambda.util.NamedEnum

Expand All @@ -30,7 +31,7 @@ class InteractSettings(
override val rotate by c.setting("Rotate For Interact", true, "Rotates the player to look at the block when interacting").group(baseGroup).index()
override val sorter by c.setting("Interact Sorter", ActionConfig.SortMode.Tool, "The order in which interactions are performed").group(baseGroup).index()
override val swingHand by c.setting("Swing On Interact", true, "Swings the players hand after interacting").group(baseGroup).index()
override val tickStageMask by c.setting("Interact Stage Mask", setOf<TickEvent>(TickEvent.Input.Post), description = "The sub-tick timing at which interact actions are performed").group(baseGroup).index()
override val tickStageMask by c.setting("Interact Stage Mask", ALL_STAGES.toSet(), setOf(TickEvent.Input.Post), description = "The sub-tick timing at which interact actions are performed").group(baseGroup).index()
override val interactSwingType by c.setting("Interact Swing Type", BuildConfig.SwingType.Vanilla, "The style of swing") { swingHand }.group(baseGroup).index()
override val interactConfirmationMode by c.setting("Interact Confirmation Mode", InteractConfig.InteractConfirmationMode.InteractThenAwait, "The style of confirmation for interactions").group(baseGroup).index()
}
Loading
Loading