From 49afd1653763371715a414ab81ded7f7c9d5ef39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emy=20=F0=9F=92=9C?= Date: Sat, 29 Nov 2025 18:32:58 -0500 Subject: [PATCH 1/8] Attempt at adding collection setting codecs --- src/main/kotlin/com/lambda/Lambda.kt | 36 ++++-- src/main/kotlin/com/lambda/config/Codec.kt | 25 +++++ .../kotlin/com/lambda/config/Configurable.kt | 46 ++++---- .../com/lambda/config/UserAutomationConfig.kt | 4 +- .../com/lambda/config/groups/ActionConfig.kt | 2 +- .../com/lambda/config/groups/EatConfig.kt | 8 +- .../com/lambda/config/groups/EatSettings.kt | 10 +- .../{BlockSerializer.kt => BlockCodec.kt} | 8 +- ...BlockPosSerializer.kt => BlockPosCodec.kt} | 7 +- .../config/serializer/ColorSerializer.kt | 25 ++--- ...ofileSerializer.kt => GameProfileCodec.kt} | 24 ++-- .../com/lambda/config/serializer/ItemCodec.kt | 46 ++++++++ ...emStackSerializer.kt => ItemStackCodec.kt} | 8 +- .../{KeyCodeSerializer.kt => KeyCodeCodec.kt} | 3 +- ...OptionalSerializer.kt => OptionalCodec.kt} | 3 +- .../{ListSetting.kt => CollectionSettings.kt} | 32 ++---- .../config/settings/collections/SetSetting.kt | 104 ------------------ .../kotlin/com/lambda/friend/FriendManager.kt | 3 +- .../com/lambda/interaction/BaritoneManager.kt | 25 +++-- .../construction/verify/TargetState.kt | 2 +- .../com/lambda/interaction/request/Request.kt | 2 +- .../request/breaking/BreakConfig.kt | 2 +- .../request/hotbar/HotbarConfig.kt | 2 +- .../request/inventory/InventoryConfig.kt | 4 +- .../module/modules/debug/SettingTest.kt | 87 --------------- .../module/modules/movement/BetterFirework.kt | 7 +- .../module/modules/network/PacketLimiter.kt | 2 +- .../module/modules/network/PacketLogger.kt | 13 ++- .../lambda/module/modules/render/BlockESP.kt | 3 +- 29 files changed, 229 insertions(+), 314 deletions(-) create mode 100644 src/main/kotlin/com/lambda/config/Codec.kt rename src/main/kotlin/com/lambda/config/serializer/{BlockSerializer.kt => BlockCodec.kt} (85%) rename src/main/kotlin/com/lambda/config/serializer/{BlockPosSerializer.kt => BlockPosCodec.kt} (86%) rename src/main/kotlin/com/lambda/config/serializer/{GameProfileSerializer.kt => GameProfileCodec.kt} (76%) create mode 100644 src/main/kotlin/com/lambda/config/serializer/ItemCodec.kt rename src/main/kotlin/com/lambda/config/serializer/{ItemStackSerializer.kt => ItemStackCodec.kt} (87%) rename src/main/kotlin/com/lambda/config/serializer/{KeyCodeSerializer.kt => KeyCodeCodec.kt} (95%) rename src/main/kotlin/com/lambda/config/serializer/{OptionalSerializer.kt => OptionalCodec.kt} (94%) rename src/main/kotlin/com/lambda/config/settings/collections/{ListSetting.kt => CollectionSettings.kt} (70%) delete mode 100644 src/main/kotlin/com/lambda/config/settings/collections/SetSetting.kt delete mode 100644 src/main/kotlin/com/lambda/module/modules/debug/SettingTest.kt diff --git a/src/main/kotlin/com/lambda/Lambda.kt b/src/main/kotlin/com/lambda/Lambda.kt index 72f10c9aa..a4ce44f43 100644 --- a/src/main/kotlin/com/lambda/Lambda.kt +++ b/src/main/kotlin/com/lambda/Lambda.kt @@ -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 @@ -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 @@ -66,14 +72,20 @@ 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)) + // We have to add all item sub classes :/. I probably missed some + .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 diff --git a/src/main/kotlin/com/lambda/config/Codec.kt b/src/main/kotlin/com/lambda/config/Codec.kt new file mode 100644 index 000000000..93dc918b9 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/Codec.kt @@ -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 . + */ + +package com.lambda.config + +import com.google.gson.JsonDeserializer +import com.google.gson.JsonSerializer + +interface Stringifiable { fun stringify(value: T): String } + +interface Codec : JsonSerializer, JsonDeserializer \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/Configurable.kt b/src/main/kotlin/com/lambda/config/Configurable.kt index 3a1ee030f..bfa58fe53 100644 --- a/src/main/kotlin/com/lambda/config/Configurable.kt +++ b/src/main/kotlin/com/lambda/config/Configurable.kt @@ -24,9 +24,8 @@ 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.CollectionSettings 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 @@ -123,21 +122,41 @@ abstract class Configurable( visibility: () -> Boolean = { true }, ) = StringSetting(name, defaultValue, multiline, flags, description, visibility).register() + inline fun setting( + name: String, + immutableList: Collection, + defaultValue: Collection = immutableList, + description: String = "", + serializer: Stringifiable, + noinline visibility: () -> Boolean = { true }, + ) = CollectionSettings( + name, + immutableList, + defaultValue.toMutableList(), + TypeToken.getParameterized(MutableList::class.java, T::class.java).type, + description, + serializer, + visibility, + ).register() + inline fun setting( name: String, - immutableList: List, - defaultValue: List, + immutableList: Collection, + defaultValue: Collection = immutableList, description: String = "", + crossinline serializer: (T) -> String = { if (it::class.java.isPrimitive) it.toString() else it::class.java.simpleName }, noinline visibility: () -> Boolean = { true }, - ) = ListSetting( + ) = CollectionSettings( name, immutableList, defaultValue.toMutableList(), - TypeToken.getParameterized(MutableList::class.java, T::class.java).type, + TypeToken.getParameterized(Collection::class.java, T::class.java).type, description, + object : Stringifiable { override fun stringify(value: T) = serializer(value) }, visibility, ).register() + // ToDo: Actually implement maps inline fun setting( name: String, defaultValue: Map, @@ -151,21 +170,6 @@ abstract class Configurable( visibility ).register() - inline fun setting( - name: String, - immutableList: Set, - defaultValue: Set = immutableList, - description: String = "", - noinline visibility: () -> Boolean = { true }, - ) = SetSetting( - name, - immutableList, - defaultValue.toMutableSet(), - TypeToken.getParameterized(MutableSet::class.java, T::class.java).type, - description, - visibility, - ).register() - fun setting( name: String, defaultValue: Double, diff --git a/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt b/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt index cdf19707e..0c86b46a6 100644 --- a/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt +++ b/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt @@ -18,10 +18,12 @@ package com.lambda.config import com.lambda.config.configurations.UserAutomationConfigs +import com.lambda.config.serializer.ItemCodec +import com.lambda.module.Module 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("Linked Modules", moduleNameMap.filter { it.value.defaultAutomationConfig != Companion.DEFAULT }.keys, emptySet(), serializer = { it }) .onSelect { module -> moduleNameMap[module]?.automationConfig = this@UserAutomationConfig } .onDeselect { module -> moduleNameMap[module]?.let { module -> diff --git a/src/main/kotlin/com/lambda/config/groups/ActionConfig.kt b/src/main/kotlin/com/lambda/config/groups/ActionConfig.kt index 8dff05ea6..8851ac52c 100644 --- a/src/main/kotlin/com/lambda/config/groups/ActionConfig.kt +++ b/src/main/kotlin/com/lambda/config/groups/ActionConfig.kt @@ -23,7 +23,7 @@ import com.lambda.util.NamedEnum interface ActionConfig { val sorter: SortMode - val tickStageMask: Set + val tickStageMask: Collection enum class SortMode( override val displayName: String, diff --git a/src/main/kotlin/com/lambda/config/groups/EatConfig.kt b/src/main/kotlin/com/lambda/config/groups/EatConfig.kt index bfc044896..5a0f36496 100644 --- a/src/main/kotlin/com/lambda/config/groups/EatConfig.kt +++ b/src/main/kotlin/com/lambda/config/groups/EatConfig.kt @@ -31,19 +31,19 @@ import net.minecraft.item.ItemStack interface EatConfig { val eatOnHunger: Boolean val minFoodLevel: Int - val nutritiousFood: List + val nutritiousFood: Collection val saturated: Saturation val eatOnFire: Boolean - val resistanceFood: List + val resistanceFood: Collection val eatOnDamage: Boolean val minDamage: Int - val regenerationFood: List + val regenerationFood: Collection val selectionPriority: SelectionPriority val ignoreBadFood: Boolean - val badFood: List + val badFood: Collection enum class Saturation( override val displayName: String, diff --git a/src/main/kotlin/com/lambda/config/groups/EatSettings.kt b/src/main/kotlin/com/lambda/config/groups/EatSettings.kt index a59ac07c4..6696edf9d 100644 --- a/src/main/kotlin/com/lambda/config/groups/EatSettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/EatSettings.kt @@ -19,7 +19,9 @@ package com.lambda.config.groups import com.lambda.config.Configurable import com.lambda.config.SettingGroup +import com.lambda.config.serializer.ItemCodec import com.lambda.util.NamedEnum +import net.minecraft.item.Item import net.minecraft.item.Items class EatSettings( @@ -34,13 +36,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, nutritiousFoodDefaults, "Items that are be considered nutritious", ItemCodec) { 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, resistanceFoodDefaults, "Items that give Fire Resistance", ItemCodec) { 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, regenerationFoodDefaults, "Items that give Regeneration", ItemCodec) { 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, negativeFoodDefaults, "Items that are considered bad food", ItemCodec) { ignoreBadFood }.group(baseGroup).index() } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializer/BlockSerializer.kt b/src/main/kotlin/com/lambda/config/serializer/BlockCodec.kt similarity index 85% rename from src/main/kotlin/com/lambda/config/serializer/BlockSerializer.kt rename to src/main/kotlin/com/lambda/config/serializer/BlockCodec.kt index c9b56dddf..caafe6235 100644 --- a/src/main/kotlin/com/lambda/config/serializer/BlockSerializer.kt +++ b/src/main/kotlin/com/lambda/config/serializer/BlockCodec.kt @@ -18,16 +18,16 @@ package com.lambda.config.serializer import com.google.gson.JsonDeserializationContext -import com.google.gson.JsonDeserializer import com.google.gson.JsonElement import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer +import com.lambda.config.Codec +import com.lambda.config.Stringifiable import com.mojang.serialization.JsonOps import net.minecraft.block.Block import net.minecraft.registry.Registries import java.lang.reflect.Type -object BlockSerializer : JsonSerializer, JsonDeserializer { +object BlockCodec : Codec, Stringifiable { override fun serialize( src: Block, typeOfSrc: Type, @@ -43,4 +43,6 @@ object BlockSerializer : JsonSerializer, JsonDeserializer { ): Block = Registries.BLOCK.codec.parse(JsonOps.INSTANCE, json) .orThrow + + override fun stringify(value: Block) = Registries.BLOCK.getId(value).path.replaceFirstChar { it.uppercase() } } diff --git a/src/main/kotlin/com/lambda/config/serializer/BlockPosSerializer.kt b/src/main/kotlin/com/lambda/config/serializer/BlockPosCodec.kt similarity index 86% rename from src/main/kotlin/com/lambda/config/serializer/BlockPosSerializer.kt rename to src/main/kotlin/com/lambda/config/serializer/BlockPosCodec.kt index f7ea8a38f..3e099aaca 100644 --- a/src/main/kotlin/com/lambda/config/serializer/BlockPosSerializer.kt +++ b/src/main/kotlin/com/lambda/config/serializer/BlockPosCodec.kt @@ -22,12 +22,15 @@ import com.google.gson.JsonDeserializer import com.google.gson.JsonElement import com.google.gson.JsonSerializationContext import com.google.gson.JsonSerializer +import com.lambda.config.Codec +import com.lambda.config.Stringifiable +import com.lambda.util.Formatting.format import com.mojang.serialization.JsonOps import net.minecraft.util.math.BlockPos import java.lang.reflect.Type import kotlin.jvm.optionals.getOrElse -object BlockPosSerializer : JsonSerializer, JsonDeserializer { +object BlockPosCodec : Codec, Stringifiable { override fun serialize( src: BlockPos, typeOfSrc: Type, @@ -44,4 +47,6 @@ object BlockPosSerializer : JsonSerializer, JsonDeserializer BlockPos.CODEC.parse(JsonOps.INSTANCE, json) .result() .getOrElse { BlockPos.ORIGIN } + + override fun stringify(value: BlockPos) = value.format() } diff --git a/src/main/kotlin/com/lambda/config/serializer/ColorSerializer.kt b/src/main/kotlin/com/lambda/config/serializer/ColorSerializer.kt index 49f04d576..64d403f75 100644 --- a/src/main/kotlin/com/lambda/config/serializer/ColorSerializer.kt +++ b/src/main/kotlin/com/lambda/config/serializer/ColorSerializer.kt @@ -18,36 +18,35 @@ package com.lambda.config.serializer import com.google.gson.JsonDeserializationContext -import com.google.gson.JsonDeserializer import com.google.gson.JsonElement -import com.google.gson.JsonNull import com.google.gson.JsonParseException import com.google.gson.JsonPrimitive import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer +import com.lambda.config.Codec +import com.lambda.config.Stringifiable import java.awt.Color import java.lang.reflect.Type -object ColorSerializer : JsonSerializer, JsonDeserializer { +object ColorSerializer : Codec, Stringifiable { override fun serialize( - src: Color?, - typeOfSrc: Type?, + src: Color, + typeOfSrc: Type, context: JsonSerializationContext?, ): JsonElement = - src?.let { - JsonPrimitive("${it.red},${it.green},${it.blue},${it.alpha}") - } ?: JsonNull.INSTANCE + JsonPrimitive("${src.red},${src.green},${src.blue},${src.alpha}") override fun deserialize( - json: JsonElement?, - typeOfT: Type?, + json: JsonElement, + typeOfT: Type, context: JsonDeserializationContext?, ): Color = - json?.asString?.split(",")?.let { + json.asString.split(",").let { when (it.size) { 3 -> Color(it[0].toInt(), it[1].toInt(), it[2].toInt()) 4 -> Color(it[0].toInt(), it[1].toInt(), it[2].toInt(), it[3].toInt()) else -> throw JsonParseException("Invalid color format") } - } ?: throw JsonParseException("Invalid color format") + } + + override fun stringify(value: Color) = "${value.red},${value.green},${value.blue},${value.alpha}" } diff --git a/src/main/kotlin/com/lambda/config/serializer/GameProfileSerializer.kt b/src/main/kotlin/com/lambda/config/serializer/GameProfileCodec.kt similarity index 76% rename from src/main/kotlin/com/lambda/config/serializer/GameProfileSerializer.kt rename to src/main/kotlin/com/lambda/config/serializer/GameProfileCodec.kt index d832e39d1..77fd12889 100644 --- a/src/main/kotlin/com/lambda/config/serializer/GameProfileSerializer.kt +++ b/src/main/kotlin/com/lambda/config/serializer/GameProfileCodec.kt @@ -24,6 +24,8 @@ import com.google.gson.JsonNull import com.google.gson.JsonObject import com.google.gson.JsonSerializationContext import com.google.gson.JsonSerializer +import com.lambda.config.Codec +import com.lambda.config.Stringifiable import com.mojang.authlib.GameProfile import java.lang.reflect.Type import java.util.* @@ -32,26 +34,24 @@ import java.util.* // But who cares, I'm doing it again. // What you gon' do bout it, huh? // That's what I thought. -object GameProfileSerializer : JsonSerializer, JsonDeserializer { +object GameProfileCodec : Codec, Stringifiable { override fun serialize( - src: GameProfile?, + src: GameProfile, typeOfSrc: Type?, context: JsonSerializationContext?, ): JsonElement = - src?.let { - JsonObject().apply { - addProperty("name", it.name) - addProperty("id", it.id.toString()) - } - } ?: JsonNull.INSTANCE + JsonObject().apply { + addProperty("name", src.name) + addProperty("id", src.id.toString()) + } override fun deserialize( - json: JsonElement?, + json: JsonElement, typeOfT: Type?, context: JsonDeserializationContext?, ): GameProfile { - val name = json?.asJsonObject?.get("name")?.asString ?: "nil" - val id = json?.asJsonObject?.get("id")?.asString ?: "00000000-0000-0000-0000-000000000000" + val name = json.asJsonObject.get("name")?.asString ?: "nil" + val id = json.asJsonObject.get("id")?.asString ?: "00000000-0000-0000-0000-000000000000" val parsedId = if (id.length == 32) id.replaceFirst( "(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})".toRegex(), @@ -61,4 +61,6 @@ object GameProfileSerializer : JsonSerializer, JsonDeserializer. + */ + +package com.lambda.config.serializer + +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonElement +import com.google.gson.JsonPrimitive +import com.google.gson.JsonSerializationContext +import com.lambda.config.Codec +import com.lambda.config.Stringifiable +import net.minecraft.item.Item +import net.minecraft.registry.Registries +import net.minecraft.util.Identifier +import java.lang.reflect.Type + +object ItemCodec : Codec, Stringifiable { + override fun serialize( + item: Item, + typeOfSrc: Type, + context: JsonSerializationContext + ): JsonElement = JsonPrimitive(item.toString()) + + override fun deserialize( + json: JsonElement, + typeOfT: Type, + context: JsonDeserializationContext + ): Item = + Registries.ITEM.get(Identifier.of(json.asString)) // Watch out!! Errors are silently catched by gson!! + + override fun stringify(value: Item) = value.name.string.replaceFirstChar { it.uppercase() } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializer/ItemStackSerializer.kt b/src/main/kotlin/com/lambda/config/serializer/ItemStackCodec.kt similarity index 87% rename from src/main/kotlin/com/lambda/config/serializer/ItemStackSerializer.kt rename to src/main/kotlin/com/lambda/config/serializer/ItemStackCodec.kt index 4b7e9e82e..76c3c5624 100644 --- a/src/main/kotlin/com/lambda/config/serializer/ItemStackSerializer.kt +++ b/src/main/kotlin/com/lambda/config/serializer/ItemStackCodec.kt @@ -18,16 +18,16 @@ package com.lambda.config.serializer import com.google.gson.JsonDeserializationContext -import com.google.gson.JsonDeserializer import com.google.gson.JsonElement import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer +import com.lambda.config.Codec +import com.lambda.config.Stringifiable import com.mojang.serialization.JsonOps import net.minecraft.item.ItemStack import java.lang.reflect.Type import kotlin.jvm.optionals.getOrElse -object ItemStackSerializer : JsonSerializer, JsonDeserializer { +object ItemStackCodec : Codec, Stringifiable { override fun serialize( stack: ItemStack, typeOfSrc: Type, @@ -44,4 +44,6 @@ object ItemStackSerializer : JsonSerializer, JsonDeserializer, JsonDeserializer { +object KeyCodeCodec : Codec { override fun serialize( src: KeyCode?, typeOfSrc: Type?, diff --git a/src/main/kotlin/com/lambda/config/serializer/OptionalSerializer.kt b/src/main/kotlin/com/lambda/config/serializer/OptionalCodec.kt similarity index 94% rename from src/main/kotlin/com/lambda/config/serializer/OptionalSerializer.kt rename to src/main/kotlin/com/lambda/config/serializer/OptionalCodec.kt index da3089a1f..413446f89 100644 --- a/src/main/kotlin/com/lambda/config/serializer/OptionalSerializer.kt +++ b/src/main/kotlin/com/lambda/config/serializer/OptionalCodec.kt @@ -23,10 +23,11 @@ import com.google.gson.JsonElement import com.google.gson.JsonNull import com.google.gson.JsonSerializationContext import com.google.gson.JsonSerializer +import com.lambda.config.Codec import java.lang.reflect.Type import java.util.* -object OptionalSerializer : JsonSerializer>, JsonDeserializer> { +object OptionalCodec : Codec> { override fun serialize(src: Optional?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement = src?.map { context?.serialize(it) }?.orElse(JsonNull.INSTANCE) ?: JsonNull.INSTANCE diff --git a/src/main/kotlin/com/lambda/config/settings/collections/ListSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt similarity index 70% rename from src/main/kotlin/com/lambda/config/settings/collections/ListSetting.kt rename to src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt index 9bde358c3..6cdd52e29 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/ListSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt @@ -18,10 +18,10 @@ package com.lambda.config.settings.collections import com.google.gson.JsonElement -import com.google.gson.reflect.TypeToken import com.lambda.Lambda.gson import com.lambda.config.AbstractSetting import com.lambda.config.AutomationConfig +import com.lambda.config.Stringifiable import com.lambda.context.SafeContext import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.threading.runSafe @@ -31,14 +31,15 @@ import java.lang.reflect.Type /** * @see [com.lambda.config.Configurable] */ -class ListSetting( +class CollectionSettings( override var name: String, - private var immutableList: List, - defaultValue: MutableList, + private var immutableCollection: Collection, + defaultValue: MutableCollection, type: Type, description: String, + private val serializer: Stringifiable, visibility: () -> Boolean, -) : AbstractSetting>( +) : AbstractSetting>( name, defaultValue, type, @@ -47,17 +48,15 @@ class ListSetting( ) { private val selectListeners = mutableListOf Unit>() private val deselectListeners = mutableListOf Unit>() - private val strListType = - TypeToken.getParameterized(MutableList::class.java, String::class.java).type override fun ImGuiBuilder.buildLayout() { combo("##$name", "$name: ${value.size} item(s)") { - immutableList + immutableCollection .forEach { val isSelected = value.contains(it) selectable( - it.toString(), isSelected, + serializer.stringify(it), isSelected, flags = DontClosePopups ) { if (isSelected) { @@ -72,18 +71,11 @@ class ListSetting( } } - // When serializing the list to json we do not want to serialize the elements' classes, but - // their stringified representation. - // If we do serialize the classes we'll run into missing type adapters errors by Gson. - override fun toJson(): JsonElement = - gson.toJsonTree(value.map { it.toString() }) + override fun toJson(): JsonElement = gson.toJsonTree(value) override fun loadFromJson(serialized: JsonElement) { - val strList = gson.fromJson>(serialized, strListType) - .mapNotNull { str -> immutableList.find { it.toString() == str } } + value = gson.fromJson>(serialized, type) .toMutableList() - - value = strList } fun onSelect(block: SafeContext.(T) -> Unit) = apply { @@ -97,8 +89,8 @@ class ListSetting( companion object { @AutomationConfig.SettingEditorDsl @Suppress("unchecked_cast") - fun AutomationConfig.TypedEditBuilder>.immutableList(immutableList: List) { - (settings as Collection>).forEach { it.immutableList = immutableList } + fun AutomationConfig.TypedEditBuilder>.immutableCollection(collection: Collection) { + (settings as Collection>).forEach { it.immutableCollection = collection } } } } diff --git a/src/main/kotlin/com/lambda/config/settings/collections/SetSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/SetSetting.kt deleted file mode 100644 index de93b5958..000000000 --- a/src/main/kotlin/com/lambda/config/settings/collections/SetSetting.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 . - */ - -package com.lambda.config.settings.collections - -import com.google.gson.JsonElement -import com.google.gson.reflect.TypeToken -import com.lambda.Lambda.gson -import com.lambda.config.AbstractSetting -import com.lambda.config.AutomationConfig -import com.lambda.context.SafeContext -import com.lambda.gui.dsl.ImGuiBuilder -import com.lambda.threading.runSafe -import imgui.flag.ImGuiSelectableFlags.DontClosePopups -import java.lang.reflect.Type - -/** - * @see [com.lambda.config.Configurable] - */ -class SetSetting( - override var name: String, - private var immutableSet: Set, - defaultValue: MutableSet, - type: Type, - description: String, - visibility: () -> Boolean, -) : AbstractSetting>( - name, - defaultValue, - type, - description, - visibility -) { - private val selectListeners = mutableListOf Unit>() - private val deselectListeners = mutableListOf Unit>() - private val strSetType = - TypeToken.getParameterized(Set::class.java, String::class.java).type - - override fun ImGuiBuilder.buildLayout() { - combo("##$name", "$name: ${value.size} item(s)") { - immutableSet - .forEach { - val isSelected = value.contains(it) - - selectable( - it.toString(), isSelected, - flags = DontClosePopups - ) { - if (isSelected) { - value.remove(it) - runSafe { deselectListeners.forEach { listener -> listener(it) } } - } else { - value.add(it) - runSafe { selectListeners.forEach { listener -> listener(it) } } - } - } - } - } - } - - // When serializing the list to json we do not want to serialize the elements' classes, but - // their stringified representation. - // If we do serialize the classes we'll run into missing type adapters errors by Gson. - override fun toJson(): JsonElement = - gson.toJsonTree(value.map { it.toString() }) - - override fun loadFromJson(serialized: JsonElement) { - val strSet = gson.fromJson>(serialized, strSetType) - .mapNotNull { str -> immutableSet.find { it.toString() == str } } - .toMutableSet() - - value = strSet - } - - fun onSelect(block: SafeContext.(T) -> Unit) = apply { - selectListeners.add(block) - } - - fun onDeselect(block: SafeContext.(T) -> Unit) = apply { - deselectListeners.add(block) - } - - companion object { - @AutomationConfig.SettingEditorDsl - @Suppress("unchecked_cast") - fun AutomationConfig.TypedEditBuilder>.immutableSet(immutableSet: Set) { - (settings as Collection>).forEach { it.immutableSet = immutableSet } - } - } -} diff --git a/src/main/kotlin/com/lambda/friend/FriendManager.kt b/src/main/kotlin/com/lambda/friend/FriendManager.kt index 5c13e6010..b916b557f 100644 --- a/src/main/kotlin/com/lambda/friend/FriendManager.kt +++ b/src/main/kotlin/com/lambda/friend/FriendManager.kt @@ -19,6 +19,7 @@ package com.lambda.friend import com.lambda.config.Configurable import com.lambda.config.configurations.FriendConfig +import com.lambda.config.serializer.GameProfileCodec import com.lambda.core.Loadable import com.lambda.util.text.ClickEvents import com.lambda.util.text.buildText @@ -41,7 +42,7 @@ import java.util.* // - Improve save file structure. object FriendManager : Configurable(FriendConfig), Loadable { override val name = "friends" - val friends by setting("friends", emptySet(), setOf()) + val friends by setting("friends", emptySet(), setOf(), serializer = GameProfileCodec) fun befriend(profile: GameProfile) = friends.add(profile) fun unfriend(profile: GameProfile): Boolean = friends.remove(profile) diff --git a/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt b/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt index 16275ef85..39a19de60 100644 --- a/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt +++ b/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt @@ -26,6 +26,8 @@ import com.lambda.config.configurations.LambdaConfig import com.lambda.config.groups.RotationSettings import com.lambda.context.Automated import com.lambda.config.AutomationConfig +import com.lambda.config.serializer.BlockCodec +import com.lambda.config.serializer.ItemCodec import com.lambda.util.BlockUtils.blockPos import com.lambda.util.NamedEnum @@ -171,7 +173,7 @@ object BaritoneManager : Configurable(LambdaConfig), Automated by AutomationConf setting("Sprint In Water", sprintInWater.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> sprintInWater.value = it } setting("Allow Break", allowBreak.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowBreak.value = it } - setting("Allow Break Anyway", allowBreakAnyway.value.toSet()).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowBreakAnyway.value = it.toList() } + setting("Allow Break Anyway", allowBreakAnyway.value, serializer = BlockCodec).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowBreakAnyway.value = it.toList() } setting("Allow Sprint", allowSprint.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowSprint.value = it } setting("Allow Place", allowPlace.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowPlace.value = it } setting("Allow Place In Fluids Source", allowPlaceInFluidsSource.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowPlaceInFluidsSource.value = it } @@ -262,18 +264,19 @@ object BaritoneManager : Configurable(LambdaConfig), Automated by AutomationConf setting("Schematic Fallback Extension", schematicFallbackExtension.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> schematicFallbackExtension.value = it } setting("Builder Tick Scan Radius", builderTickScanRadius.value, 0..64).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> builderTickScanRadius.value = it } - setting("Acceptable Throwaway Items", acceptableThrowawayItems.value.toSet()).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> acceptableThrowawayItems.value = it.toList() } - setting("Blocks To Avoid", blocksToAvoid.value.toSet()).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoid.value = it.toList() } - setting("Blocks To Disallow Breaking", blocksToDisallowBreaking.value.toSet()).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToDisallowBreaking.value = it.toList() } - setting("Blocks To Avoid Breaking", blocksToAvoidBreaking.value.toSet()).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoidBreaking.value = it.toList() } - setting("Build Ignore Blocks", buildIgnoreBlocks.value.toSet()).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreBlocks.value = it.toList() } - setting("Build Skip Blocks", buildSkipBlocks.value.toSet()).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSkipBlocks.value = it.toList() } - setting("Build Valid Substitutes", buildValidSubstitutes.value.mapValues { (_, v) -> v.toSet() }).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildValidSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } - setting("Build Substitutes", buildSubstitutes.value.mapValues { (_, v) -> v.toSet() }).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } - setting("Ok If Air", okIfAir.value.toSet()).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> okIfAir.value = it.toList() } + setting("Acceptable Throwaway Items", acceptableThrowawayItems.value, serializer = ItemCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> acceptableThrowawayItems.value = it.toList() } + setting("Blocks To Avoid", blocksToAvoid.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoid.value = it.toList() } + setting("Blocks To Disallow Breaking", blocksToDisallowBreaking.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToDisallowBreaking.value = it.toList() } + setting("Blocks To Avoid Breaking", blocksToAvoidBreaking.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoidBreaking.value = it.toList() } + setting("Build Ignore Blocks", buildIgnoreBlocks.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreBlocks.value = it.toList() } + setting("Build Skip Blocks", buildSkipBlocks.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSkipBlocks.value = it.toList() } + // FixMe: lmao fuck this im so done + //setting("Build Valid Substitutes", buildValidSubstitutes.value.flatMap { it.value }, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildValidSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } + //setting("Build Substitutes", buildSubstitutes.value.flatMap { it.value }, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } + setting("Ok If Air", okIfAir.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> okIfAir.value = it.toList() } setting("Build Ignore Existing", buildIgnoreExisting.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreExisting.value = it } setting("Build Ignore Direction", buildIgnoreDirection.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreDirection.value = it } - setting("Build Ignore Properties", buildIgnoreProperties.value.toSet()).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreProperties.value = it.toList() } + setting("Build Ignore Properties", buildIgnoreProperties.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreProperties.value = it.toList() } setting("Avoid Updating Falling Blocks", avoidUpdatingFallingBlocks.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> avoidUpdatingFallingBlocks.value = it } // RENDERING diff --git a/src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt b/src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt index 4ef59c17e..3642d133b 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt @@ -79,7 +79,7 @@ sealed class TargetState(val type: Type) : StateMatcher { override fun isEmpty() = true } - data class Solid(val replace: Set) : TargetState(Type.Solid) { + data class Solid(val replace: Collection) : TargetState(Type.Solid) { override fun toString() = "Solid" context(safeContext: SafeContext) diff --git a/src/main/kotlin/com/lambda/interaction/request/Request.kt b/src/main/kotlin/com/lambda/interaction/request/Request.kt index ba61c3c54..a010af841 100644 --- a/src/main/kotlin/com/lambda/interaction/request/Request.kt +++ b/src/main/kotlin/com/lambda/interaction/request/Request.kt @@ -31,7 +31,7 @@ abstract class Request : Automated { abstract val requestId: Int var fresh = true - abstract val tickStageMask: Set + abstract val tickStageMask: Collection abstract val nowOrNothing: Boolean abstract val done: Boolean diff --git a/src/main/kotlin/com/lambda/interaction/request/breaking/BreakConfig.kt b/src/main/kotlin/com/lambda/interaction/request/breaking/BreakConfig.kt index a4425c4e4..ee5987e91 100644 --- a/src/main/kotlin/com/lambda/interaction/request/breaking/BreakConfig.kt +++ b/src/main/kotlin/com/lambda/interaction/request/breaking/BreakConfig.kt @@ -51,7 +51,7 @@ interface BreakConfig : ActionConfig { val avoidLiquids: Boolean val avoidSupporting: Boolean - val ignoredBlocks: Set + val ignoredBlocks: Collection val efficientOnly: Boolean val suitableToolsOnly: Boolean diff --git a/src/main/kotlin/com/lambda/interaction/request/hotbar/HotbarConfig.kt b/src/main/kotlin/com/lambda/interaction/request/hotbar/HotbarConfig.kt index 2541397de..e3fca1383 100644 --- a/src/main/kotlin/com/lambda/interaction/request/hotbar/HotbarConfig.kt +++ b/src/main/kotlin/com/lambda/interaction/request/hotbar/HotbarConfig.kt @@ -53,5 +53,5 @@ interface HotbarConfig { /** * The sub-tick timings at which hotbar actions can be performed */ - val tickStageMask: Set + val tickStageMask: Collection } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/interaction/request/inventory/InventoryConfig.kt b/src/main/kotlin/com/lambda/interaction/request/inventory/InventoryConfig.kt index 2d03d437c..fcc7662bd 100644 --- a/src/main/kotlin/com/lambda/interaction/request/inventory/InventoryConfig.kt +++ b/src/main/kotlin/com/lambda/interaction/request/inventory/InventoryConfig.kt @@ -27,8 +27,8 @@ import net.minecraft.block.Block interface InventoryConfig { val actionsPerSecond: Int - val tickStageMask: Set - val disposables: Set + val tickStageMask: Collection + val disposables: Collection val swapWithDisposables: Boolean val providerPriority: Priority val storePriority: Priority diff --git a/src/main/kotlin/com/lambda/module/modules/debug/SettingTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/SettingTest.kt deleted file mode 100644 index 5d76c1634..000000000 --- a/src/main/kotlin/com/lambda/module/modules/debug/SettingTest.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 . - */ - -package com.lambda.module.modules.debug - -import com.lambda.module.Module -import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.info -import com.lambda.util.KeyCode -import com.lambda.util.NamedEnum -import net.minecraft.block.Blocks -import net.minecraft.util.math.BlockPos -import java.awt.Color - -object SettingTest : Module( - name = "SettingTest", - tag = ModuleTag.DEBUG, -) { - private enum class Group(override val displayName: String) : NamedEnum { - Generic("Generic"), - Numeric("Numeric"), - Collections("Collections"), - Complex("Complex"), - Functional("Functional"), - } - - private enum class SubGroup(override val displayName: String) : NamedEnum { - Foo("Foo"), - Bar("Bar") - } - - // CharSetting - private val charSetting by setting("Character Setting", 'A').group(Group.Generic) - - // String - private val stringSetting by setting("String Setting", "Default String").group(Group.Generic, SubGroup.Foo) - - // Comparable - private val booleanSetting by setting("Boolean Setting", true).group(Group.Generic, SubGroup.Bar) - private val enumSetting by setting("Enum Setting", ExampleEnum.ValueOne).group(Group.Generic) - - // Numeric - private val doubleSetting by setting("Double Setting", 3.14159, 0.0..100.0, 0.1, description = "Changes the crumbs count", unit = " crumbs").group(Group.Numeric) - private val floatSetting by setting("Float Setting", 3.14f, 0.0f..100.0f, 0.1f, unit = " pies").group(Group.Numeric) - private val integerSetting by setting("Integer Setting", 42, 0..1000, unit = " apples").group(Group.Numeric) - private val longSetting by setting("Long Setting", 100000L, 0L..1000000L, 1000L, unit = " pizzas").group(Group.Numeric) - - // Collections - private val stringList by setting("String List", listOf("Hello", "World"), listOf("Hello", "World")).group(Group.Collections) - private val stringSet by setting("String Set", setOf("Apple", "Banana"), setOf("Apple", "Banana")).group(Group.Collections) - private val stringMap by setting("String Map", mapOf("Key1" to "Value1", "Key2" to "Value2")).group(Group.Collections) - - // Complex - private val blockPosSetting by setting("Block Position", BlockPos(0, 0, 0)).group(Group.Complex) - private val blockSetting by setting("Block Setting", Blocks.OBSIDIAN).group(Group.Complex) - private val colorSetting by setting("Color Setting", Color.GREEN).group(Group.Complex) - private val keybindSettingTest by setting("Key Bind Setting", KeyCode.T).group(Group.Complex) - - // Complex collections - private val blockPosSet by setting("Block Position Set", setOf(BlockPos(0, 0, 0)), setOf(BlockPos(0, 0, 0))).group(Group.Complex) - private val blockList by setting("Block List", listOf(Blocks.OBSIDIAN), listOf(Blocks.OBSIDIAN)).group(Group.Complex) - private val colorMap by setting("Color Map", mapOf("Primary" to Color.GREEN)).group(Group.Complex) - private val keybindSet by setting("Key Bind Set", setOf(KeyCode.T), setOf(KeyCode.T)).group(Group.Complex) - - // Other - private val unitSetting by setting("Unit Test", { this@SettingTest.info("Unit setting") }).group(Group.Functional) - - enum class ExampleEnum { - ValueOne, - ValueTwo, - ValueThree - } -} diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 17c06980b..58f328b44 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -21,7 +21,6 @@ import com.lambda.config.AutomationConfig.Companion.DEFAULT.edit import com.lambda.config.AutomationConfig.Companion.DEFAULT.hideAll import com.lambda.config.groups.HotbarSettings import com.lambda.config.groups.InventorySettings -import com.lambda.config.settings.collections.SetSetting.Companion.immutableSet import com.lambda.config.settings.complex.Bind import com.lambda.context.SafeContext import com.lambda.event.events.KeyboardEvent @@ -63,12 +62,14 @@ object BetterFirework : Module( override val hotbarConfig = HotbarSettings(this, Group.Hotbar).apply { hideAll(this) - ::tickStageMask.edit { immutableSet(setOf(TickEvent.Pre)); defaultValue(mutableSetOf(TickEvent.Pre)) } + // FixMe: Bring this back + ::tickStageMask.edit { /*immutableCollection(setOf(TickEvent.Pre));*/ defaultValue(mutableSetOf(TickEvent.Pre)) } } override val inventoryConfig = InventorySettings(this, Group.Inventory).apply { hideAll(this) - ::tickStageMask.edit { immutableSet(setOf(TickEvent.Pre)); defaultValue(mutableSetOf(TickEvent.Pre)) } + // FixMe: Bring this back + ::tickStageMask.edit { /*immutableCollection(setOf(TickEvent.Pre));*/ defaultValue(mutableSetOf(TickEvent.Pre)) } } private enum class Group(override val displayName: String) : NamedEnum { diff --git a/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt b/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt index db575fc9f..fa5010fc2 100644 --- a/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt +++ b/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt @@ -53,7 +53,7 @@ object PacketLimiter : Module( ) // ToDo: Find a way to have a list of serverbound packets - private val ignorePackets by setting("Ignore Packets", defaultIgnorePackets, defaultIgnorePackets, "Packets to ignore when limiting") + private val ignorePackets by setting("Ignore Packets", defaultIgnorePackets, description = "Packets to ignore when limiting") init { onEnable { diff --git a/src/main/kotlin/com/lambda/module/modules/network/PacketLogger.kt b/src/main/kotlin/com/lambda/module/modules/network/PacketLogger.kt index 0e862af78..b4b8519bd 100644 --- a/src/main/kotlin/com/lambda/module/modules/network/PacketLogger.kt +++ b/src/main/kotlin/com/lambda/module/modules/network/PacketLogger.kt @@ -17,6 +17,7 @@ package com.lambda.module.modules.network +import com.google.gson.JsonPrimitive import com.lambda.Lambda import com.lambda.Lambda.mc import com.lambda.event.events.PacketEvent @@ -32,6 +33,7 @@ import com.lambda.util.DynamicReflectionSerializer.dynamicString import com.lambda.util.FolderRegister import com.lambda.util.FolderRegister.relativeMCPath import com.lambda.util.Formatting.getTime +import com.lambda.util.reflections.getInstances import com.lambda.util.text.ClickEvents import com.lambda.util.text.buildText import com.lambda.util.text.clickEvent @@ -58,8 +60,11 @@ object PacketLogger : Module( private val networkSide by setting("Network Side", NetworkSide.Any, "Side of the network to log packets from") private val logTicks by setting("Log Ticks", true, "Show game ticks in the log") private val scope by setting("Scope", Scope.Any, "Scope of packets to log") - private val whitelist by setting("Whitelist Packets", emptyList(), emptyList(), "Packets to whitelist") { scope == Scope.Whitelist } - private val blacklist by setting("Blacklist Packets", emptyList(), emptyList(), "Packets to blacklist") { scope == Scope.Blacklist } + + val packetList = getInstances> { println(it.moduleInfo.location); true } + // ToDo: Add a packet list + //private val whitelist by setting("Whitelist Packets", emptyList(), emptyList(), "Packets to whitelist", { JsonPrimitive(it) }, { it.asString }) { scope == Scope.Whitelist } + //private val blacklist by setting("Blacklist Packets", emptyList(), emptyList(), "Packets to blacklist", { JsonPrimitive(it) }, { it.asString }) { scope == Scope.Blacklist } private val maxRecursionDepth by setting("Max Recursion Depth", 6, 1..10, 1, "Maximum recursion depth for packet serialization") private val logConcurrent by setting("Build Data Concurrent", false, "Whether to serialize packets concurrently. Will not save packets in chronological order but wont lag the game.") @@ -79,8 +84,8 @@ object PacketLogger : Module( fun shouldLog(packet: Packet<*>) = when (this) { Any -> true - Whitelist -> packet::class.simpleName in whitelist - Blacklist -> packet::class.simpleName !in blacklist + Whitelist -> false//packet::class.simpleName in whitelist + Blacklist -> false//packet::class.simpleName !in blacklist } } diff --git a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt index 6cc826950..baae427d6 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt @@ -18,6 +18,7 @@ package com.lambda.module.modules.render import com.lambda.Lambda.mc +import com.lambda.config.serializer.BlockCodec import com.lambda.context.SafeContext import com.lambda.graphics.renderer.esp.ChunkedESP.Companion.newChunkedESP import com.lambda.graphics.renderer.esp.DirectionMask @@ -42,7 +43,7 @@ object BlockESP : Module( ) { // ToDo: Toggle searching, solve memory leak private val searchBlocks by setting("Search Blocks", true, "Search for blocks around the player") - private val blocks by setting("Blocks", setOf(Blocks.BEDROCK), setOf(Blocks.BEDROCK), "Render blocks") { searchBlocks }.onValueChange(::rebuildMesh) + private val blocks by setting("Blocks", setOf(Blocks.BEDROCK), setOf(Blocks.BEDROCK), "Render blocks", BlockCodec) { searchBlocks }.onValueChange(::rebuildMesh) private var drawFaces: Boolean by setting("Draw Faces", true, "Draw faces of blocks") { searchBlocks }.onValueChange(::rebuildMesh).onValueChange { _, to -> if (!to) drawOutlines = true } private var drawOutlines: Boolean by setting("Draw Outlines", true, "Draw outlines of blocks") { searchBlocks }.onValueChange(::rebuildMesh).onValueChange { _, to -> if (!to) drawFaces = true } private val mesh by setting("Mesh", true, "Connect similar adjacent blocks") { searchBlocks }.onValueChange(::rebuildMesh) From 29b2a77342fd61d35c9c1a73f1d5bad6685651dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emy=20=F0=9F=92=9C?= Date: Sun, 30 Nov 2025 14:26:25 -0500 Subject: [PATCH 2/8] Open collection settings for typed collections --- .../kotlin/com/lambda/config/Configurable.kt | 38 ++++++---- .../kotlin/com/lambda/config/Configuration.kt | 2 +- .../com/lambda/config/UserAutomationConfig.kt | 4 +- .../com/lambda/config/groups/EatSettings.kt | 9 ++- .../lambda/config/groups/InventorySettings.kt | 2 +- .../collections/BlockCollectionSetting.kt | 70 +++++++++++++++++++ .../collections/CollectionSettings.kt | 39 ++++------- .../collections/ItemCollectionSetting.kt | 70 +++++++++++++++++++ .../kotlin/com/lambda/friend/FriendManager.kt | 2 +- .../kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt | 8 ++- .../com/lambda/interaction/BaritoneManager.kt | 20 +++--- .../lambda/module/modules/render/BlockESP.kt | 2 +- .../com/lambda/module/modules/render/XRay.kt | 2 +- 13 files changed, 206 insertions(+), 62 deletions(-) create mode 100644 src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt create mode 100644 src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt diff --git a/src/main/kotlin/com/lambda/config/Configurable.kt b/src/main/kotlin/com/lambda/config/Configurable.kt index bfa58fe53..4ccb5b9e0 100644 --- a/src/main/kotlin/com/lambda/config/Configurable.kt +++ b/src/main/kotlin/com/lambda/config/Configurable.kt @@ -24,7 +24,9 @@ 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.BlockCollectionSetting import com.lambda.config.settings.collections.CollectionSettings +import com.lambda.config.settings.collections.ItemCollectionSetting import com.lambda.config.settings.collections.MapSetting import com.lambda.config.settings.comparable.BooleanSetting import com.lambda.config.settings.comparable.EnumSetting @@ -43,6 +45,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 @@ -122,20 +126,30 @@ abstract class Configurable( visibility: () -> Boolean = { true }, ) = StringSetting(name, defaultValue, multiline, flags, description, visibility).register() - inline fun setting( - name: String, - immutableList: Collection, - defaultValue: Collection = immutableList, - description: String = "", - serializer: Stringifiable, - noinline visibility: () -> Boolean = { true }, - ) = CollectionSettings( + + fun setting( + name: String, + defaultValue: Collection, + description: String = "", + visibility: () -> Boolean = { true }, + ) = BlockCollectionSetting( name, - immutableList, + Registries.BLOCK.toList(), + defaultValue.toMutableList(), + description, + visibility, + ).register() + + fun setting( + name: String, + defaultValue: Collection, + description: String = "", + visibility: () -> Boolean = { true }, + ) = ItemCollectionSetting( + name, + Registries.ITEM.toList(), defaultValue.toMutableList(), - TypeToken.getParameterized(MutableList::class.java, T::class.java).type, description, - serializer, visibility, ).register() @@ -144,7 +158,6 @@ abstract class Configurable( immutableList: Collection, defaultValue: Collection = immutableList, description: String = "", - crossinline serializer: (T) -> String = { if (it::class.java.isPrimitive) it.toString() else it::class.java.simpleName }, noinline visibility: () -> Boolean = { true }, ) = CollectionSettings( name, @@ -152,7 +165,6 @@ abstract class Configurable( defaultValue.toMutableList(), TypeToken.getParameterized(Collection::class.java, T::class.java).type, description, - object : Stringifiable { override fun stringify(value: T) = serializer(value) }, visibility, ).register() diff --git a/src/main/kotlin/com/lambda/config/Configuration.kt b/src/main/kotlin/com/lambda/config/Configuration.kt index a668e4580..5dd784ad9 100644 --- a/src/main/kotlin/com/lambda/config/Configuration.kt +++ b/src/main/kotlin/com/lambda/config/Configuration.kt @@ -100,7 +100,7 @@ abstract class Configuration : Jsonable, Loadable { private fun save() = runCatching { primary.createIfNotExists() .let { - it.writeText(gson.toJson(toJson())) + it.writeText(toJson().toString()) it.copyTo(backup, true) } } diff --git a/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt b/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt index 0c86b46a6..31c34b7c3 100644 --- a/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt +++ b/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt @@ -18,12 +18,10 @@ package com.lambda.config import com.lambda.config.configurations.UserAutomationConfigs -import com.lambda.config.serializer.ItemCodec -import com.lambda.module.Module 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(), serializer = { it }) + val linkedModules = setting("Linked Modules", moduleNameMap.filter { it.value.defaultAutomationConfig != Companion.DEFAULT }.keys, emptySet()) .onSelect { module -> moduleNameMap[module]?.automationConfig = this@UserAutomationConfig } .onDeselect { module -> moduleNameMap[module]?.let { module -> diff --git a/src/main/kotlin/com/lambda/config/groups/EatSettings.kt b/src/main/kotlin/com/lambda/config/groups/EatSettings.kt index 6696edf9d..3f21ea757 100644 --- a/src/main/kotlin/com/lambda/config/groups/EatSettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/EatSettings.kt @@ -19,7 +19,6 @@ package com.lambda.config.groups import com.lambda.config.Configurable import com.lambda.config.SettingGroup -import com.lambda.config.serializer.ItemCodec import com.lambda.util.NamedEnum import net.minecraft.item.Item import net.minecraft.item.Items @@ -36,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", ItemCodec) { 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", ItemCodec) { 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", ItemCodec) { 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", ItemCodec) { ignoreBadFood }.group(baseGroup).index() + override val badFood by c.setting("Bad Food", negativeFoodDefaults, description = "Items that are considered bad food") { ignoreBadFood }.group(baseGroup).index() } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt b/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt index 2b6f30753..f6f911bf9 100644 --- a/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt @@ -36,7 +36,7 @@ class InventorySettings( 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() 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() - 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() + 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() override val swapWithDisposables by c.setting("Swap With Disposables", true, "Swap items with disposable ones").group(baseGroup, Group.Container).index() 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() 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() diff --git a/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt new file mode 100644 index 000000000..51ba6cc6c --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt @@ -0,0 +1,70 @@ +/* + * 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 . + */ + +package com.lambda.config.settings.collections + +import com.lambda.config.serializer.BlockCodec +import com.lambda.gui.dsl.ImGuiBuilder +import imgui.flag.ImGuiSelectableFlags.DontClosePopups +import net.minecraft.block.Block + +class BlockCollectionSetting( + override var name: String, + private val immutableCollection: Collection, + defaultValue: MutableCollection, + description: String, + visibility: () -> Boolean, +) : CollectionSettings( + name, + immutableCollection, + defaultValue, + Block::class.java, + description, + visibility, +) { + override fun ImGuiBuilder.buildLayout() { + val text = if (value.size == 1) "block" else "blocks" + + combo("##$name", "$name: ${value.size} $text") { + value.toMutableList() // Copy the list instead of iterating the immutable one + .forEach { + selectable( + label = BlockCodec.stringify(it), + selected = true, + flags = DontClosePopups + ) { value.remove(it) } + } + } + + button("Add") { openPopup("Blocks") } + + popup("Blocks") { + filter("Search for blocks") { filter -> + immutableCollection + .filter { + //filter.inputBuffer.levenshteinDistance(ItemCodec.stringify(it)) < 3 && + !value.contains(it) + } + .forEach { + text(BlockCodec.stringify(it)) + sameLine() + button("Add") { value.add(it) } + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt index 6cdd52e29..bfcde0f1f 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt @@ -21,23 +21,20 @@ import com.google.gson.JsonElement import com.lambda.Lambda.gson import com.lambda.config.AbstractSetting import com.lambda.config.AutomationConfig -import com.lambda.config.Stringifiable import com.lambda.context.SafeContext import com.lambda.gui.dsl.ImGuiBuilder -import com.lambda.threading.runSafe import imgui.flag.ImGuiSelectableFlags.DontClosePopups import java.lang.reflect.Type /** * @see [com.lambda.config.Configurable] */ -class CollectionSettings( +open class CollectionSettings( override var name: String, private var immutableCollection: Collection, defaultValue: MutableCollection, type: Type, description: String, - private val serializer: Stringifiable, visibility: () -> Boolean, ) : AbstractSetting>( name, @@ -49,6 +46,14 @@ class CollectionSettings( private val selectListeners = mutableListOf Unit>() private val deselectListeners = mutableListOf Unit>() + fun onSelect(block: SafeContext.(T) -> Unit) = apply { + selectListeners.add(block) + } + + fun onDeselect(block: SafeContext.(T) -> Unit) = apply { + deselectListeners.add(block) + } + override fun ImGuiBuilder.buildLayout() { combo("##$name", "$name: ${value.size} item(s)") { immutableCollection @@ -56,36 +61,22 @@ class CollectionSettings( val isSelected = value.contains(it) selectable( - serializer.stringify(it), isSelected, - flags = DontClosePopups + label = it.toString(), + selected = isSelected, + flags = DontClosePopups, ) { - if (isSelected) { - value.remove(it) - runSafe { deselectListeners.forEach { listener -> listener(it) } } - } else { - value.add(it) - runSafe { selectListeners.forEach { listener -> listener(it) } } - } + if (isSelected) value.remove(it) + else value.add(it) } } } } - override fun toJson(): JsonElement = gson.toJsonTree(value) - override fun loadFromJson(serialized: JsonElement) { - value = gson.fromJson>(serialized, type) + value = gson.fromJson>(serialized, type) .toMutableList() } - fun onSelect(block: SafeContext.(T) -> Unit) = apply { - selectListeners.add(block) - } - - fun onDeselect(block: SafeContext.(T) -> Unit) = apply { - deselectListeners.add(block) - } - companion object { @AutomationConfig.SettingEditorDsl @Suppress("unchecked_cast") diff --git a/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt new file mode 100644 index 000000000..a82a3aebd --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt @@ -0,0 +1,70 @@ +/* + * 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 . + */ + +package com.lambda.config.settings.collections + +import com.lambda.config.serializer.ItemCodec +import com.lambda.gui.dsl.ImGuiBuilder +import imgui.flag.ImGuiSelectableFlags.DontClosePopups +import net.minecraft.item.Item + +class ItemCollectionSetting( + override var name: String, + private val immutableCollection: Collection, + defaultValue: MutableCollection, + description: String, + visibility: () -> Boolean, +) : CollectionSettings( + name, + immutableCollection, + defaultValue, + Item::class.java, + description, + visibility, +) { + override fun ImGuiBuilder.buildLayout() { + val text = if (value.size == 1) "item" else "items" + + combo("##$name", "$name: ${value.size} $text") { + value.toMutableList() // Copy the list instead of iterating the immutable one + .forEach { + selectable( + label = ItemCodec.stringify(it), + selected = true, + flags = DontClosePopups + ) { value.remove(it) } + } + } + + button("Add") { openPopup("Items") } + + popup("Items") { + filter("Search for items") { filter -> + immutableCollection + .filter { + //filter.inputBuffer.levenshteinDistance(ItemCodec.stringify(it)) < 3 && + !value.contains(it) + } + .forEach { + text(ItemCodec.stringify(it)) + sameLine() + button("Add") { value.add(it) } + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/friend/FriendManager.kt b/src/main/kotlin/com/lambda/friend/FriendManager.kt index b916b557f..38c9c9f03 100644 --- a/src/main/kotlin/com/lambda/friend/FriendManager.kt +++ b/src/main/kotlin/com/lambda/friend/FriendManager.kt @@ -42,7 +42,7 @@ import java.util.* // - Improve save file structure. object FriendManager : Configurable(FriendConfig), Loadable { override val name = "friends" - val friends by setting("friends", emptySet(), setOf(), serializer = GameProfileCodec) + val friends by setting("friends", emptySet()) fun befriend(profile: GameProfile) = friends.add(profile) fun unfriend(profile: GameProfile): Boolean = friends.remove(profile) diff --git a/src/main/kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt b/src/main/kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt index 2b987c981..ae3049c34 100644 --- a/src/main/kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt +++ b/src/main/kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt @@ -1583,15 +1583,19 @@ object ImGuiBuilder { lambdaTooltip(description()) } + @ImGuiDsl + fun openPopup(strId: String, flags: Int = ImGuiPopupFlags.None) = + ImGui.openPopup(strId, flags) + /** - * Creates a popup. + * Creates a popup. You must first call [openPopup] with the same [strId] * * @param strId Unique identifier * @param flags Popup flags * @param block Content of the popup */ @ImGuiDsl - inline fun popup(strId: String, flags: Int = ImGuiPopupFlags.None, block: ProcedureBlock) { + inline fun popup(strId: String, flags: Int = ImGuiPopupFlags.AnyPopup, block: ProcedureBlock) { if (beginPopup(strId, flags)) { block() endPopup() diff --git a/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt b/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt index 39a19de60..e1a892335 100644 --- a/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt +++ b/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt @@ -173,7 +173,7 @@ object BaritoneManager : Configurable(LambdaConfig), Automated by AutomationConf setting("Sprint In Water", sprintInWater.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> sprintInWater.value = it } setting("Allow Break", allowBreak.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowBreak.value = it } - setting("Allow Break Anyway", allowBreakAnyway.value, serializer = BlockCodec).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowBreakAnyway.value = it.toList() } + setting("Allow Break Anyway", allowBreakAnyway.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowBreakAnyway.value = it.toList() } setting("Allow Sprint", allowSprint.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowSprint.value = it } setting("Allow Place", allowPlace.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowPlace.value = it } setting("Allow Place In Fluids Source", allowPlaceInFluidsSource.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowPlaceInFluidsSource.value = it } @@ -264,16 +264,16 @@ object BaritoneManager : Configurable(LambdaConfig), Automated by AutomationConf setting("Schematic Fallback Extension", schematicFallbackExtension.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> schematicFallbackExtension.value = it } setting("Builder Tick Scan Radius", builderTickScanRadius.value, 0..64).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> builderTickScanRadius.value = it } - setting("Acceptable Throwaway Items", acceptableThrowawayItems.value, serializer = ItemCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> acceptableThrowawayItems.value = it.toList() } - setting("Blocks To Avoid", blocksToAvoid.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoid.value = it.toList() } - setting("Blocks To Disallow Breaking", blocksToDisallowBreaking.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToDisallowBreaking.value = it.toList() } - setting("Blocks To Avoid Breaking", blocksToAvoidBreaking.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoidBreaking.value = it.toList() } - setting("Build Ignore Blocks", buildIgnoreBlocks.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreBlocks.value = it.toList() } - setting("Build Skip Blocks", buildSkipBlocks.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSkipBlocks.value = it.toList() } + setting("Acceptable Throwaway Items", acceptableThrowawayItems.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> acceptableThrowawayItems.value = it.toList() } + setting("Blocks To Avoid", blocksToAvoid.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoid.value = it.toList() } + setting("Blocks To Disallow Breaking", blocksToDisallowBreaking.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToDisallowBreaking.value = it.toList() } + setting("Blocks To Avoid Breaking", blocksToAvoidBreaking.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoidBreaking.value = it.toList() } + setting("Build Ignore Blocks", buildIgnoreBlocks.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreBlocks.value = it.toList() } + setting("Build Skip Blocks", buildSkipBlocks.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSkipBlocks.value = it.toList() } // FixMe: lmao fuck this im so done - //setting("Build Valid Substitutes", buildValidSubstitutes.value.flatMap { it.value }, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildValidSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } - //setting("Build Substitutes", buildSubstitutes.value.flatMap { it.value }, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } - setting("Ok If Air", okIfAir.value, serializer = BlockCodec).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> okIfAir.value = it.toList() } + //setting("Build Valid Substitutes", buildValidSubstitutes.value.flatMap { it.value }).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildValidSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } + //setting("Build Substitutes", buildSubstitutes.value.flatMap { it.value }).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } + setting("Ok If Air", okIfAir.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> okIfAir.value = it.toList() } setting("Build Ignore Existing", buildIgnoreExisting.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreExisting.value = it } setting("Build Ignore Direction", buildIgnoreDirection.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreDirection.value = it } setting("Build Ignore Properties", buildIgnoreProperties.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreProperties.value = it.toList() } diff --git a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt index baae427d6..d58be2c9b 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt @@ -43,7 +43,7 @@ object BlockESP : Module( ) { // ToDo: Toggle searching, solve memory leak private val searchBlocks by setting("Search Blocks", true, "Search for blocks around the player") - private val blocks by setting("Blocks", setOf(Blocks.BEDROCK), setOf(Blocks.BEDROCK), "Render blocks", BlockCodec) { searchBlocks }.onValueChange(::rebuildMesh) + private val blocks by setting("Blocks", setOf(Blocks.BEDROCK), description = "Render blocks") { searchBlocks }.onValueChange(::rebuildMesh) private var drawFaces: Boolean by setting("Draw Faces", true, "Draw faces of blocks") { searchBlocks }.onValueChange(::rebuildMesh).onValueChange { _, to -> if (!to) drawOutlines = true } private var drawOutlines: Boolean by setting("Draw Outlines", true, "Draw outlines of blocks") { searchBlocks }.onValueChange(::rebuildMesh).onValueChange { _, to -> if (!to) drawFaces = true } private val mesh by setting("Mesh", true, "Connect similar adjacent blocks") { searchBlocks }.onValueChange(::rebuildMesh) diff --git a/src/main/kotlin/com/lambda/module/modules/render/XRay.kt b/src/main/kotlin/com/lambda/module/modules/render/XRay.kt index be52e5208..08d90d0f3 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/XRay.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/XRay.kt @@ -44,7 +44,7 @@ object XRay : Module( val opacity by setting("Opacity", 40, 0..100, 1, "Opacity of the non x-rayed blocks, (automatically overridden as 0 when running Sodium)") .onValueChange { _, _ -> if (isEnabled) mc.worldRenderer.reload() } - private val selection by setting("Block Selection", defaultBlocks, defaultBlocks, "Block selection that will be shown (whitelist) or hidden (blacklist)") + private val selection by setting("Block Selection", defaultBlocks, "Block selection that will be shown (whitelist) or hidden (blacklist)") .onValueChange { _, _ -> if (isEnabled) mc.worldRenderer.reload() } private val mode by setting("Selection Mode", Selection.Whitelist, "The mode of the block selection") From bddc76daf5de0804d6367b30e15ed25b496dc049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emy=20=F0=9F=92=9C?= Date: Sun, 30 Nov 2025 17:16:54 -0500 Subject: [PATCH 3/8] Fixed configuration indent --- src/main/kotlin/com/lambda/config/Configuration.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/lambda/config/Configuration.kt b/src/main/kotlin/com/lambda/config/Configuration.kt index 5dd784ad9..a668e4580 100644 --- a/src/main/kotlin/com/lambda/config/Configuration.kt +++ b/src/main/kotlin/com/lambda/config/Configuration.kt @@ -100,7 +100,7 @@ abstract class Configuration : Jsonable, Loadable { private fun save() = runCatching { primary.createIfNotExists() .let { - it.writeText(toJson().toString()) + it.writeText(gson.toJson(toJson())) it.copyTo(backup, true) } } From 177842fddcd1332d7f67965d59b3f6868a4e7132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emy=20=F0=9F=92=9C?= Date: Sun, 30 Nov 2025 18:47:42 -0500 Subject: [PATCH 4/8] Update BetterFirework.kt --- .../com/lambda/module/modules/movement/BetterFirework.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 9cff85b84..33c382521 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -19,10 +19,6 @@ package com.lambda.module.modules.movement import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig import com.lambda.config.applyEdits -import com.lambda.config.AutomationConfig.Companion.DEFAULT.edit -import com.lambda.config.AutomationConfig.Companion.DEFAULT.hideAll -import com.lambda.config.groups.HotbarSettings -import com.lambda.config.groups.InventorySettings import com.lambda.config.settings.complex.Bind import com.lambda.context.SafeContext import com.lambda.event.events.KeyboardEvent From 0565a8d058362359ce50b0a352d6c3630a080aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emy=20=F0=9F=92=9C?= Date: Sun, 30 Nov 2025 18:48:39 -0500 Subject: [PATCH 5/8] Fixed custom collection settings type token --- .../config/settings/collections/BlockCollectionSetting.kt | 3 ++- .../config/settings/collections/ItemCollectionSetting.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt index 51ba6cc6c..4a09bd869 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt @@ -17,6 +17,7 @@ package com.lambda.config.settings.collections +import com.google.gson.reflect.TypeToken import com.lambda.config.serializer.BlockCodec import com.lambda.gui.dsl.ImGuiBuilder import imgui.flag.ImGuiSelectableFlags.DontClosePopups @@ -32,7 +33,7 @@ class BlockCollectionSetting( name, immutableCollection, defaultValue, - Block::class.java, + TypeToken.getParameterized(Collection::class.java, Block::class.java).type, description, visibility, ) { diff --git a/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt index a82a3aebd..226243ef3 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt @@ -17,6 +17,7 @@ package com.lambda.config.settings.collections +import com.google.gson.reflect.TypeToken import com.lambda.config.serializer.ItemCodec import com.lambda.gui.dsl.ImGuiBuilder import imgui.flag.ImGuiSelectableFlags.DontClosePopups @@ -32,7 +33,7 @@ class ItemCollectionSetting( name, immutableCollection, defaultValue, - Item::class.java, + TypeToken.getParameterized(Collection::class.java, Item::class.java).type, description, visibility, ) { From 342b9da8a9cfd72c87969fc460267569bc2116dc Mon Sep 17 00:00:00 2001 From: beanbag44 Date: Sun, 30 Nov 2025 23:51:16 +0000 Subject: [PATCH 6/8] open all managers on all tick stages by default with a blacklist. Also fix tick stage settings --- .../kotlin/com/lambda/config/Configurable.kt | 4 +- .../com/lambda/config/groups/BreakSettings.kt | 3 +- .../lambda/config/groups/HotbarSettings.kt | 3 +- .../lambda/config/groups/InteractSettings.kt | 3 +- .../lambda/config/groups/InventorySettings.kt | 4 +- .../com/lambda/config/groups/PlaceSettings.kt | 3 +- .../lambda/config/groups/RotationSettings.kt | 3 +- .../collections/BlockCollectionSetting.kt | 2 +- ...ectionSettings.kt => CollectionSetting.kt} | 4 +- .../collections/EventCollectionSetting.kt | 37 +++++++++++++++++++ .../collections/ItemCollectionSetting.kt | 2 +- .../config/settings/collections/SetSetting.kt | 0 .../interaction/request/RequestHandler.kt | 4 +- .../request/breaking/BreakManager.kt | 4 -- .../request/hotbar/HotbarManager.kt | 4 -- .../request/interacting/InteractionManager.kt | 4 -- .../request/inventory/InventoryManager.kt | 4 -- .../request/placing/PlaceManager.kt | 4 -- .../request/rotating/RotationConfig.kt | 3 +- .../request/rotating/RotationManager.kt | 6 +-- .../module/modules/movement/BetterFirework.kt | 17 +++------ 21 files changed, 66 insertions(+), 52 deletions(-) rename src/main/kotlin/com/lambda/config/settings/collections/{CollectionSettings.kt => CollectionSetting.kt} (94%) create mode 100644 src/main/kotlin/com/lambda/config/settings/collections/EventCollectionSetting.kt delete mode 100644 src/main/kotlin/com/lambda/config/settings/collections/SetSetting.kt diff --git a/src/main/kotlin/com/lambda/config/Configurable.kt b/src/main/kotlin/com/lambda/config/Configurable.kt index 35d589dc5..fdd3c14bf 100644 --- a/src/main/kotlin/com/lambda/config/Configurable.kt +++ b/src/main/kotlin/com/lambda/config/Configurable.kt @@ -25,7 +25,7 @@ import com.lambda.config.settings.CharSetting import com.lambda.config.settings.FunctionSetting import com.lambda.config.settings.StringSetting import com.lambda.config.settings.collections.BlockCollectionSetting -import com.lambda.config.settings.collections.CollectionSettings +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.comparable.BooleanSetting @@ -160,7 +160,7 @@ abstract class Configurable( defaultValue: Collection = immutableList, description: String = "", noinline visibility: () -> Boolean = { true }, - ) = CollectionSettings( + ) = CollectionSetting( name, immutableList, defaultValue.toMutableList(), diff --git a/src/main/kotlin/com/lambda/config/groups/BreakSettings.kt b/src/main/kotlin/com/lambda/config/groups/BreakSettings.kt index e02f0c792..e961fb451 100644 --- a/src/main/kotlin/com/lambda/config/groups/BreakSettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/BreakSettings.kt @@ -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 @@ -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.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() diff --git a/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt b/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt index be0a39c87..af916a068 100644 --- a/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt @@ -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 @@ -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.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() } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/InteractSettings.kt b/src/main/kotlin/com/lambda/config/groups/InteractSettings.kt index f85214b2c..b1e599339 100644 --- a/src/main/kotlin/com/lambda/config/groups/InteractSettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/InteractSettings.kt @@ -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 @@ -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.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() } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt b/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt index f6f911bf9..8c025002e 100644 --- a/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt @@ -19,7 +19,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.inventory.InventoryConfig import com.lambda.util.NamedEnum import com.lambda.util.item.ItemUtils @@ -35,7 +35,7 @@ class InventorySettings( } 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() - 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() + override val tickStageMask by c.setting("Inventory Stage Mask", ALL_STAGES.toSet(), description = "The sub-tick timing at which inventory actions are performed").group(baseGroup, Group.General).index() 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() override val swapWithDisposables by c.setting("Swap With Disposables", true, "Swap items with disposable ones").group(baseGroup, Group.Container).index() 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() diff --git a/src/main/kotlin/com/lambda/config/groups/PlaceSettings.kt b/src/main/kotlin/com/lambda/config/groups/PlaceSettings.kt index 35e1f295d..d8b7342bd 100644 --- a/src/main/kotlin/com/lambda/config/groups/PlaceSettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/PlaceSettings.kt @@ -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.placing.PlaceConfig import com.lambda.interaction.request.placing.PlaceConfig.AirPlaceMode import com.lambda.interaction.request.placing.PlaceConfig.PlaceConfirmationMode @@ -33,7 +34,7 @@ class PlaceSettings( override val airPlace by c.setting("Air Place", AirPlaceMode.None, "Allows for placing blocks without adjacent faces").group(baseGroup).index() override val axisRotateSetting by c.setting("Axis Rotate", true, "Overrides the Rotate For Place setting and rotates the player on each axis to air place rotational blocks") { airPlace.isEnabled }.group(baseGroup).index() override val sorter by c.setting("Place Sorter", ActionConfig.SortMode.Tool, "The order in which placements are performed").group(baseGroup).index() - override val tickStageMask by c.setting("Place Stage mask", setOf(TickEvent.Input.Post), description = "The sub-tick timing at which place actions are performed").group(baseGroup).index() + override val tickStageMask by c.setting("Place Stage mask", ALL_STAGES.toSet(), setOf(TickEvent.Input.Post), description = "The sub-tick timing at which place actions are performed").group(baseGroup).index() override val placeConfirmationMode by c.setting("Place Confirmation", PlaceConfirmationMode.PlaceThenAwait, "Wait for block placement confirmation").group(baseGroup).index() override val maxPendingPlacements by c.setting("Max Pending Placements", 5, 0..30, 1, "The maximum amount of pending placements").group(baseGroup).index() override val placementsPerTick by c.setting("Places Per Tick", 1, 1..30, 1, "Maximum instant block places per tick").group(baseGroup).index() diff --git a/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt b/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt index 09048839d..c378eab6a 100644 --- a/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt @@ -19,6 +19,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.rotating.RotationConfig import com.lambda.interaction.request.rotating.RotationMode @@ -42,7 +43,7 @@ class RotationSettings( /** How many ticks to wait before resetting the rotation */ override val decayTicks by c.setting("Reset Rotation", 1, 1..10, 1, "Ticks before rotation is reset", " ticks") { rotate }.group(baseGroup).index() - override val tickStageMask = ALL_STAGES.toSet() + override val tickStageMask = ALL_STAGES.subList(0, ALL_STAGES.indexOf(TickEvent.Player.Post)).toSet() /** Whether the rotation is instant */ var instant by c.setting("Instant Rotation", true, "Instantly rotate") { rotate }.group(baseGroup).index() diff --git a/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt index 4a09bd869..9420c2d84 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt @@ -29,7 +29,7 @@ class BlockCollectionSetting( defaultValue: MutableCollection, description: String, visibility: () -> Boolean, -) : CollectionSettings( +) : CollectionSetting( name, immutableCollection, defaultValue, diff --git a/src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt similarity index 94% rename from src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt rename to src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt index 6d109e3d5..dfffc92e1 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/CollectionSettings.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt @@ -30,7 +30,7 @@ import java.lang.reflect.Type /** * @see [com.lambda.config.Configurable] */ -open class CollectionSettings( +open class CollectionSetting( override var name: String, private var immutableCollection: Collection, defaultValue: MutableCollection, @@ -82,7 +82,7 @@ open class CollectionSettings( @SettingEditorDsl @Suppress("unchecked_cast") fun SettingGroupEditor.TypedEditBuilder>.immutableCollection(collection: Collection) { - (settings as Collection>).forEach { it.immutableCollection = collection } + (settings as Collection>).forEach { it.immutableCollection = collection } } } } diff --git a/src/main/kotlin/com/lambda/config/settings/collections/EventCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/EventCollectionSetting.kt new file mode 100644 index 000000000..a98692ea9 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/collections/EventCollectionSetting.kt @@ -0,0 +1,37 @@ +/* + * 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 . + */ + +package com.lambda.config.settings.collections + +import net.minecraft.item.Item + +class EventCollectionSetting( + override var name: String, + private val immutableSet: Set, + defaultValue: MutableSet, + description: String, + visibility: () -> Boolean +) : CollectionSetting( + name, + immutableSet, + defaultValue, + Item::class.java, + description, + visibility, +) { + +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt index 226243ef3..e9acb93fa 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt @@ -29,7 +29,7 @@ class ItemCollectionSetting( defaultValue: MutableCollection, description: String, visibility: () -> Boolean, -) : CollectionSettings( +) : CollectionSetting( name, immutableCollection, defaultValue, diff --git a/src/main/kotlin/com/lambda/config/settings/collections/SetSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/SetSetting.kt deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/main/kotlin/com/lambda/interaction/request/RequestHandler.kt b/src/main/kotlin/com/lambda/interaction/request/RequestHandler.kt index 2251edea8..ff188b8cc 100644 --- a/src/main/kotlin/com/lambda/interaction/request/RequestHandler.kt +++ b/src/main/kotlin/com/lambda/interaction/request/RequestHandler.kt @@ -35,10 +35,12 @@ import kotlin.reflect.KClass */ abstract class RequestHandler( val stagePriority: Int, - private vararg val openStages: Event, + vararg val blacklistedStages: TickEvent, private val onOpen: (SafeContext.() -> Unit)? = null, private val onClose: (SafeContext.() -> Unit)? = null ) : Loadable { + val openStages: List = ALL_STAGES.filter { it !in blacklistedStages } + /** * Represents if the handler is accepting requests at any given time */ diff --git a/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt b/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt index a60e41b35..861253876 100644 --- a/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt +++ b/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt @@ -112,10 +112,6 @@ import kotlin.math.min */ object BreakManager : RequestHandler( 0, - TickEvent.Pre, - TickEvent.Input.Pre, - TickEvent.Input.Post, - TickEvent.Player.Post, onOpen = { if (activeInfos.isNotEmpty() || breaks.isNotEmpty()) BreakManager.logger.newStage(BreakManager.tickStage) diff --git a/src/main/kotlin/com/lambda/interaction/request/hotbar/HotbarManager.kt b/src/main/kotlin/com/lambda/interaction/request/hotbar/HotbarManager.kt index 5726dd362..e93d59fee 100644 --- a/src/main/kotlin/com/lambda/interaction/request/hotbar/HotbarManager.kt +++ b/src/main/kotlin/com/lambda/interaction/request/hotbar/HotbarManager.kt @@ -47,10 +47,6 @@ import net.minecraft.item.ItemStack */ object HotbarManager : RequestHandler( 1, - TickEvent.Pre, - TickEvent.Input.Pre, - TickEvent.Input.Post, - TickEvent.Player.Post, onOpen = { if (activeRequest != null) { setActiveSlot() diff --git a/src/main/kotlin/com/lambda/interaction/request/interacting/InteractionManager.kt b/src/main/kotlin/com/lambda/interaction/request/interacting/InteractionManager.kt index 01fce1170..171aa14e7 100644 --- a/src/main/kotlin/com/lambda/interaction/request/interacting/InteractionManager.kt +++ b/src/main/kotlin/com/lambda/interaction/request/interacting/InteractionManager.kt @@ -54,10 +54,6 @@ import net.minecraft.util.Hand */ object InteractionManager : RequestHandler( 0, - TickEvent.Pre, - TickEvent.Input.Pre, - TickEvent.Input.Post, - TickEvent.Player.Post, onOpen = { if (potentialInteractions.isNotEmpty()) InteractionManager.logger.newStage(InteractionManager.tickStage) diff --git a/src/main/kotlin/com/lambda/interaction/request/inventory/InventoryManager.kt b/src/main/kotlin/com/lambda/interaction/request/inventory/InventoryManager.kt index 45f26f8d0..2602e0705 100644 --- a/src/main/kotlin/com/lambda/interaction/request/inventory/InventoryManager.kt +++ b/src/main/kotlin/com/lambda/interaction/request/inventory/InventoryManager.kt @@ -52,10 +52,6 @@ import net.minecraft.screen.slot.Slot */ object InventoryManager : RequestHandler( 1, - TickEvent.Pre, - TickEvent.Input.Pre, - TickEvent.Input.Post, - TickEvent.Player.Post, onOpen = { processActiveRequest() } ), Logger { private var activeRequest: InventoryRequest? = null diff --git a/src/main/kotlin/com/lambda/interaction/request/placing/PlaceManager.kt b/src/main/kotlin/com/lambda/interaction/request/placing/PlaceManager.kt index eb94479f2..3153710db 100644 --- a/src/main/kotlin/com/lambda/interaction/request/placing/PlaceManager.kt +++ b/src/main/kotlin/com/lambda/interaction/request/placing/PlaceManager.kt @@ -71,10 +71,6 @@ import kotlin.math.min object PlaceManager : RequestHandler( 0, - TickEvent.Pre, - TickEvent.Input.Pre, - TickEvent.Input.Post, - TickEvent.Player.Post, onOpen = { if (potentialPlacements.isNotEmpty()) PlaceManager.logger.newStage(PlaceManager.tickStage) diff --git a/src/main/kotlin/com/lambda/interaction/request/rotating/RotationConfig.kt b/src/main/kotlin/com/lambda/interaction/request/rotating/RotationConfig.kt index c7b9c8af0..75cca282f 100644 --- a/src/main/kotlin/com/lambda/interaction/request/rotating/RotationConfig.kt +++ b/src/main/kotlin/com/lambda/interaction/request/rotating/RotationConfig.kt @@ -20,7 +20,6 @@ package com.lambda.interaction.request.rotating import com.lambda.config.AbstractSetting import com.lambda.config.ISettingGroup import com.lambda.event.events.TickEvent -import com.lambda.event.events.TickEvent.Companion.ALL_STAGES interface RotationConfig : ISettingGroup { /** @@ -56,6 +55,6 @@ interface RotationConfig : ISettingGroup { override val keepTicks = 1 override val decayTicks = 1 override val turnSpeed = 360.0 - override val tickStageMask = ALL_STAGES.toSet() + override val tickStageMask = RotationManager.openStages.toSet() } } diff --git a/src/main/kotlin/com/lambda/interaction/request/rotating/RotationManager.kt b/src/main/kotlin/com/lambda/interaction/request/rotating/RotationManager.kt index b3a9c755c..276edf865 100644 --- a/src/main/kotlin/com/lambda/interaction/request/rotating/RotationManager.kt +++ b/src/main/kotlin/com/lambda/interaction/request/rotating/RotationManager.kt @@ -26,6 +26,7 @@ import com.lambda.event.events.PacketEvent import com.lambda.event.events.PlayerEvent import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent +import com.lambda.event.events.TickEvent.Companion.ALL_STAGES import com.lambda.event.events.UpdateManagerEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe @@ -61,10 +62,7 @@ import kotlin.math.sin */ object RotationManager : RequestHandler( 1, - TickEvent.Pre, - TickEvent.Input.Pre, - TickEvent.Input.Post, - TickEvent.Player.Post, + *(ALL_STAGES.subList(ALL_STAGES.indexOf(TickEvent.Player.Post), ALL_STAGES.size - 1).toTypedArray()), ), Logger { var activeRotation = Rotation.ZERO var serverRotation = Rotation.ZERO diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 33c382521..820541f40 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -33,7 +33,6 @@ import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe import com.lambda.util.KeyCode import com.lambda.util.Mouse -import com.lambda.util.NamedEnum import com.lambda.util.player.SlotUtils.hotbar import com.lambda.util.player.SlotUtils.hotbarAndStorage import net.minecraft.client.network.ClientPlayerEntity @@ -49,20 +48,14 @@ object BetterFirework : Module( description = "Automatic takeoff with fireworks", tag = ModuleTag.MOVEMENT, ) { - private var activateButton by setting("Activate Key", Bind(0, 0, Mouse.Middle.ordinal), "Button to activate Firework").group(Group.General) - private var midFlightActivationKey by setting("Mid-Flight Activation Key", Bind(0, 0, KeyCode.Unbound.code), "Firework use key for mid flight activation").group(Group.General) - private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { activateButton.key != KeyCode.Unbound.code }.group(Group.General) + private var activateButton by setting("Activate Key", Bind(0, 0, Mouse.Middle.ordinal), "Button to activate Firework") + private var midFlightActivationKey by setting("Mid-Flight Activation Key", Bind(0, 0, KeyCode.Unbound.code), "Firework use key for mid flight activation") + private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { activateButton.key != KeyCode.Unbound.code } private var fireworkInteract by setting("Right Click Fly", true, "Automatically start flying when right clicking fireworks") private var fireworkInteractCancel by setting("Right Click Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract } - private var clientSwing by setting("Swing", true, "Swing hand client side").group(Group.General) - private var invUse by setting("Inventory", true, "Use fireworks from inventory") { activateButton.key != KeyCode.Unbound.code }.group(Group.General) - - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Hotbar("Hotbar"), - Inventory("Inventory") - } + private var clientSwing by setting("Swing", true, "Swing hand client side") + private var invUse by setting("Inventory", true, "Use fireworks from inventory") { activateButton.key != KeyCode.Unbound.code } private var takeoffState = TakeoffState.None From 1a4d86bf79959afd882ebfeb8445bdf1dc4ebf2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emy=20=F0=9F=92=9C?= Date: Sun, 30 Nov 2025 20:17:44 -0500 Subject: [PATCH 7/8] Fixed config loading; Better collection settings --- src/main/kotlin/com/lambda/Lambda.kt | 1 - .../kotlin/com/lambda/config/Configuration.kt | 10 ++- .../collections/BlockCollectionSetting.kt | 9 +++ .../collections/ClassCollectionSetting.kt | 78 +++++++++++++++++++ .../settings/collections/CollectionSetting.kt | 19 ++++- .../collections/EventCollectionSetting.kt | 37 --------- .../collections/ItemCollectionSetting.kt | 9 +++ 7 files changed, 120 insertions(+), 43 deletions(-) create mode 100644 src/main/kotlin/com/lambda/config/settings/collections/ClassCollectionSetting.kt delete mode 100644 src/main/kotlin/com/lambda/config/settings/collections/EventCollectionSetting.kt diff --git a/src/main/kotlin/com/lambda/Lambda.kt b/src/main/kotlin/com/lambda/Lambda.kt index a4ce44f43..c8242977d 100644 --- a/src/main/kotlin/com/lambda/Lambda.kt +++ b/src/main/kotlin/com/lambda/Lambda.kt @@ -80,7 +80,6 @@ object Lambda : ClientModInitializer { .registerTypeAdapter(Optional::class.java, OptionalCodec) .registerTypeAdapter(ItemStack::class.java, ItemStackCodec) .registerTypeAdapter(Text::class.java, Text.Serializer(DynamicRegistryManager.EMPTY)) - // We have to add all item sub classes :/. I probably missed some .registerTypeAdapter(Item::class.java, ItemCodec) .registerTypeAdapter(BlockItem::class.java, ItemCodec) .registerTypeAdapter(ArrowItem::class.java, ItemCodec) diff --git a/src/main/kotlin/com/lambda/config/Configuration.kt b/src/main/kotlin/com/lambda/config/Configuration.kt index a668e4580..2815fea11 100644 --- a/src/main/kotlin/com/lambda/config/Configuration.kt +++ b/src/main/kotlin/com/lambda/config/Configuration.kt @@ -135,16 +135,18 @@ abstract class Configuration : Jsonable, Loadable { LOG.info(message) info(message) } - .onFailure { - var message: String + .onFailure { primaryError -> + throw 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) } diff --git a/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt index 9420c2d84..6ca899fe6 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt @@ -17,7 +17,9 @@ package com.lambda.config.settings.collections +import com.google.gson.JsonElement import com.google.gson.reflect.TypeToken +import com.lambda.Lambda.gson import com.lambda.config.serializer.BlockCodec import com.lambda.gui.dsl.ImGuiBuilder import imgui.flag.ImGuiSelectableFlags.DontClosePopups @@ -68,4 +70,11 @@ class BlockCollectionSetting( } } } + + override fun toJson(): JsonElement = gson.toJsonTree(value, type) + + override fun loadFromJson(serialized: JsonElement) { + value = gson.fromJson>(serialized, type) + .toMutableList() + } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/collections/ClassCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/ClassCollectionSetting.kt new file mode 100644 index 000000000..1bd531008 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/collections/ClassCollectionSetting.kt @@ -0,0 +1,78 @@ +/* + * 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 . + */ + +package com.lambda.config.settings.collections + +import com.google.gson.JsonElement +import com.google.gson.reflect.TypeToken +import com.lambda.Lambda.gson +import com.lambda.gui.dsl.ImGuiBuilder +import imgui.flag.ImGuiSelectableFlags.DontClosePopups + +/** + * @see [com.lambda.config.settings.collections.CollectionSettings] + * @see [com.lambda.config.Configurable] + */ +class ClassCollectionSetting( + override var name: String, + private val immutableCollection: Collection, + defaultValue: MutableCollection, + description: String, + visibility: () -> Boolean, +) : CollectionSetting( + name, + immutableCollection, + defaultValue, + TypeToken.getParameterized(Collection::class.java, Any::class.java).type, + description, + visibility, +) { + override fun ImGuiBuilder.buildLayout() { + combo("##$name", "$name: ${value.size} item(s)") { + immutableCollection + .forEach { + val isSelected = value.contains(it) + + selectable( + label = it.className, + selected = isSelected, + flags = DontClosePopups, + ) { + if (isSelected) value.remove(it) + else value.add(it) + } + } + } + } + + val Any.className: String get() = this::class.java.name + .substringAfter("${this::class.java.packageName}.") + .replace('$', '.') + + // When serializing the list to json we do not want to serialize the elements' classes, but their stringified representation. + // If we do serialize the classes we'll run into missing type adapters errors by Gson. + // This is intended behaviour. If you wish your collection settings to display something else then you must extend this class. + override fun toJson(): JsonElement = gson.toJsonTree(value.map { it.className }) + + override fun loadFromJson(serialized: JsonElement) { + val strList = gson.fromJson>(serialized, type) + .mapNotNull { str -> immutableCollection.find { it.className == str } } + .toMutableList() + + value = strList + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt index dfffc92e1..6f0aaa533 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt @@ -18,6 +18,7 @@ package com.lambda.config.settings.collections import com.google.gson.JsonElement +import com.google.gson.reflect.TypeToken import com.lambda.Lambda.gson import com.lambda.config.AbstractSetting import com.lambda.config.SettingEditorDsl @@ -28,6 +29,13 @@ import imgui.flag.ImGuiSelectableFlags.DontClosePopups import java.lang.reflect.Type /** + * This generic collection settings handles all [Comparable] values (i.e not classes) and serialize + * their values by calling [Any.toString] and loads them by comparing what's in the [immutableCollection]. + * This behaviour is by design. If you wish to store collections of non-comparable values you must use [ClassCollectionSetting]. + * + * If you wish to use a different codec or simply display values differently you must create your own + * collection setting. + * * @see [com.lambda.config.Configurable] */ open class CollectionSetting( @@ -44,6 +52,9 @@ open class CollectionSetting( description, visibility ) { + private val strListType = + TypeToken.getParameterized(Collection::class.java, String::class.java).type + private val selectListeners = mutableListOf Unit>() private val deselectListeners = mutableListOf Unit>() @@ -73,9 +84,15 @@ open class CollectionSetting( } } + override fun toJson(): JsonElement = + gson.toJsonTree(value.map { it.toString() }) + override fun loadFromJson(serialized: JsonElement) { - value = gson.fromJson>(serialized, type) + val strList = gson.fromJson>(serialized, strListType) + .mapNotNull { str -> immutableCollection.find { it.toString() == str } } .toMutableList() + + value = strList } companion object { diff --git a/src/main/kotlin/com/lambda/config/settings/collections/EventCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/EventCollectionSetting.kt deleted file mode 100644 index a98692ea9..000000000 --- a/src/main/kotlin/com/lambda/config/settings/collections/EventCollectionSetting.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 . - */ - -package com.lambda.config.settings.collections - -import net.minecraft.item.Item - -class EventCollectionSetting( - override var name: String, - private val immutableSet: Set, - defaultValue: MutableSet, - description: String, - visibility: () -> Boolean -) : CollectionSetting( - name, - immutableSet, - defaultValue, - Item::class.java, - description, - visibility, -) { - -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt index e9acb93fa..daf88804b 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt @@ -17,7 +17,9 @@ package com.lambda.config.settings.collections +import com.google.gson.JsonElement import com.google.gson.reflect.TypeToken +import com.lambda.Lambda.gson import com.lambda.config.serializer.ItemCodec import com.lambda.gui.dsl.ImGuiBuilder import imgui.flag.ImGuiSelectableFlags.DontClosePopups @@ -68,4 +70,11 @@ class ItemCollectionSetting( } } } + + override fun toJson(): JsonElement = gson.toJsonTree(value, type) + + override fun loadFromJson(serialized: JsonElement) { + value = gson.fromJson>(serialized, type) + .toMutableList() + } } \ No newline at end of file From 78ebb6bb976a141812633beb3b40c8c262b8c314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emy=20=F0=9F=92=9C?= Date: Sun, 30 Nov 2025 20:26:06 -0500 Subject: [PATCH 8/8] Fixed for good --- .../kotlin/com/lambda/config/Configurable.kt | 17 ++++++++++++++++- .../kotlin/com/lambda/config/Configuration.kt | 1 - .../com/lambda/config/groups/PlaceSettings.kt | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/lambda/config/Configurable.kt b/src/main/kotlin/com/lambda/config/Configurable.kt index fdd3c14bf..c0d0a41d7 100644 --- a/src/main/kotlin/com/lambda/config/Configurable.kt +++ b/src/main/kotlin/com/lambda/config/Configurable.kt @@ -25,6 +25,7 @@ import com.lambda.config.settings.CharSetting import com.lambda.config.settings.FunctionSetting import com.lambda.config.settings.StringSetting 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 @@ -154,7 +155,7 @@ abstract class Configurable( visibility, ).register() - inline fun setting( + inline fun > setting( name: String, immutableList: Collection, defaultValue: Collection = immutableList, @@ -169,6 +170,20 @@ abstract class Configurable( visibility, ).register() + inline fun setting( + name: String, + immutableList: Collection, + defaultValue: Collection = immutableList, + description: String = "", + noinline visibility: () -> Boolean = { true }, + ) = ClassCollectionSetting( + name, + immutableList, + defaultValue.toMutableList(), + description, + visibility, + ).register() + // ToDo: Actually implement maps inline fun setting( name: String, diff --git a/src/main/kotlin/com/lambda/config/Configuration.kt b/src/main/kotlin/com/lambda/config/Configuration.kt index 2815fea11..102924ace 100644 --- a/src/main/kotlin/com/lambda/config/Configuration.kt +++ b/src/main/kotlin/com/lambda/config/Configuration.kt @@ -136,7 +136,6 @@ abstract class Configuration : Jsonable, Loadable { info(message) } .onFailure { primaryError -> - throw primaryError LOG.error(primaryError) runCatching { load(backup) } diff --git a/src/main/kotlin/com/lambda/config/groups/PlaceSettings.kt b/src/main/kotlin/com/lambda/config/groups/PlaceSettings.kt index d8b7342bd..1b138096a 100644 --- a/src/main/kotlin/com/lambda/config/groups/PlaceSettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/PlaceSettings.kt @@ -34,7 +34,7 @@ class PlaceSettings( override val airPlace by c.setting("Air Place", AirPlaceMode.None, "Allows for placing blocks without adjacent faces").group(baseGroup).index() override val axisRotateSetting by c.setting("Axis Rotate", true, "Overrides the Rotate For Place setting and rotates the player on each axis to air place rotational blocks") { airPlace.isEnabled }.group(baseGroup).index() override val sorter by c.setting("Place Sorter", ActionConfig.SortMode.Tool, "The order in which placements are performed").group(baseGroup).index() - override val tickStageMask by c.setting("Place Stage mask", ALL_STAGES.toSet(), setOf(TickEvent.Input.Post), description = "The sub-tick timing at which place actions are performed").group(baseGroup).index() + override val tickStageMask by c.setting("Place Stage Mask", ALL_STAGES.toSet(), setOf(TickEvent.Input.Post), description = "The sub-tick timing at which place actions are performed").group(baseGroup).index() override val placeConfirmationMode by c.setting("Place Confirmation", PlaceConfirmationMode.PlaceThenAwait, "Wait for block placement confirmation").group(baseGroup).index() override val maxPendingPlacements by c.setting("Max Pending Placements", 5, 0..30, 1, "The maximum amount of pending placements").group(baseGroup).index() override val placementsPerTick by c.setting("Places Per Tick", 1, 1..30, 1, "Maximum instant block places per tick").group(baseGroup).index()