From e1b951f6124c28a5cc1ec9d9ca3416f5104b27b3 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Sun, 19 May 2024 11:45:42 -0400 Subject: Simon Says Solver --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 2 + .../config/categories/DungeonsCategory.java | 1220 ++++++++++---------- .../skyblocker/config/configs/DungeonsConfig.java | 8 + .../hysky/skyblocker/mixins/ClientWorldMixin.java | 11 +- .../skyblock/dungeon/device/SimonSays.java | 124 ++ .../skyblocker/utils/render/RenderHelper.java | 10 +- 6 files changed, 767 insertions(+), 608 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index f1eb4321..5366daf7 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -14,6 +14,7 @@ import de.hysky.skyblocker.skyblock.chocolatefactory.TimeTowerReminder; import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; import de.hysky.skyblocker.skyblock.dungeon.*; +import de.hysky.skyblocker.skyblock.dungeon.device.SimonSays; import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; import de.hysky.skyblocker.skyblock.dungeon.puzzle.*; import de.hysky.skyblocker.skyblock.dungeon.puzzle.boulder.Boulder; @@ -151,6 +152,7 @@ public class SkyblockerMod implements ClientModInitializer { Silverfish.init(); IceFill.init(); DungeonScore.init(); + SimonSays.init(); PartyFinderScreen.initClass(); ChestValue.init(); FireFreezeStaffTimer.init(); diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java index 28ace441..36999778 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -15,619 +15,633 @@ import net.minecraft.util.Formatting; public class DungeonsCategory { - public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { - return ConfigCategory.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons")) + public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { + return ConfigCategory.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons")) - //Ungrouped Options - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.fancyPartyFinder")) - .binding(defaults.dungeons.fancyPartyFinder, - () -> config.dungeons.fancyPartyFinder, - newValue -> config.dungeons.fancyPartyFinder = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.croesusHelper")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.croesusHelper.@Tooltip"))) - .binding(defaults.dungeons.croesusHelper, - () -> config.dungeons.croesusHelper, - newValue -> config.dungeons.croesusHelper = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.playerSecretsTracker")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.playerSecretsTracker.@Tooltip"))) - .binding(defaults.dungeons.playerSecretsTracker, - () -> config.dungeons.playerSecretsTracker, - newValue -> config.dungeons.playerSecretsTracker = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.starredMobGlow")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobGlow.@Tooltip"))) - .binding(defaults.dungeons.starredMobGlow, - () -> config.dungeons.starredMobGlow, - newValue -> config.dungeons.starredMobGlow = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.starredMobBoundingBoxes")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobBoundingBoxes.@Tooltip"))) - .binding(defaults.dungeons.starredMobBoundingBoxes, - () -> config.dungeons.starredMobBoundingBoxes, - newValue -> config.dungeons.starredMobBoundingBoxes = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.allowDroppingProtectedItems")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.allowDroppingProtectedItems.@Tooltip"))) - .binding(defaults.dungeons.allowDroppingProtectedItems, - () -> config.dungeons.allowDroppingProtectedItems, - newValue -> config.dungeons.allowDroppingProtectedItems = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.hideSoulweaverSkulls")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.hideSoulweaverSkulls.@Tooltip"))) - .binding(defaults.dungeons.hideSoulweaverSkulls, - () -> config.dungeons.hideSoulweaverSkulls, - newValue -> config.dungeons.hideSoulweaverSkulls = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) + //Ungrouped Options + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.fancyPartyFinder")) + .binding(defaults.dungeons.fancyPartyFinder, + () -> config.dungeons.fancyPartyFinder, + newValue -> config.dungeons.fancyPartyFinder = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.croesusHelper")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.croesusHelper.@Tooltip"))) + .binding(defaults.dungeons.croesusHelper, + () -> config.dungeons.croesusHelper, + newValue -> config.dungeons.croesusHelper = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.playerSecretsTracker")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.playerSecretsTracker.@Tooltip"))) + .binding(defaults.dungeons.playerSecretsTracker, + () -> config.dungeons.playerSecretsTracker, + newValue -> config.dungeons.playerSecretsTracker = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.starredMobGlow")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobGlow.@Tooltip"))) + .binding(defaults.dungeons.starredMobGlow, + () -> config.dungeons.starredMobGlow, + newValue -> config.dungeons.starredMobGlow = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.starredMobBoundingBoxes")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobBoundingBoxes.@Tooltip"))) + .binding(defaults.dungeons.starredMobBoundingBoxes, + () -> config.dungeons.starredMobBoundingBoxes, + newValue -> config.dungeons.starredMobBoundingBoxes = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.allowDroppingProtectedItems")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.allowDroppingProtectedItems.@Tooltip"))) + .binding(defaults.dungeons.allowDroppingProtectedItems, + () -> config.dungeons.allowDroppingProtectedItems, + newValue -> config.dungeons.allowDroppingProtectedItems = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.hideSoulweaverSkulls")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.hideSoulweaverSkulls.@Tooltip"))) + .binding(defaults.dungeons.hideSoulweaverSkulls, + () -> config.dungeons.hideSoulweaverSkulls, + newValue -> config.dungeons.hideSoulweaverSkulls = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) - // Map - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.map")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.map.enableMap")) - .binding(defaults.dungeons.dungeonMap.enableMap, - () -> config.dungeons.dungeonMap.enableMap, - newValue -> config.dungeons.dungeonMap.enableMap = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.map.mapScaling")) - .binding(defaults.dungeons.dungeonMap.mapScaling, - () -> config.dungeons.dungeonMap.mapScaling, - newValue -> config.dungeons.dungeonMap.mapScaling = newValue) - .controller(FloatFieldControllerBuilder::create) - .build()) - .option(ButtonOption.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.map.mapScreen")) - .text(Text.translatable("text.skyblocker.open")) - .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new DungeonMapConfigScreen(screen))) - .build()) - .build()) + // Map + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map.enableMap")) + .binding(defaults.dungeons.dungeonMap.enableMap, + () -> config.dungeons.dungeonMap.enableMap, + newValue -> config.dungeons.dungeonMap.enableMap = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map.mapScaling")) + .binding(defaults.dungeons.dungeonMap.mapScaling, + () -> config.dungeons.dungeonMap.mapScaling, + newValue -> config.dungeons.dungeonMap.mapScaling = newValue) + .controller(FloatFieldControllerBuilder::create) + .build()) + .option(ButtonOption.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map.mapScreen")) + .text(Text.translatable("text.skyblocker.open")) + .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new DungeonMapConfigScreen(screen))) + .build()) + .build()) - // Puzzle Solver - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveTicTacToe")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveTicTacToe.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.solveTicTacToe, - () -> config.dungeons.puzzleSolvers.solveTicTacToe, - newValue -> config.dungeons.puzzleSolvers.solveTicTacToe = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveThreeWeirdos")) - .binding(defaults.dungeons.puzzleSolvers.solveThreeWeirdos, - () -> config.dungeons.puzzleSolvers.solveThreeWeirdos, - newValue -> config.dungeons.puzzleSolvers.solveThreeWeirdos = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.creeperSolver")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.creeperSolver.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.creeperSolver, - () -> config.dungeons.puzzleSolvers.creeperSolver, - newValue -> config.dungeons.puzzleSolvers.creeperSolver = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveWaterboard")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveWaterboard.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.solveWaterboard, - () -> config.dungeons.puzzleSolvers.solveWaterboard, - newValue -> config.dungeons.puzzleSolvers.solveWaterboard = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.blazeSolver")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.blazeSolver.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.blazeSolver, - () -> config.dungeons.puzzleSolvers.blazeSolver, - newValue -> config.dungeons.puzzleSolvers.blazeSolver = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveBoulder")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveBoulder.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.solveBoulder, - () -> config.dungeons.puzzleSolvers.solveBoulder, - newValue -> config.dungeons.puzzleSolvers.solveBoulder = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveIceFill")) - .binding(defaults.dungeons.puzzleSolvers.solveIceFill, - () -> config.dungeons.puzzleSolvers.solveIceFill, - newValue -> config.dungeons.puzzleSolvers.solveIceFill = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveSilverfish")) - .binding(defaults.dungeons.puzzleSolvers.solveSilverfish, - () -> config.dungeons.puzzleSolvers.solveSilverfish, - newValue -> config.dungeons.puzzleSolvers.solveSilverfish = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveTrivia")) - .binding(defaults.dungeons.puzzleSolvers.solveTrivia, - () -> config.dungeons.puzzleSolvers.solveTrivia, - newValue -> config.dungeons.puzzleSolvers.solveTrivia = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .build()) + // Puzzle Solver + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveTicTacToe")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveTicTacToe.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.solveTicTacToe, + () -> config.dungeons.puzzleSolvers.solveTicTacToe, + newValue -> config.dungeons.puzzleSolvers.solveTicTacToe = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveThreeWeirdos")) + .binding(defaults.dungeons.puzzleSolvers.solveThreeWeirdos, + () -> config.dungeons.puzzleSolvers.solveThreeWeirdos, + newValue -> config.dungeons.puzzleSolvers.solveThreeWeirdos = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.creeperSolver")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.creeperSolver.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.creeperSolver, + () -> config.dungeons.puzzleSolvers.creeperSolver, + newValue -> config.dungeons.puzzleSolvers.creeperSolver = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveWaterboard")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveWaterboard.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.solveWaterboard, + () -> config.dungeons.puzzleSolvers.solveWaterboard, + newValue -> config.dungeons.puzzleSolvers.solveWaterboard = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.blazeSolver")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.blazeSolver.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.blazeSolver, + () -> config.dungeons.puzzleSolvers.blazeSolver, + newValue -> config.dungeons.puzzleSolvers.blazeSolver = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveBoulder")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveBoulder.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.solveBoulder, + () -> config.dungeons.puzzleSolvers.solveBoulder, + newValue -> config.dungeons.puzzleSolvers.solveBoulder = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveIceFill")) + .binding(defaults.dungeons.puzzleSolvers.solveIceFill, + () -> config.dungeons.puzzleSolvers.solveIceFill, + newValue -> config.dungeons.puzzleSolvers.solveIceFill = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveSilverfish")) + .binding(defaults.dungeons.puzzleSolvers.solveSilverfish, + () -> config.dungeons.puzzleSolvers.solveSilverfish, + newValue -> config.dungeons.puzzleSolvers.solveSilverfish = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveTrivia")) + .binding(defaults.dungeons.puzzleSolvers.solveTrivia, + () -> config.dungeons.puzzleSolvers.solveTrivia, + newValue -> config.dungeons.puzzleSolvers.solveTrivia = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // The Professor (F3/M3) - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.professor")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.professor.fireFreezeStaffTimer")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.professor.fireFreezeStaffTimer.@Tooltip"))) - .binding(defaults.dungeons.theProfessor.fireFreezeStaffTimer, - () -> config.dungeons.theProfessor.fireFreezeStaffTimer, - newValue -> config.dungeons.theProfessor.fireFreezeStaffTimer = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.professor.floor3GuardianHealthDisplay")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.professor.floor3GuardianHealthDisplay.@Tooltip"))) - .binding(defaults.dungeons.theProfessor.floor3GuardianHealthDisplay, - () -> config.dungeons.theProfessor.floor3GuardianHealthDisplay, - newValue -> config.dungeons.theProfessor.floor3GuardianHealthDisplay = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .build()) + // The Professor (F3/M3) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.professor")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.professor.fireFreezeStaffTimer")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.professor.fireFreezeStaffTimer.@Tooltip"))) + .binding(defaults.dungeons.theProfessor.fireFreezeStaffTimer, + () -> config.dungeons.theProfessor.fireFreezeStaffTimer, + newValue -> config.dungeons.theProfessor.fireFreezeStaffTimer = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.professor.floor3GuardianHealthDisplay")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.professor.floor3GuardianHealthDisplay.@Tooltip"))) + .binding(defaults.dungeons.theProfessor.floor3GuardianHealthDisplay, + () -> config.dungeons.theProfessor.floor3GuardianHealthDisplay, + newValue -> config.dungeons.theProfessor.floor3GuardianHealthDisplay = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // Livid (F5/M5) - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorGlow")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorGlow.@Tooltip"))) - .binding(defaults.dungeons.livid.enableLividColorGlow, - () -> config.dungeons.livid.enableLividColorGlow, - newValue -> config.dungeons.livid.enableLividColorGlow = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorText")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorText.@Tooltip"))) - .binding(defaults.dungeons.livid.enableLividColorText, - () -> config.dungeons.livid.enableLividColorText, - newValue -> config.dungeons.livid.enableLividColorText = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorTitle")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorTitle.@Tooltip"))) - .binding(defaults.dungeons.livid.enableLividColorTitle, - () -> config.dungeons.livid.enableLividColorTitle, - newValue -> config.dungeons.livid.enableLividColorTitle = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid.lividColorText")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.lividColorText.@Tooltip"))) - .binding(defaults.dungeons.livid.lividColorText, - () -> config.dungeons.livid.lividColorText, - newValue -> config.dungeons.livid.lividColorText = newValue) - .controller(StringControllerBuilder::create) - .build()) - .build()) + // Livid (F5/M5) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorGlow")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorGlow.@Tooltip"))) + .binding(defaults.dungeons.livid.enableLividColorGlow, + () -> config.dungeons.livid.enableLividColorGlow, + newValue -> config.dungeons.livid.enableLividColorGlow = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorText")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorText.@Tooltip"))) + .binding(defaults.dungeons.livid.enableLividColorText, + () -> config.dungeons.livid.enableLividColorText, + newValue -> config.dungeons.livid.enableLividColorText = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorTitle")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorTitle.@Tooltip"))) + .binding(defaults.dungeons.livid.enableLividColorTitle, + () -> config.dungeons.livid.enableLividColorTitle, + newValue -> config.dungeons.livid.enableLividColorTitle = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid.lividColorText")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.lividColorText.@Tooltip"))) + .binding(defaults.dungeons.livid.lividColorText, + () -> config.dungeons.livid.lividColorText, + newValue -> config.dungeons.livid.lividColorText = newValue) + .controller(StringControllerBuilder::create) + .build()) + .build()) - // Terminal (F7/M7) - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals.solveColor")) - .binding(defaults.dungeons.terminals.solveColor, - () -> config.dungeons.terminals.solveColor, - newValue -> config.dungeons.terminals.solveColor = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals.solveOrder")) - .binding(defaults.dungeons.terminals.solveOrder, - () -> config.dungeons.terminals.solveOrder, - newValue -> config.dungeons.terminals.solveOrder = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals.solveStartsWith")) - .binding(defaults.dungeons.terminals.solveStartsWith, - () -> config.dungeons.terminals.solveStartsWith, - newValue -> config.dungeons.terminals.solveStartsWith = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals.blockIncorrectClicks")) - .binding(defaults.dungeons.terminals.blockIncorrectClicks, - () -> config.dungeons.terminals.blockIncorrectClicks, - newValue -> config.dungeons.terminals.blockIncorrectClicks = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .build()) + // Terminal (F7/M7) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals.solveColor")) + .binding(defaults.dungeons.terminals.solveColor, + () -> config.dungeons.terminals.solveColor, + newValue -> config.dungeons.terminals.solveColor = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals.solveOrder")) + .binding(defaults.dungeons.terminals.solveOrder, + () -> config.dungeons.terminals.solveOrder, + newValue -> config.dungeons.terminals.solveOrder = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals.solveStartsWith")) + .binding(defaults.dungeons.terminals.solveStartsWith, + () -> config.dungeons.terminals.solveStartsWith, + newValue -> config.dungeons.terminals.solveStartsWith = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals.blockIncorrectClicks")) + .binding(defaults.dungeons.terminals.blockIncorrectClicks, + () -> config.dungeons.terminals.blockIncorrectClicks, + newValue -> config.dungeons.terminals.blockIncorrectClicks = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // Dungeon Secret Waypoints - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableRoomMatching")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableRoomMatching.@Tooltip"))) - .binding(defaults.dungeons.secretWaypoints.enableRoomMatching, - () -> config.dungeons.secretWaypoints.enableRoomMatching, - newValue -> config.dungeons.secretWaypoints.enableRoomMatching = newValue) - .controller(ConfigUtils::createBooleanController) - .flag(OptionFlag.GAME_RESTART) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableSecretWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableSecretWaypoints, - () -> config.dungeons.secretWaypoints.enableSecretWaypoints, - newValue -> config.dungeons.secretWaypoints.enableSecretWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType.@Tooltip"), - Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType.generalNote"))) - .binding(defaults.dungeons.secretWaypoints.waypointType, - () -> config.dungeons.secretWaypoints.waypointType, - newValue -> config.dungeons.secretWaypoints.waypointType = newValue) - .controller(ConfigUtils::createEnumCyclingListController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.showSecretText")) - .binding(defaults.dungeons.secretWaypoints.showSecretText, - () -> config.dungeons.secretWaypoints.showSecretText, - newValue -> config.dungeons.secretWaypoints.showSecretText = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableEntranceWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableEntranceWaypoints, - () -> config.dungeons.secretWaypoints.enableEntranceWaypoints, - newValue -> config.dungeons.secretWaypoints.enableEntranceWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableSuperboomWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableSuperboomWaypoints, - () -> config.dungeons.secretWaypoints.enableSuperboomWaypoints, - newValue -> config.dungeons.secretWaypoints.enableSuperboomWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableChestWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableChestWaypoints, - () -> config.dungeons.secretWaypoints.enableChestWaypoints, - newValue -> config.dungeons.secretWaypoints.enableChestWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableItemWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableItemWaypoints, - () -> config.dungeons.secretWaypoints.enableItemWaypoints, - newValue -> config.dungeons.secretWaypoints.enableItemWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableBatWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableBatWaypoints, - () -> config.dungeons.secretWaypoints.enableBatWaypoints, - newValue -> config.dungeons.secretWaypoints.enableBatWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableWitherWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableWitherWaypoints, - () -> config.dungeons.secretWaypoints.enableWitherWaypoints, - newValue -> config.dungeons.secretWaypoints.enableWitherWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableLeverWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableLeverWaypoints, - () -> config.dungeons.secretWaypoints.enableLeverWaypoints, - newValue -> config.dungeons.secretWaypoints.enableLeverWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableFairySoulWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableFairySoulWaypoints, - () -> config.dungeons.secretWaypoints.enableFairySoulWaypoints, - newValue -> config.dungeons.secretWaypoints.enableFairySoulWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableStonkWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableStonkWaypoints, - () -> config.dungeons.secretWaypoints.enableStonkWaypoints, - newValue -> config.dungeons.secretWaypoints.enableStonkWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableAotvWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableAotvWaypoints, - () -> config.dungeons.secretWaypoints.enableAotvWaypoints, - newValue -> config.dungeons.secretWaypoints.enableAotvWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enablePearlWaypoints")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enablePearlWaypoints.@Tooltip"))) - .binding(defaults.dungeons.secretWaypoints.enablePearlWaypoints, - () -> config.dungeons.secretWaypoints.enablePearlWaypoints, - newValue -> config.dungeons.secretWaypoints.enablePearlWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableDefaultWaypoints")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableDefaultWaypoints.@Tooltip"))) - .binding(defaults.dungeons.secretWaypoints.enableDefaultWaypoints, - () -> config.dungeons.secretWaypoints.enableDefaultWaypoints, - newValue -> config.dungeons.secretWaypoints.enableDefaultWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .build()) + // Devices (F7/M7) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.devices")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.devices.solveSimonSays")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.devices.solveSimonSays.@Tooltip"))) + .binding(defaults.dungeons.devices.solveSimonSays, + () -> config.dungeons.devices.solveSimonSays, + newValue -> config.dungeons.devices.solveSimonSays = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // Mimic Message - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.mimicMessage")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.mimicMessage.sendMimicMessage")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.mimicMessage.sendMimicMessage.@Tooltip"))) - .binding(defaults.dungeons.mimicMessage.sendMimicMessage, - () -> config.dungeons.mimicMessage.sendMimicMessage, - newValue -> config.dungeons.mimicMessage.sendMimicMessage = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.mimicMessage.mimicMessage")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.mimicMessage.mimicMessage.@Tooltip"))) - .binding(defaults.dungeons.mimicMessage.mimicMessage, - () -> config.dungeons.mimicMessage.mimicMessage, - newValue -> config.dungeons.mimicMessage.mimicMessage = newValue) - .controller(StringControllerBuilder::create) - .build()) - .build()) + // Dungeon Secret Waypoints + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableRoomMatching")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableRoomMatching.@Tooltip"))) + .binding(defaults.dungeons.secretWaypoints.enableRoomMatching, + () -> config.dungeons.secretWaypoints.enableRoomMatching, + newValue -> config.dungeons.secretWaypoints.enableRoomMatching = newValue) + .controller(ConfigUtils::createBooleanController) + .flag(OptionFlag.GAME_RESTART) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableSecretWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableSecretWaypoints, + () -> config.dungeons.secretWaypoints.enableSecretWaypoints, + newValue -> config.dungeons.secretWaypoints.enableSecretWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType.@Tooltip"), + Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType.generalNote"))) + .binding(defaults.dungeons.secretWaypoints.waypointType, + () -> config.dungeons.secretWaypoints.waypointType, + newValue -> config.dungeons.secretWaypoints.waypointType = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.showSecretText")) + .binding(defaults.dungeons.secretWaypoints.showSecretText, + () -> config.dungeons.secretWaypoints.showSecretText, + newValue -> config.dungeons.secretWaypoints.showSecretText = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableEntranceWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableEntranceWaypoints, + () -> config.dungeons.secretWaypoints.enableEntranceWaypoints, + newValue -> config.dungeons.secretWaypoints.enableEntranceWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableSuperboomWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableSuperboomWaypoints, + () -> config.dungeons.secretWaypoints.enableSuperboomWaypoints, + newValue -> config.dungeons.secretWaypoints.enableSuperboomWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableChestWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableChestWaypoints, + () -> config.dungeons.secretWaypoints.enableChestWaypoints, + newValue -> config.dungeons.secretWaypoints.enableChestWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableItemWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableItemWaypoints, + () -> config.dungeons.secretWaypoints.enableItemWaypoints, + newValue -> config.dungeons.secretWaypoints.enableItemWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableBatWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableBatWaypoints, + () -> config.dungeons.secretWaypoints.enableBatWaypoints, + newValue -> config.dungeons.secretWaypoints.enableBatWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableWitherWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableWitherWaypoints, + () -> config.dungeons.secretWaypoints.enableWitherWaypoints, + newValue -> config.dungeons.secretWaypoints.enableWitherWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableLeverWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableLeverWaypoints, + () -> config.dungeons.secretWaypoints.enableLeverWaypoints, + newValue -> config.dungeons.secretWaypoints.enableLeverWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableFairySoulWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableFairySoulWaypoints, + () -> config.dungeons.secretWaypoints.enableFairySoulWaypoints, + newValue -> config.dungeons.secretWaypoints.enableFairySoulWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableStonkWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableStonkWaypoints, + () -> config.dungeons.secretWaypoints.enableStonkWaypoints, + newValue -> config.dungeons.secretWaypoints.enableStonkWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableAotvWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableAotvWaypoints, + () -> config.dungeons.secretWaypoints.enableAotvWaypoints, + newValue -> config.dungeons.secretWaypoints.enableAotvWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enablePearlWaypoints")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enablePearlWaypoints.@Tooltip"))) + .binding(defaults.dungeons.secretWaypoints.enablePearlWaypoints, + () -> config.dungeons.secretWaypoints.enablePearlWaypoints, + newValue -> config.dungeons.secretWaypoints.enablePearlWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableDefaultWaypoints")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableDefaultWaypoints.@Tooltip"))) + .binding(defaults.dungeons.secretWaypoints.enableDefaultWaypoints, + () -> config.dungeons.secretWaypoints.enableDefaultWaypoints, + newValue -> config.dungeons.secretWaypoints.enableDefaultWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // Door Highlight - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.doorHighlight")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.doorHighlight.enableDoorHighlight")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.doorHighlight.enableDoorHighlight.@Tooltip"))) - .binding(defaults.dungeons.doorHighlight.enableDoorHighlight, - () -> config.dungeons.doorHighlight.enableDoorHighlight, - newValue -> config.dungeons.doorHighlight.enableDoorHighlight = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType.@Tooltip"), - Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType.secretWaypointsNote"))) - .binding(defaults.dungeons.doorHighlight.doorHighlightType, - () -> config.dungeons.doorHighlight.doorHighlightType, - newValue -> config.dungeons.doorHighlight.doorHighlightType = newValue) - .controller(ConfigUtils::createEnumCyclingListController) - .build()) - .build()) + // Mimic Message + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.mimicMessage")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.mimicMessage.sendMimicMessage")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.mimicMessage.sendMimicMessage.@Tooltip"))) + .binding(defaults.dungeons.mimicMessage.sendMimicMessage, + () -> config.dungeons.mimicMessage.sendMimicMessage, + newValue -> config.dungeons.mimicMessage.sendMimicMessage = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.mimicMessage.mimicMessage")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.mimicMessage.mimicMessage.@Tooltip"))) + .binding(defaults.dungeons.mimicMessage.mimicMessage, + () -> config.dungeons.mimicMessage.mimicMessage, + newValue -> config.dungeons.mimicMessage.mimicMessage = newValue) + .controller(StringControllerBuilder::create) + .build()) + .build()) - // Dungeon Score - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage", 270)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage.@Tooltip", 270))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Message, - () -> config.dungeons.dungeonScore.enableDungeonScore270Message, - newValue -> config.dungeons.dungeonScore.enableDungeonScore270Message = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle", 270)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle.@Tooltip", 270))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Title, - () -> config.dungeons.dungeonScore.enableDungeonScore270Title, - newValue -> config.dungeons.dungeonScore.enableDungeonScore270Title = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound", 270)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound.@Tooltip", 270))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Sound, - () -> config.dungeons.dungeonScore.enableDungeonScore270Sound, - newValue -> config.dungeons.dungeonScore.enableDungeonScore270Sound = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage", 270)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage.@Tooltip", 270, 270))) - .binding(defaults.dungeons.dungeonScore.dungeonScore270Message, - () -> config.dungeons.dungeonScore.dungeonScore270Message, - newValue -> config.dungeons.dungeonScore.dungeonScore270Message = newValue) - .controller(StringControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage", 300)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage.@Tooltip", 300))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Message, - () -> config.dungeons.dungeonScore.enableDungeonScore300Message, - newValue -> config.dungeons.dungeonScore.enableDungeonScore300Message = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle", 300)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle.@Tooltip", 300))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Title, - () -> config.dungeons.dungeonScore.enableDungeonScore300Title, - newValue -> config.dungeons.dungeonScore.enableDungeonScore300Title = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound", 300)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound.@Tooltip", 300))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Sound, - () -> config.dungeons.dungeonScore.enableDungeonScore300Sound, - newValue -> config.dungeons.dungeonScore.enableDungeonScore300Sound = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage", 300)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage.@Tooltip", 300, 300))) - .binding(defaults.dungeons.dungeonScore.dungeonScore300Message, - () -> config.dungeons.dungeonScore.dungeonScore300Message, - newValue -> config.dungeons.dungeonScore.dungeonScore300Message = newValue) - .controller(StringControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonCryptsMessage")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonCryptsMessage.@Tooltip"))) - .binding(defaults.dungeons.dungeonScore.enableDungeonCryptsMessage, - () -> config.dungeons.dungeonScore.enableDungeonCryptsMessage, - newValue -> config.dungeons.dungeonScore.enableDungeonCryptsMessage = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessageThreshold")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessageThreshold.@Tooltip"))) - .binding(defaults.dungeons.dungeonScore.dungeonCryptsMessageThreshold, - () -> config.dungeons.dungeonScore.dungeonCryptsMessageThreshold, - newValue -> config.dungeons.dungeonScore.dungeonCryptsMessageThreshold = newValue) - .controller(IntegerFieldControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessage")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessage.@Tooltip"))) - .binding(defaults.dungeons.dungeonScore.dungeonCryptsMessage, - () -> config.dungeons.dungeonScore.dungeonCryptsMessage, - newValue -> config.dungeons.dungeonScore.dungeonCryptsMessage = newValue) - .controller(StringControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD.@Tooltip"), - Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD.deathMessagesNote"))) - .binding(defaults.dungeons.dungeonScore.enableScoreHUD, - () -> config.dungeons.dungeonScore.enableScoreHUD, - newValue -> config.dungeons.dungeonScore.enableScoreHUD = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.scoreScaling")) - .binding(defaults.dungeons.dungeonScore.scoreScaling, - () -> config.dungeons.dungeonScore.scoreScaling, - newValue -> { - config.dungeons.dungeonScore.scoreX = config.dungeons.dungeonScore.scoreX + (int) ((config.dungeons.dungeonScore.scoreScaling - newValue) * 38.0); - config.dungeons.dungeonScore.scoreY = config.dungeons.dungeonScore.scoreY + (int) ((config.dungeons.dungeonScore.scoreScaling - newValue) * MinecraftClient.getInstance().textRenderer.fontHeight / 2.0); - config.dungeons.dungeonScore.scoreScaling = newValue; - }) - .controller(FloatFieldControllerBuilder::create) - .build()) - .build()) + // Door Highlight + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.doorHighlight")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.doorHighlight.enableDoorHighlight")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.doorHighlight.enableDoorHighlight.@Tooltip"))) + .binding(defaults.dungeons.doorHighlight.enableDoorHighlight, + () -> config.dungeons.doorHighlight.enableDoorHighlight, + newValue -> config.dungeons.doorHighlight.enableDoorHighlight = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType.@Tooltip"), + Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType.secretWaypointsNote"))) + .binding(defaults.dungeons.doorHighlight.doorHighlightType, + () -> config.dungeons.doorHighlight.doorHighlightType, + newValue -> config.dungeons.doorHighlight.doorHighlightType = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + .build()) - // Dungeon Chest Profit Calculator - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.enableProfitCalculator")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.enableProfitCalculator.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.enableProfitCalculator, - () -> config.dungeons.dungeonChestProfit.enableProfitCalculator, - newValue -> config.dungeons.dungeonChestProfit.enableProfitCalculator = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.croesusProfit")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.croesusProfit.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.croesusProfit, - () -> config.dungeons.dungeonChestProfit.croesusProfit, - newValue -> config.dungeons.dungeonChestProfit.croesusProfit = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeKismet")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeKismet.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.includeKismet, - () -> config.dungeons.dungeonChestProfit.includeKismet, - newValue -> config.dungeons.dungeonChestProfit.includeKismet = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeEssence")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeEssence.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.includeEssence, - () -> config.dungeons.dungeonChestProfit.includeEssence, - newValue -> config.dungeons.dungeonChestProfit.includeEssence = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - //FIXME maybe use color controller - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralThreshold")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralThreshold.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.neutralThreshold, - () -> config.dungeons.dungeonChestProfit.neutralThreshold, - newValue -> config.dungeons.dungeonChestProfit.neutralThreshold = newValue) - .controller(IntegerFieldControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralColor")) - .binding(defaults.dungeons.dungeonChestProfit.neutralColor, - () -> config.dungeons.dungeonChestProfit.neutralColor, - newValue -> config.dungeons.dungeonChestProfit.neutralColor = newValue) - .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.profitColor")) - .binding(defaults.dungeons.dungeonChestProfit.profitColor, - () -> config.dungeons.dungeonChestProfit.profitColor, - newValue -> config.dungeons.dungeonChestProfit.profitColor = newValue) - .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.lossColor")) - .binding(defaults.dungeons.dungeonChestProfit.lossColor, - () -> config.dungeons.dungeonChestProfit.lossColor, - newValue -> config.dungeons.dungeonChestProfit.lossColor = newValue) - .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.incompleteColor")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.incompleteColor.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.incompleteColor, - () -> config.dungeons.dungeonChestProfit.incompleteColor, - newValue -> config.dungeons.dungeonChestProfit.incompleteColor = newValue) - .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) - .build()) - .build()) + // Dungeon Score + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage", 270)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage.@Tooltip", 270))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Message, + () -> config.dungeons.dungeonScore.enableDungeonScore270Message, + newValue -> config.dungeons.dungeonScore.enableDungeonScore270Message = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle", 270)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle.@Tooltip", 270))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Title, + () -> config.dungeons.dungeonScore.enableDungeonScore270Title, + newValue -> config.dungeons.dungeonScore.enableDungeonScore270Title = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound", 270)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound.@Tooltip", 270))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Sound, + () -> config.dungeons.dungeonScore.enableDungeonScore270Sound, + newValue -> config.dungeons.dungeonScore.enableDungeonScore270Sound = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage", 270)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage.@Tooltip", 270, 270))) + .binding(defaults.dungeons.dungeonScore.dungeonScore270Message, + () -> config.dungeons.dungeonScore.dungeonScore270Message, + newValue -> config.dungeons.dungeonScore.dungeonScore270Message = newValue) + .controller(StringControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage", 300)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage.@Tooltip", 300))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Message, + () -> config.dungeons.dungeonScore.enableDungeonScore300Message, + newValue -> config.dungeons.dungeonScore.enableDungeonScore300Message = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle", 300)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle.@Tooltip", 300))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Title, + () -> config.dungeons.dungeonScore.enableDungeonScore300Title, + newValue -> config.dungeons.dungeonScore.enableDungeonScore300Title = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound", 300)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound.@Tooltip", 300))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Sound, + () -> config.dungeons.dungeonScore.enableDungeonScore300Sound, + newValue -> config.dungeons.dungeonScore.enableDungeonScore300Sound = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage", 300)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage.@Tooltip", 300, 300))) + .binding(defaults.dungeons.dungeonScore.dungeonScore300Message, + () -> config.dungeons.dungeonScore.dungeonScore300Message, + newValue -> config.dungeons.dungeonScore.dungeonScore300Message = newValue) + .controller(StringControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonCryptsMessage")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonCryptsMessage.@Tooltip"))) + .binding(defaults.dungeons.dungeonScore.enableDungeonCryptsMessage, + () -> config.dungeons.dungeonScore.enableDungeonCryptsMessage, + newValue -> config.dungeons.dungeonScore.enableDungeonCryptsMessage = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessageThreshold")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessageThreshold.@Tooltip"))) + .binding(defaults.dungeons.dungeonScore.dungeonCryptsMessageThreshold, + () -> config.dungeons.dungeonScore.dungeonCryptsMessageThreshold, + newValue -> config.dungeons.dungeonScore.dungeonCryptsMessageThreshold = newValue) + .controller(IntegerFieldControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessage")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessage.@Tooltip"))) + .binding(defaults.dungeons.dungeonScore.dungeonCryptsMessage, + () -> config.dungeons.dungeonScore.dungeonCryptsMessage, + newValue -> config.dungeons.dungeonScore.dungeonCryptsMessage = newValue) + .controller(StringControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD.@Tooltip"), + Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD.deathMessagesNote"))) + .binding(defaults.dungeons.dungeonScore.enableScoreHUD, + () -> config.dungeons.dungeonScore.enableScoreHUD, + newValue -> config.dungeons.dungeonScore.enableScoreHUD = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.scoreScaling")) + .binding(defaults.dungeons.dungeonScore.scoreScaling, + () -> config.dungeons.dungeonScore.scoreScaling, + newValue -> { + config.dungeons.dungeonScore.scoreX = config.dungeons.dungeonScore.scoreX + (int) ((config.dungeons.dungeonScore.scoreScaling - newValue) * 38.0); + config.dungeons.dungeonScore.scoreY = config.dungeons.dungeonScore.scoreY + (int) ((config.dungeons.dungeonScore.scoreScaling - newValue) * MinecraftClient.getInstance().textRenderer.fontHeight / 2.0); + config.dungeons.dungeonScore.scoreScaling = newValue; + }) + .controller(FloatFieldControllerBuilder::create) + .build()) + .build()) - .build(); - } + // Dungeon Chest Profit Calculator + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.enableProfitCalculator")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.enableProfitCalculator.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.enableProfitCalculator, + () -> config.dungeons.dungeonChestProfit.enableProfitCalculator, + newValue -> config.dungeons.dungeonChestProfit.enableProfitCalculator = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.croesusProfit")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.croesusProfit.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.croesusProfit, + () -> config.dungeons.dungeonChestProfit.croesusProfit, + newValue -> config.dungeons.dungeonChestProfit.croesusProfit = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeKismet")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeKismet.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.includeKismet, + () -> config.dungeons.dungeonChestProfit.includeKismet, + newValue -> config.dungeons.dungeonChestProfit.includeKismet = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeEssence")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeEssence.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.includeEssence, + () -> config.dungeons.dungeonChestProfit.includeEssence, + newValue -> config.dungeons.dungeonChestProfit.includeEssence = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + //FIXME maybe use color controller + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralThreshold")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralThreshold.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.neutralThreshold, + () -> config.dungeons.dungeonChestProfit.neutralThreshold, + newValue -> config.dungeons.dungeonChestProfit.neutralThreshold = newValue) + .controller(IntegerFieldControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralColor")) + .binding(defaults.dungeons.dungeonChestProfit.neutralColor, + () -> config.dungeons.dungeonChestProfit.neutralColor, + newValue -> config.dungeons.dungeonChestProfit.neutralColor = newValue) + .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.profitColor")) + .binding(defaults.dungeons.dungeonChestProfit.profitColor, + () -> config.dungeons.dungeonChestProfit.profitColor, + newValue -> config.dungeons.dungeonChestProfit.profitColor = newValue) + .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.lossColor")) + .binding(defaults.dungeons.dungeonChestProfit.lossColor, + () -> config.dungeons.dungeonChestProfit.lossColor, + newValue -> config.dungeons.dungeonChestProfit.lossColor = newValue) + .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.incompleteColor")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.incompleteColor.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.incompleteColor, + () -> config.dungeons.dungeonChestProfit.incompleteColor, + newValue -> config.dungeons.dungeonChestProfit.incompleteColor = newValue) + .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) + .build()) + .build()) + + .build(); + } } diff --git a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java index 7b394b53..2a3075bc 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java @@ -41,6 +41,9 @@ public class DungeonsConfig { @SerialEntry public Terminals terminals = new Terminals(); + @SerialEntry + public Devices devices = new Devices(); + @SerialEntry public SecretWaypoints secretWaypoints = new SecretWaypoints(); @@ -135,6 +138,11 @@ public class DungeonsConfig { public boolean blockIncorrectClicks = false; } + public static class Devices { + @SerialEntry + public boolean solveSimonSays = true; + } + public static class SecretWaypoints { @SerialEntry public boolean enableRoomMatching = true; diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java index 6c10e5d2..83a23b46 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.mixins; - import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager; +import de.hysky.skyblocker.skyblock.dungeon.device.SimonSays; import de.hysky.skyblocker.utils.Utils; import net.minecraft.block.BlockState; import net.minecraft.client.world.ClientWorld; @@ -11,13 +11,20 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import com.llamalad7.mixinextras.sugar.Local; + @Mixin(ClientWorld.class) public class ClientWorldMixin { + /** + * @implNote The {@code pos} can be mutable when this is called by chunk delta updates, so if you want to copy it into memory + * (e.g. store it in a field/list/map) make sure to duplicate it via {@link BlockPos#BlockPos(net.minecraft.util.math.Vec3i)}. + */ @Inject(method = "handleBlockUpdate", at = @At("RETURN")) - private void skyblocker$handleBlockUpdate(BlockPos pos, BlockState state, int flags, CallbackInfo ci) { + private void skyblocker$handleBlockUpdate(CallbackInfo ci, @Local(argsOnly = true) BlockPos pos, @Local(argsOnly = true) BlockState state) { if (Utils.isInCrimson()) { DojoManager.onBlockUpdate(pos.toImmutable(), state); + SimonSays.onBlockUpdate(pos, state); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java new file mode 100644 index 00000000..341c6025 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java @@ -0,0 +1,124 @@ +package de.hysky.skyblocker.skyblock.dungeon.device; + +import java.util.Objects; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.dungeon.DungeonBoss; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; +import de.hysky.skyblocker.utils.Boxes; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.render.RenderHelper; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.DyeColor; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class SimonSays { + private static final Box BOARD_AREA = Box.enclosing(new BlockPos(111, 123, 92), new BlockPos(111, 120, 95)); + private static final Box BUTTONS_AREA = Box.enclosing(new BlockPos(110, 123, 92), new BlockPos(110, 120, 95)); + private static final BlockPos START_BUTTON = new BlockPos(110, 121, 91); + private static final float[] GREEN = DyeColor.LIME.getColorComponents(); + private static final float[] YELLOW = DyeColor.YELLOW.getColorComponents(); + private static final ObjectSet CLICKED_BUTTONS = new ObjectOpenHashSet<>(); + private static final Int2ObjectRBTreeMap SIMON_PATTERN = new Int2ObjectRBTreeMap<>(); + + public static void init() { + UseBlockCallback.EVENT.register(SimonSays::onBlockInteract); + ClientPlayConnectionEvents.JOIN.register((_handler, _sender, _client) -> reset()); + WorldRenderEvents.AFTER_TRANSLUCENT.register(SimonSays::render); + } + + //When another player is pressing the buttons hypixel doesnt send block or block state updates + //so you can't see it which means the solver can only count the buttons you press yourself + private static ActionResult onBlockInteract(PlayerEntity player, World world, Hand hand, BlockHitResult hitResult) { + if (shouldProcess()) { + BlockPos pos = hitResult.getBlockPos(); + Block block = world.getBlockState(pos).getBlock(); + + if (block.equals(Blocks.STONE_BUTTON)) { + if (BUTTONS_AREA.contains(Vec3d.of(pos))) { + CLICKED_BUTTONS.add(new BlockPos(pos)); //Copy just in case it becomes mutable in the future + } else if (pos.equals(START_BUTTON)) { + reset(); + } + } + } + + //This could also be used to cancel incorrect clicks in the future + return ActionResult.PASS; + } + + //If the player goes out of the range required to receive block/chunk updates then their solver won't detect stuff but that + //doesn't matter because if they're doing pre-4 or something they won't be doing the ss, and if they end up needing to they can + //just reset it or have the other person finish the current sequence first then let them do it. + public static void onBlockUpdate(BlockPos pos, BlockState state) { + if (shouldProcess()) { + Vec3d posVec = Vec3d.of(pos); + Block block = state.getBlock(); + + if (BOARD_AREA.contains(posVec) && block.equals(Blocks.SEA_LANTERN)) { + int nextIndex = SIMON_PATTERN.size() + 1; + + SIMON_PATTERN.put(nextIndex, new BlockPos(pos)); //Copy it because it can be mutable in chunk delta updates + } else if (BUTTONS_AREA.contains(posVec) && block.equals(Blocks.AIR)) { + //Upon reaching the showing of the next sequence we need to reset the state so that we don't show old data + //Otherwise, the nextIndex will go beyond 5 and that can cause bugs, it also helps with the other case noted above + reset(); + } + } + } + + private static void render(WorldRenderContext context) { + if (shouldProcess()) { + int buttonsRendered = 0; + + //Tree maps iterate in natural order of key - so it goes from the lowest to the highest int :) + for (Int2ObjectMap.Entry entry : SIMON_PATTERN.int2ObjectEntrySet()) { + //Offset to west (x - 1) to get the position of the button from the sea lantern block + BlockPos buttonPos = entry.getValue().west(); + ClientWorld world = Objects.requireNonNull(MinecraftClient.getInstance().world); //Should never be null here + BlockState state = world.getBlockState(buttonPos); + + //If the button hasn't been clicked yet + //Also don't do anything if the button isn't there which means the device is showing the sequence + if (!CLICKED_BUTTONS.contains(buttonPos) && state.getBlock().equals(Blocks.STONE_BUTTON)) { + Box outline = state.getOutlineShape(world, buttonPos).asCuboid().getBoundingBox().offset(buttonPos); + float[] colour = buttonsRendered == 0 ? GREEN : YELLOW; + + RenderHelper.renderFilled(context, Boxes.getMinVec(outline), Boxes.getLengthVec(outline), colour, 0.5f, true); + RenderHelper.renderOutline(context, outline, colour, 5f, true); + + if (++buttonsRendered == 2) return; + } + } + } + } + + private static boolean shouldProcess() { + return SkyblockerConfigManager.get().dungeons.devices.solveSimonSays && + Utils.isInDungeons() && DungeonManager.isInBoss() && DungeonManager.getBoss() == DungeonBoss.MAXOR; + } + + private static void reset() { + CLICKED_BUTTONS.clear(); + SIMON_PATTERN.clear(); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java index a5b9bf6b..6a53e4c4 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java @@ -64,18 +64,22 @@ public class RenderHelper { } public static void renderFilled(WorldRenderContext context, BlockPos pos, Vec3d dimensions, float[] colorComponents, float alpha, boolean throughWalls) { + renderFilled(context, Vec3d.of(pos), dimensions, colorComponents, alpha, throughWalls); + } + + public static void renderFilled(WorldRenderContext context, Vec3d pos, Vec3d dimensions, float[] colorComponents, float alpha, boolean throughWalls) { if (throughWalls) { if (FrustumUtils.isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + dimensions.x, pos.getY() + dimensions.y, pos.getZ() + dimensions.z)) { - renderFilled(context, Vec3d.of(pos), dimensions, colorComponents, alpha, true); + renderFilledInternal(context, pos, dimensions, colorComponents, alpha, true); } } else { if (OcclusionCulling.getRegularCuller().isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + dimensions.x, pos.getY() + dimensions.y, pos.getZ() + dimensions.z)) { - renderFilled(context, Vec3d.of(pos), dimensions, colorComponents, alpha, false); + renderFilledInternal(context, pos, dimensions, colorComponents, alpha, false); } } } - private static void renderFilled(WorldRenderContext context, Vec3d pos, Vec3d dimensions, float[] colorComponents, float alpha, boolean throughWalls) { + private static void renderFilledInternal(WorldRenderContext context, Vec3d pos, Vec3d dimensions, float[] colorComponents, float alpha, boolean throughWalls) { MatrixStack matrices = context.matrixStack(); Vec3d camera = context.camera().getPos(); -- cgit From 41b575e41545fbea3b38deb516ba580251a9cd0b Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Wed, 29 May 2024 14:53:18 -0400 Subject: Move block bounding box into RenderHelper --- .../de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java | 2 +- .../java/de/hysky/skyblocker/utils/render/RenderHelper.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java index 341c6025..20bd9ebc 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java @@ -100,7 +100,7 @@ public class SimonSays { //If the button hasn't been clicked yet //Also don't do anything if the button isn't there which means the device is showing the sequence if (!CLICKED_BUTTONS.contains(buttonPos) && state.getBlock().equals(Blocks.STONE_BUTTON)) { - Box outline = state.getOutlineShape(world, buttonPos).asCuboid().getBoundingBox().offset(buttonPos); + Box outline = RenderHelper.getBlockBoundingBox(world, state, buttonPos); float[] colour = buttonsRendered == 0 ? GREEN : YELLOW; RenderHelper.renderFilled(context, Boxes.getMinVec(outline), Boxes.getLengthVec(outline), colour, 0.5f, true); diff --git a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java index 6a53e4c4..1b16b138 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java @@ -11,6 +11,7 @@ import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.event.Event; +import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -20,6 +21,7 @@ import net.minecraft.client.texture.Scaling; import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.BufferAllocator; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.world.ClientWorld; import net.minecraft.sound.SoundEvents; import net.minecraft.text.OrderedText; import net.minecraft.text.Text; @@ -334,6 +336,14 @@ public class RenderHelper { } } + public static Box getBlockBoundingBox(ClientWorld world, BlockPos pos) { + return getBlockBoundingBox(world, world.getBlockState(pos), pos); + } + + public static Box getBlockBoundingBox(ClientWorld world, BlockState state, BlockPos pos) { + return state.getOutlineShape(world, pos).asCuboid().getBoundingBox().offset(pos); + } + /** * Adds the title to {@link TitleContainer} and {@link #playNotificationSound() plays the notification sound} if the title is not in the {@link TitleContainer} already. * No checking needs to be done on whether the title is in the {@link TitleContainer} already by the caller. -- cgit From 99e70f1d9aaafa5f9f39500efbc474eda561eda8 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Wed, 10 Jul 2024 15:49:11 -0400 Subject: Port Simon Says solver to 1.21 --- .../java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java index 20bd9ebc..0c78c2d3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java @@ -6,6 +6,7 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.dungeon.DungeonBoss; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.utils.Boxes; +import de.hysky.skyblocker.utils.ColorUtils; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -35,8 +36,8 @@ public class SimonSays { private static final Box BOARD_AREA = Box.enclosing(new BlockPos(111, 123, 92), new BlockPos(111, 120, 95)); private static final Box BUTTONS_AREA = Box.enclosing(new BlockPos(110, 123, 92), new BlockPos(110, 120, 95)); private static final BlockPos START_BUTTON = new BlockPos(110, 121, 91); - private static final float[] GREEN = DyeColor.LIME.getColorComponents(); - private static final float[] YELLOW = DyeColor.YELLOW.getColorComponents(); + private static final float[] GREEN = ColorUtils.getFloatComponents(DyeColor.LIME); + private static final float[] YELLOW = ColorUtils.getFloatComponents(DyeColor.YELLOW); private static final ObjectSet CLICKED_BUTTONS = new ObjectOpenHashSet<>(); private static final Int2ObjectRBTreeMap SIMON_PATTERN = new Int2ObjectRBTreeMap<>(); -- cgit From 8f8b583c31955c192856126d3ce48810d301f016 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Wed, 10 Jul 2024 16:03:19 -0400 Subject: Refactor Simon Says solver Should be less conflicting with other things --- .../config/categories/DungeonsCategory.java | 1232 ++++++++++---------- .../hysky/skyblocker/mixins/ClientWorldMixin.java | 4 +- .../skyblock/dungeon/device/SimonSays.java | 15 +- 3 files changed, 624 insertions(+), 627 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java index 36999778..4a804650 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -15,633 +15,633 @@ import net.minecraft.util.Formatting; public class DungeonsCategory { - public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { - return ConfigCategory.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons")) + public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { + return ConfigCategory.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons")) - //Ungrouped Options - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.fancyPartyFinder")) - .binding(defaults.dungeons.fancyPartyFinder, - () -> config.dungeons.fancyPartyFinder, - newValue -> config.dungeons.fancyPartyFinder = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.croesusHelper")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.croesusHelper.@Tooltip"))) - .binding(defaults.dungeons.croesusHelper, - () -> config.dungeons.croesusHelper, - newValue -> config.dungeons.croesusHelper = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.playerSecretsTracker")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.playerSecretsTracker.@Tooltip"))) - .binding(defaults.dungeons.playerSecretsTracker, - () -> config.dungeons.playerSecretsTracker, - newValue -> config.dungeons.playerSecretsTracker = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.starredMobGlow")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobGlow.@Tooltip"))) - .binding(defaults.dungeons.starredMobGlow, - () -> config.dungeons.starredMobGlow, - newValue -> config.dungeons.starredMobGlow = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.starredMobBoundingBoxes")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobBoundingBoxes.@Tooltip"))) - .binding(defaults.dungeons.starredMobBoundingBoxes, - () -> config.dungeons.starredMobBoundingBoxes, - newValue -> config.dungeons.starredMobBoundingBoxes = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.allowDroppingProtectedItems")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.allowDroppingProtectedItems.@Tooltip"))) - .binding(defaults.dungeons.allowDroppingProtectedItems, - () -> config.dungeons.allowDroppingProtectedItems, - newValue -> config.dungeons.allowDroppingProtectedItems = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.hideSoulweaverSkulls")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.hideSoulweaverSkulls.@Tooltip"))) - .binding(defaults.dungeons.hideSoulweaverSkulls, - () -> config.dungeons.hideSoulweaverSkulls, - newValue -> config.dungeons.hideSoulweaverSkulls = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) + //Ungrouped Options + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.fancyPartyFinder")) + .binding(defaults.dungeons.fancyPartyFinder, + () -> config.dungeons.fancyPartyFinder, + newValue -> config.dungeons.fancyPartyFinder = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.croesusHelper")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.croesusHelper.@Tooltip"))) + .binding(defaults.dungeons.croesusHelper, + () -> config.dungeons.croesusHelper, + newValue -> config.dungeons.croesusHelper = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.playerSecretsTracker")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.playerSecretsTracker.@Tooltip"))) + .binding(defaults.dungeons.playerSecretsTracker, + () -> config.dungeons.playerSecretsTracker, + newValue -> config.dungeons.playerSecretsTracker = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.starredMobGlow")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobGlow.@Tooltip"))) + .binding(defaults.dungeons.starredMobGlow, + () -> config.dungeons.starredMobGlow, + newValue -> config.dungeons.starredMobGlow = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.starredMobBoundingBoxes")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobBoundingBoxes.@Tooltip"))) + .binding(defaults.dungeons.starredMobBoundingBoxes, + () -> config.dungeons.starredMobBoundingBoxes, + newValue -> config.dungeons.starredMobBoundingBoxes = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.allowDroppingProtectedItems")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.allowDroppingProtectedItems.@Tooltip"))) + .binding(defaults.dungeons.allowDroppingProtectedItems, + () -> config.dungeons.allowDroppingProtectedItems, + newValue -> config.dungeons.allowDroppingProtectedItems = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.hideSoulweaverSkulls")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.hideSoulweaverSkulls.@Tooltip"))) + .binding(defaults.dungeons.hideSoulweaverSkulls, + () -> config.dungeons.hideSoulweaverSkulls, + newValue -> config.dungeons.hideSoulweaverSkulls = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) - // Map - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.map")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.map.enableMap")) - .binding(defaults.dungeons.dungeonMap.enableMap, - () -> config.dungeons.dungeonMap.enableMap, - newValue -> config.dungeons.dungeonMap.enableMap = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.map.mapScaling")) - .binding(defaults.dungeons.dungeonMap.mapScaling, - () -> config.dungeons.dungeonMap.mapScaling, - newValue -> config.dungeons.dungeonMap.mapScaling = newValue) - .controller(FloatFieldControllerBuilder::create) - .build()) - .option(ButtonOption.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.map.mapScreen")) - .text(Text.translatable("text.skyblocker.open")) - .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new DungeonMapConfigScreen(screen))) - .build()) - .build()) + // Map + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map.enableMap")) + .binding(defaults.dungeons.dungeonMap.enableMap, + () -> config.dungeons.dungeonMap.enableMap, + newValue -> config.dungeons.dungeonMap.enableMap = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map.mapScaling")) + .binding(defaults.dungeons.dungeonMap.mapScaling, + () -> config.dungeons.dungeonMap.mapScaling, + newValue -> config.dungeons.dungeonMap.mapScaling = newValue) + .controller(FloatFieldControllerBuilder::create) + .build()) + .option(ButtonOption.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map.mapScreen")) + .text(Text.translatable("text.skyblocker.open")) + .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new DungeonMapConfigScreen(screen))) + .build()) + .build()) - // Puzzle Solver - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveTicTacToe")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveTicTacToe.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.solveTicTacToe, - () -> config.dungeons.puzzleSolvers.solveTicTacToe, - newValue -> config.dungeons.puzzleSolvers.solveTicTacToe = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveThreeWeirdos")) - .binding(defaults.dungeons.puzzleSolvers.solveThreeWeirdos, - () -> config.dungeons.puzzleSolvers.solveThreeWeirdos, - newValue -> config.dungeons.puzzleSolvers.solveThreeWeirdos = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.creeperSolver")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.creeperSolver.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.creeperSolver, - () -> config.dungeons.puzzleSolvers.creeperSolver, - newValue -> config.dungeons.puzzleSolvers.creeperSolver = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveWaterboard")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveWaterboard.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.solveWaterboard, - () -> config.dungeons.puzzleSolvers.solveWaterboard, - newValue -> config.dungeons.puzzleSolvers.solveWaterboard = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.blazeSolver")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.blazeSolver.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.blazeSolver, - () -> config.dungeons.puzzleSolvers.blazeSolver, - newValue -> config.dungeons.puzzleSolvers.blazeSolver = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveBoulder")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveBoulder.@Tooltip"))) - .binding(defaults.dungeons.puzzleSolvers.solveBoulder, - () -> config.dungeons.puzzleSolvers.solveBoulder, - newValue -> config.dungeons.puzzleSolvers.solveBoulder = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveIceFill")) - .binding(defaults.dungeons.puzzleSolvers.solveIceFill, - () -> config.dungeons.puzzleSolvers.solveIceFill, - newValue -> config.dungeons.puzzleSolvers.solveIceFill = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveSilverfish")) - .binding(defaults.dungeons.puzzleSolvers.solveSilverfish, - () -> config.dungeons.puzzleSolvers.solveSilverfish, - newValue -> config.dungeons.puzzleSolvers.solveSilverfish = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveTrivia")) - .binding(defaults.dungeons.puzzleSolvers.solveTrivia, - () -> config.dungeons.puzzleSolvers.solveTrivia, - newValue -> config.dungeons.puzzleSolvers.solveTrivia = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .build()) + // Puzzle Solver + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveTicTacToe")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveTicTacToe.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.solveTicTacToe, + () -> config.dungeons.puzzleSolvers.solveTicTacToe, + newValue -> config.dungeons.puzzleSolvers.solveTicTacToe = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveThreeWeirdos")) + .binding(defaults.dungeons.puzzleSolvers.solveThreeWeirdos, + () -> config.dungeons.puzzleSolvers.solveThreeWeirdos, + newValue -> config.dungeons.puzzleSolvers.solveThreeWeirdos = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.creeperSolver")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.creeperSolver.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.creeperSolver, + () -> config.dungeons.puzzleSolvers.creeperSolver, + newValue -> config.dungeons.puzzleSolvers.creeperSolver = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveWaterboard")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveWaterboard.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.solveWaterboard, + () -> config.dungeons.puzzleSolvers.solveWaterboard, + newValue -> config.dungeons.puzzleSolvers.solveWaterboard = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.blazeSolver")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.blazeSolver.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.blazeSolver, + () -> config.dungeons.puzzleSolvers.blazeSolver, + newValue -> config.dungeons.puzzleSolvers.blazeSolver = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveBoulder")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.puzzle.solveBoulder.@Tooltip"))) + .binding(defaults.dungeons.puzzleSolvers.solveBoulder, + () -> config.dungeons.puzzleSolvers.solveBoulder, + newValue -> config.dungeons.puzzleSolvers.solveBoulder = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveIceFill")) + .binding(defaults.dungeons.puzzleSolvers.solveIceFill, + () -> config.dungeons.puzzleSolvers.solveIceFill, + newValue -> config.dungeons.puzzleSolvers.solveIceFill = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveSilverfish")) + .binding(defaults.dungeons.puzzleSolvers.solveSilverfish, + () -> config.dungeons.puzzleSolvers.solveSilverfish, + newValue -> config.dungeons.puzzleSolvers.solveSilverfish = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.puzzle.solveTrivia")) + .binding(defaults.dungeons.puzzleSolvers.solveTrivia, + () -> config.dungeons.puzzleSolvers.solveTrivia, + newValue -> config.dungeons.puzzleSolvers.solveTrivia = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // The Professor (F3/M3) - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.professor")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.professor.fireFreezeStaffTimer")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.professor.fireFreezeStaffTimer.@Tooltip"))) - .binding(defaults.dungeons.theProfessor.fireFreezeStaffTimer, - () -> config.dungeons.theProfessor.fireFreezeStaffTimer, - newValue -> config.dungeons.theProfessor.fireFreezeStaffTimer = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.professor.floor3GuardianHealthDisplay")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.professor.floor3GuardianHealthDisplay.@Tooltip"))) - .binding(defaults.dungeons.theProfessor.floor3GuardianHealthDisplay, - () -> config.dungeons.theProfessor.floor3GuardianHealthDisplay, - newValue -> config.dungeons.theProfessor.floor3GuardianHealthDisplay = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .build()) + // The Professor (F3/M3) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.professor")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.professor.fireFreezeStaffTimer")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.professor.fireFreezeStaffTimer.@Tooltip"))) + .binding(defaults.dungeons.theProfessor.fireFreezeStaffTimer, + () -> config.dungeons.theProfessor.fireFreezeStaffTimer, + newValue -> config.dungeons.theProfessor.fireFreezeStaffTimer = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.professor.floor3GuardianHealthDisplay")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.professor.floor3GuardianHealthDisplay.@Tooltip"))) + .binding(defaults.dungeons.theProfessor.floor3GuardianHealthDisplay, + () -> config.dungeons.theProfessor.floor3GuardianHealthDisplay, + newValue -> config.dungeons.theProfessor.floor3GuardianHealthDisplay = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // Livid (F5/M5) - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorGlow")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorGlow.@Tooltip"))) - .binding(defaults.dungeons.livid.enableLividColorGlow, - () -> config.dungeons.livid.enableLividColorGlow, - newValue -> config.dungeons.livid.enableLividColorGlow = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorText")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorText.@Tooltip"))) - .binding(defaults.dungeons.livid.enableLividColorText, - () -> config.dungeons.livid.enableLividColorText, - newValue -> config.dungeons.livid.enableLividColorText = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorTitle")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorTitle.@Tooltip"))) - .binding(defaults.dungeons.livid.enableLividColorTitle, - () -> config.dungeons.livid.enableLividColorTitle, - newValue -> config.dungeons.livid.enableLividColorTitle = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.livid.lividColorText")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.lividColorText.@Tooltip"))) - .binding(defaults.dungeons.livid.lividColorText, - () -> config.dungeons.livid.lividColorText, - newValue -> config.dungeons.livid.lividColorText = newValue) - .controller(StringControllerBuilder::create) - .build()) - .build()) + // Livid (F5/M5) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorGlow")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorGlow.@Tooltip"))) + .binding(defaults.dungeons.livid.enableLividColorGlow, + () -> config.dungeons.livid.enableLividColorGlow, + newValue -> config.dungeons.livid.enableLividColorGlow = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorText")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorText.@Tooltip"))) + .binding(defaults.dungeons.livid.enableLividColorText, + () -> config.dungeons.livid.enableLividColorText, + newValue -> config.dungeons.livid.enableLividColorText = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorTitle")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.enableLividColorTitle.@Tooltip"))) + .binding(defaults.dungeons.livid.enableLividColorTitle, + () -> config.dungeons.livid.enableLividColorTitle, + newValue -> config.dungeons.livid.enableLividColorTitle = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.livid.lividColorText")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.livid.lividColorText.@Tooltip"))) + .binding(defaults.dungeons.livid.lividColorText, + () -> config.dungeons.livid.lividColorText, + newValue -> config.dungeons.livid.lividColorText = newValue) + .controller(StringControllerBuilder::create) + .build()) + .build()) - // Terminal (F7/M7) - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals.solveColor")) - .binding(defaults.dungeons.terminals.solveColor, - () -> config.dungeons.terminals.solveColor, - newValue -> config.dungeons.terminals.solveColor = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals.solveOrder")) - .binding(defaults.dungeons.terminals.solveOrder, - () -> config.dungeons.terminals.solveOrder, - newValue -> config.dungeons.terminals.solveOrder = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals.solveStartsWith")) - .binding(defaults.dungeons.terminals.solveStartsWith, - () -> config.dungeons.terminals.solveStartsWith, - newValue -> config.dungeons.terminals.solveStartsWith = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.terminals.blockIncorrectClicks")) - .binding(defaults.dungeons.terminals.blockIncorrectClicks, - () -> config.dungeons.terminals.blockIncorrectClicks, - newValue -> config.dungeons.terminals.blockIncorrectClicks = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .build()) + // Terminal (F7/M7) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals.solveColor")) + .binding(defaults.dungeons.terminals.solveColor, + () -> config.dungeons.terminals.solveColor, + newValue -> config.dungeons.terminals.solveColor = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals.solveOrder")) + .binding(defaults.dungeons.terminals.solveOrder, + () -> config.dungeons.terminals.solveOrder, + newValue -> config.dungeons.terminals.solveOrder = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals.solveStartsWith")) + .binding(defaults.dungeons.terminals.solveStartsWith, + () -> config.dungeons.terminals.solveStartsWith, + newValue -> config.dungeons.terminals.solveStartsWith = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.terminals.blockIncorrectClicks")) + .binding(defaults.dungeons.terminals.blockIncorrectClicks, + () -> config.dungeons.terminals.blockIncorrectClicks, + newValue -> config.dungeons.terminals.blockIncorrectClicks = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // Devices (F7/M7) - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.devices")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.devices.solveSimonSays")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.devices.solveSimonSays.@Tooltip"))) - .binding(defaults.dungeons.devices.solveSimonSays, - () -> config.dungeons.devices.solveSimonSays, - newValue -> config.dungeons.devices.solveSimonSays = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .build()) + // Devices (F7/M7) + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.devices")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.devices.solveSimonSays")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.devices.solveSimonSays.@Tooltip"))) + .binding(defaults.dungeons.devices.solveSimonSays, + () -> config.dungeons.devices.solveSimonSays, + newValue -> config.dungeons.devices.solveSimonSays = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // Dungeon Secret Waypoints - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableRoomMatching")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableRoomMatching.@Tooltip"))) - .binding(defaults.dungeons.secretWaypoints.enableRoomMatching, - () -> config.dungeons.secretWaypoints.enableRoomMatching, - newValue -> config.dungeons.secretWaypoints.enableRoomMatching = newValue) - .controller(ConfigUtils::createBooleanController) - .flag(OptionFlag.GAME_RESTART) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableSecretWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableSecretWaypoints, - () -> config.dungeons.secretWaypoints.enableSecretWaypoints, - newValue -> config.dungeons.secretWaypoints.enableSecretWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType.@Tooltip"), - Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType.generalNote"))) - .binding(defaults.dungeons.secretWaypoints.waypointType, - () -> config.dungeons.secretWaypoints.waypointType, - newValue -> config.dungeons.secretWaypoints.waypointType = newValue) - .controller(ConfigUtils::createEnumCyclingListController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.showSecretText")) - .binding(defaults.dungeons.secretWaypoints.showSecretText, - () -> config.dungeons.secretWaypoints.showSecretText, - newValue -> config.dungeons.secretWaypoints.showSecretText = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableEntranceWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableEntranceWaypoints, - () -> config.dungeons.secretWaypoints.enableEntranceWaypoints, - newValue -> config.dungeons.secretWaypoints.enableEntranceWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableSuperboomWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableSuperboomWaypoints, - () -> config.dungeons.secretWaypoints.enableSuperboomWaypoints, - newValue -> config.dungeons.secretWaypoints.enableSuperboomWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableChestWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableChestWaypoints, - () -> config.dungeons.secretWaypoints.enableChestWaypoints, - newValue -> config.dungeons.secretWaypoints.enableChestWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableItemWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableItemWaypoints, - () -> config.dungeons.secretWaypoints.enableItemWaypoints, - newValue -> config.dungeons.secretWaypoints.enableItemWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableBatWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableBatWaypoints, - () -> config.dungeons.secretWaypoints.enableBatWaypoints, - newValue -> config.dungeons.secretWaypoints.enableBatWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableWitherWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableWitherWaypoints, - () -> config.dungeons.secretWaypoints.enableWitherWaypoints, - newValue -> config.dungeons.secretWaypoints.enableWitherWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableLeverWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableLeverWaypoints, - () -> config.dungeons.secretWaypoints.enableLeverWaypoints, - newValue -> config.dungeons.secretWaypoints.enableLeverWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableFairySoulWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableFairySoulWaypoints, - () -> config.dungeons.secretWaypoints.enableFairySoulWaypoints, - newValue -> config.dungeons.secretWaypoints.enableFairySoulWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableStonkWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableStonkWaypoints, - () -> config.dungeons.secretWaypoints.enableStonkWaypoints, - newValue -> config.dungeons.secretWaypoints.enableStonkWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableAotvWaypoints")) - .binding(defaults.dungeons.secretWaypoints.enableAotvWaypoints, - () -> config.dungeons.secretWaypoints.enableAotvWaypoints, - newValue -> config.dungeons.secretWaypoints.enableAotvWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enablePearlWaypoints")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enablePearlWaypoints.@Tooltip"))) - .binding(defaults.dungeons.secretWaypoints.enablePearlWaypoints, - () -> config.dungeons.secretWaypoints.enablePearlWaypoints, - newValue -> config.dungeons.secretWaypoints.enablePearlWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableDefaultWaypoints")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableDefaultWaypoints.@Tooltip"))) - .binding(defaults.dungeons.secretWaypoints.enableDefaultWaypoints, - () -> config.dungeons.secretWaypoints.enableDefaultWaypoints, - newValue -> config.dungeons.secretWaypoints.enableDefaultWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .build()) + // Dungeon Secret Waypoints + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableRoomMatching")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableRoomMatching.@Tooltip"))) + .binding(defaults.dungeons.secretWaypoints.enableRoomMatching, + () -> config.dungeons.secretWaypoints.enableRoomMatching, + newValue -> config.dungeons.secretWaypoints.enableRoomMatching = newValue) + .controller(ConfigUtils::createBooleanController) + .flag(OptionFlag.GAME_RESTART) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableSecretWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableSecretWaypoints, + () -> config.dungeons.secretWaypoints.enableSecretWaypoints, + newValue -> config.dungeons.secretWaypoints.enableSecretWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType.@Tooltip"), + Text.translatable("skyblocker.config.dungeons.secretWaypoints.waypointType.generalNote"))) + .binding(defaults.dungeons.secretWaypoints.waypointType, + () -> config.dungeons.secretWaypoints.waypointType, + newValue -> config.dungeons.secretWaypoints.waypointType = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.showSecretText")) + .binding(defaults.dungeons.secretWaypoints.showSecretText, + () -> config.dungeons.secretWaypoints.showSecretText, + newValue -> config.dungeons.secretWaypoints.showSecretText = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableEntranceWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableEntranceWaypoints, + () -> config.dungeons.secretWaypoints.enableEntranceWaypoints, + newValue -> config.dungeons.secretWaypoints.enableEntranceWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableSuperboomWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableSuperboomWaypoints, + () -> config.dungeons.secretWaypoints.enableSuperboomWaypoints, + newValue -> config.dungeons.secretWaypoints.enableSuperboomWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableChestWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableChestWaypoints, + () -> config.dungeons.secretWaypoints.enableChestWaypoints, + newValue -> config.dungeons.secretWaypoints.enableChestWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableItemWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableItemWaypoints, + () -> config.dungeons.secretWaypoints.enableItemWaypoints, + newValue -> config.dungeons.secretWaypoints.enableItemWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableBatWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableBatWaypoints, + () -> config.dungeons.secretWaypoints.enableBatWaypoints, + newValue -> config.dungeons.secretWaypoints.enableBatWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableWitherWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableWitherWaypoints, + () -> config.dungeons.secretWaypoints.enableWitherWaypoints, + newValue -> config.dungeons.secretWaypoints.enableWitherWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableLeverWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableLeverWaypoints, + () -> config.dungeons.secretWaypoints.enableLeverWaypoints, + newValue -> config.dungeons.secretWaypoints.enableLeverWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableFairySoulWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableFairySoulWaypoints, + () -> config.dungeons.secretWaypoints.enableFairySoulWaypoints, + newValue -> config.dungeons.secretWaypoints.enableFairySoulWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableStonkWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableStonkWaypoints, + () -> config.dungeons.secretWaypoints.enableStonkWaypoints, + newValue -> config.dungeons.secretWaypoints.enableStonkWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableAotvWaypoints")) + .binding(defaults.dungeons.secretWaypoints.enableAotvWaypoints, + () -> config.dungeons.secretWaypoints.enableAotvWaypoints, + newValue -> config.dungeons.secretWaypoints.enableAotvWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enablePearlWaypoints")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enablePearlWaypoints.@Tooltip"))) + .binding(defaults.dungeons.secretWaypoints.enablePearlWaypoints, + () -> config.dungeons.secretWaypoints.enablePearlWaypoints, + newValue -> config.dungeons.secretWaypoints.enablePearlWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableDefaultWaypoints")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.secretWaypoints.enableDefaultWaypoints.@Tooltip"))) + .binding(defaults.dungeons.secretWaypoints.enableDefaultWaypoints, + () -> config.dungeons.secretWaypoints.enableDefaultWaypoints, + newValue -> config.dungeons.secretWaypoints.enableDefaultWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) - // Mimic Message - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.mimicMessage")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.mimicMessage.sendMimicMessage")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.mimicMessage.sendMimicMessage.@Tooltip"))) - .binding(defaults.dungeons.mimicMessage.sendMimicMessage, - () -> config.dungeons.mimicMessage.sendMimicMessage, - newValue -> config.dungeons.mimicMessage.sendMimicMessage = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.mimicMessage.mimicMessage")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.mimicMessage.mimicMessage.@Tooltip"))) - .binding(defaults.dungeons.mimicMessage.mimicMessage, - () -> config.dungeons.mimicMessage.mimicMessage, - newValue -> config.dungeons.mimicMessage.mimicMessage = newValue) - .controller(StringControllerBuilder::create) - .build()) - .build()) + // Mimic Message + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.mimicMessage")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.mimicMessage.sendMimicMessage")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.mimicMessage.sendMimicMessage.@Tooltip"))) + .binding(defaults.dungeons.mimicMessage.sendMimicMessage, + () -> config.dungeons.mimicMessage.sendMimicMessage, + newValue -> config.dungeons.mimicMessage.sendMimicMessage = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.mimicMessage.mimicMessage")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.mimicMessage.mimicMessage.@Tooltip"))) + .binding(defaults.dungeons.mimicMessage.mimicMessage, + () -> config.dungeons.mimicMessage.mimicMessage, + newValue -> config.dungeons.mimicMessage.mimicMessage = newValue) + .controller(StringControllerBuilder::create) + .build()) + .build()) - // Door Highlight - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.doorHighlight")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.doorHighlight.enableDoorHighlight")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.doorHighlight.enableDoorHighlight.@Tooltip"))) - .binding(defaults.dungeons.doorHighlight.enableDoorHighlight, - () -> config.dungeons.doorHighlight.enableDoorHighlight, - newValue -> config.dungeons.doorHighlight.enableDoorHighlight = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType.@Tooltip"), - Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType.secretWaypointsNote"))) - .binding(defaults.dungeons.doorHighlight.doorHighlightType, - () -> config.dungeons.doorHighlight.doorHighlightType, - newValue -> config.dungeons.doorHighlight.doorHighlightType = newValue) - .controller(ConfigUtils::createEnumCyclingListController) - .build()) - .build()) + // Door Highlight + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.doorHighlight")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.doorHighlight.enableDoorHighlight")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.doorHighlight.enableDoorHighlight.@Tooltip"))) + .binding(defaults.dungeons.doorHighlight.enableDoorHighlight, + () -> config.dungeons.doorHighlight.enableDoorHighlight, + newValue -> config.dungeons.doorHighlight.enableDoorHighlight = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType.@Tooltip"), + Text.translatable("skyblocker.config.dungeons.doorHighlight.doorHighlightType.secretWaypointsNote"))) + .binding(defaults.dungeons.doorHighlight.doorHighlightType, + () -> config.dungeons.doorHighlight.doorHighlightType, + newValue -> config.dungeons.doorHighlight.doorHighlightType = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + .build()) - // Dungeon Score - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage", 270)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage.@Tooltip", 270))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Message, - () -> config.dungeons.dungeonScore.enableDungeonScore270Message, - newValue -> config.dungeons.dungeonScore.enableDungeonScore270Message = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle", 270)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle.@Tooltip", 270))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Title, - () -> config.dungeons.dungeonScore.enableDungeonScore270Title, - newValue -> config.dungeons.dungeonScore.enableDungeonScore270Title = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound", 270)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound.@Tooltip", 270))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Sound, - () -> config.dungeons.dungeonScore.enableDungeonScore270Sound, - newValue -> config.dungeons.dungeonScore.enableDungeonScore270Sound = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage", 270)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage.@Tooltip", 270, 270))) - .binding(defaults.dungeons.dungeonScore.dungeonScore270Message, - () -> config.dungeons.dungeonScore.dungeonScore270Message, - newValue -> config.dungeons.dungeonScore.dungeonScore270Message = newValue) - .controller(StringControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage", 300)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage.@Tooltip", 300))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Message, - () -> config.dungeons.dungeonScore.enableDungeonScore300Message, - newValue -> config.dungeons.dungeonScore.enableDungeonScore300Message = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle", 300)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle.@Tooltip", 300))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Title, - () -> config.dungeons.dungeonScore.enableDungeonScore300Title, - newValue -> config.dungeons.dungeonScore.enableDungeonScore300Title = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound", 300)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound.@Tooltip", 300))) - .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Sound, - () -> config.dungeons.dungeonScore.enableDungeonScore300Sound, - newValue -> config.dungeons.dungeonScore.enableDungeonScore300Sound = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage", 300)) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage.@Tooltip", 300, 300))) - .binding(defaults.dungeons.dungeonScore.dungeonScore300Message, - () -> config.dungeons.dungeonScore.dungeonScore300Message, - newValue -> config.dungeons.dungeonScore.dungeonScore300Message = newValue) - .controller(StringControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonCryptsMessage")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonCryptsMessage.@Tooltip"))) - .binding(defaults.dungeons.dungeonScore.enableDungeonCryptsMessage, - () -> config.dungeons.dungeonScore.enableDungeonCryptsMessage, - newValue -> config.dungeons.dungeonScore.enableDungeonCryptsMessage = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessageThreshold")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessageThreshold.@Tooltip"))) - .binding(defaults.dungeons.dungeonScore.dungeonCryptsMessageThreshold, - () -> config.dungeons.dungeonScore.dungeonCryptsMessageThreshold, - newValue -> config.dungeons.dungeonScore.dungeonCryptsMessageThreshold = newValue) - .controller(IntegerFieldControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessage")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessage.@Tooltip"))) - .binding(defaults.dungeons.dungeonScore.dungeonCryptsMessage, - () -> config.dungeons.dungeonScore.dungeonCryptsMessage, - newValue -> config.dungeons.dungeonScore.dungeonCryptsMessage = newValue) - .controller(StringControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD.@Tooltip"), - Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD.deathMessagesNote"))) - .binding(defaults.dungeons.dungeonScore.enableScoreHUD, - () -> config.dungeons.dungeonScore.enableScoreHUD, - newValue -> config.dungeons.dungeonScore.enableScoreHUD = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.scoreScaling")) - .binding(defaults.dungeons.dungeonScore.scoreScaling, - () -> config.dungeons.dungeonScore.scoreScaling, - newValue -> { - config.dungeons.dungeonScore.scoreX = config.dungeons.dungeonScore.scoreX + (int) ((config.dungeons.dungeonScore.scoreScaling - newValue) * 38.0); - config.dungeons.dungeonScore.scoreY = config.dungeons.dungeonScore.scoreY + (int) ((config.dungeons.dungeonScore.scoreScaling - newValue) * MinecraftClient.getInstance().textRenderer.fontHeight / 2.0); - config.dungeons.dungeonScore.scoreScaling = newValue; - }) - .controller(FloatFieldControllerBuilder::create) - .build()) - .build()) + // Dungeon Score + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage", 270)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage.@Tooltip", 270))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Message, + () -> config.dungeons.dungeonScore.enableDungeonScore270Message, + newValue -> config.dungeons.dungeonScore.enableDungeonScore270Message = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle", 270)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle.@Tooltip", 270))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Title, + () -> config.dungeons.dungeonScore.enableDungeonScore270Title, + newValue -> config.dungeons.dungeonScore.enableDungeonScore270Title = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound", 270)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound.@Tooltip", 270))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore270Sound, + () -> config.dungeons.dungeonScore.enableDungeonScore270Sound, + newValue -> config.dungeons.dungeonScore.enableDungeonScore270Sound = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage", 270)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage.@Tooltip", 270, 270))) + .binding(defaults.dungeons.dungeonScore.dungeonScore270Message, + () -> config.dungeons.dungeonScore.dungeonScore270Message, + newValue -> config.dungeons.dungeonScore.dungeonScore270Message = newValue) + .controller(StringControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage", 300)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreMessage.@Tooltip", 300))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Message, + () -> config.dungeons.dungeonScore.enableDungeonScore300Message, + newValue -> config.dungeons.dungeonScore.enableDungeonScore300Message = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle", 300)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreTitle.@Tooltip", 300))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Title, + () -> config.dungeons.dungeonScore.enableDungeonScore300Title, + newValue -> config.dungeons.dungeonScore.enableDungeonScore300Title = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound", 300)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonScoreSound.@Tooltip", 300))) + .binding(defaults.dungeons.dungeonScore.enableDungeonScore300Sound, + () -> config.dungeons.dungeonScore.enableDungeonScore300Sound, + newValue -> config.dungeons.dungeonScore.enableDungeonScore300Sound = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage", 300)) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonScoreMessage.@Tooltip", 300, 300))) + .binding(defaults.dungeons.dungeonScore.dungeonScore300Message, + () -> config.dungeons.dungeonScore.dungeonScore300Message, + newValue -> config.dungeons.dungeonScore.dungeonScore300Message = newValue) + .controller(StringControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonCryptsMessage")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableDungeonCryptsMessage.@Tooltip"))) + .binding(defaults.dungeons.dungeonScore.enableDungeonCryptsMessage, + () -> config.dungeons.dungeonScore.enableDungeonCryptsMessage, + newValue -> config.dungeons.dungeonScore.enableDungeonCryptsMessage = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessageThreshold")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessageThreshold.@Tooltip"))) + .binding(defaults.dungeons.dungeonScore.dungeonCryptsMessageThreshold, + () -> config.dungeons.dungeonScore.dungeonCryptsMessageThreshold, + newValue -> config.dungeons.dungeonScore.dungeonCryptsMessageThreshold = newValue) + .controller(IntegerFieldControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessage")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.dungeonCryptsMessage.@Tooltip"))) + .binding(defaults.dungeons.dungeonScore.dungeonCryptsMessage, + () -> config.dungeons.dungeonScore.dungeonCryptsMessage, + newValue -> config.dungeons.dungeonScore.dungeonCryptsMessage = newValue) + .controller(StringControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD.@Tooltip"), + Text.translatable("skyblocker.config.dungeons.dungeonScore.enableScoreHUD.deathMessagesNote"))) + .binding(defaults.dungeons.dungeonScore.enableScoreHUD, + () -> config.dungeons.dungeonScore.enableScoreHUD, + newValue -> config.dungeons.dungeonScore.enableScoreHUD = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonScore.scoreScaling")) + .binding(defaults.dungeons.dungeonScore.scoreScaling, + () -> config.dungeons.dungeonScore.scoreScaling, + newValue -> { + config.dungeons.dungeonScore.scoreX = config.dungeons.dungeonScore.scoreX + (int) ((config.dungeons.dungeonScore.scoreScaling - newValue) * 38.0); + config.dungeons.dungeonScore.scoreY = config.dungeons.dungeonScore.scoreY + (int) ((config.dungeons.dungeonScore.scoreScaling - newValue) * MinecraftClient.getInstance().textRenderer.fontHeight / 2.0); + config.dungeons.dungeonScore.scoreScaling = newValue; + }) + .controller(FloatFieldControllerBuilder::create) + .build()) + .build()) - // Dungeon Chest Profit Calculator - .group(OptionGroup.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.enableProfitCalculator")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.enableProfitCalculator.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.enableProfitCalculator, - () -> config.dungeons.dungeonChestProfit.enableProfitCalculator, - newValue -> config.dungeons.dungeonChestProfit.enableProfitCalculator = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.croesusProfit")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.croesusProfit.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.croesusProfit, - () -> config.dungeons.dungeonChestProfit.croesusProfit, - newValue -> config.dungeons.dungeonChestProfit.croesusProfit = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeKismet")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeKismet.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.includeKismet, - () -> config.dungeons.dungeonChestProfit.includeKismet, - newValue -> config.dungeons.dungeonChestProfit.includeKismet = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeEssence")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeEssence.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.includeEssence, - () -> config.dungeons.dungeonChestProfit.includeEssence, - newValue -> config.dungeons.dungeonChestProfit.includeEssence = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - //FIXME maybe use color controller - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralThreshold")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralThreshold.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.neutralThreshold, - () -> config.dungeons.dungeonChestProfit.neutralThreshold, - newValue -> config.dungeons.dungeonChestProfit.neutralThreshold = newValue) - .controller(IntegerFieldControllerBuilder::create) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralColor")) - .binding(defaults.dungeons.dungeonChestProfit.neutralColor, - () -> config.dungeons.dungeonChestProfit.neutralColor, - newValue -> config.dungeons.dungeonChestProfit.neutralColor = newValue) - .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.profitColor")) - .binding(defaults.dungeons.dungeonChestProfit.profitColor, - () -> config.dungeons.dungeonChestProfit.profitColor, - newValue -> config.dungeons.dungeonChestProfit.profitColor = newValue) - .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.lossColor")) - .binding(defaults.dungeons.dungeonChestProfit.lossColor, - () -> config.dungeons.dungeonChestProfit.lossColor, - newValue -> config.dungeons.dungeonChestProfit.lossColor = newValue) - .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.incompleteColor")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.incompleteColor.@Tooltip"))) - .binding(defaults.dungeons.dungeonChestProfit.incompleteColor, - () -> config.dungeons.dungeonChestProfit.incompleteColor, - newValue -> config.dungeons.dungeonChestProfit.incompleteColor = newValue) - .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) - .build()) - .build()) + // Dungeon Chest Profit Calculator + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.enableProfitCalculator")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.enableProfitCalculator.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.enableProfitCalculator, + () -> config.dungeons.dungeonChestProfit.enableProfitCalculator, + newValue -> config.dungeons.dungeonChestProfit.enableProfitCalculator = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.croesusProfit")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.croesusProfit.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.croesusProfit, + () -> config.dungeons.dungeonChestProfit.croesusProfit, + newValue -> config.dungeons.dungeonChestProfit.croesusProfit = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeKismet")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeKismet.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.includeKismet, + () -> config.dungeons.dungeonChestProfit.includeKismet, + newValue -> config.dungeons.dungeonChestProfit.includeKismet = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeEssence")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.includeEssence.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.includeEssence, + () -> config.dungeons.dungeonChestProfit.includeEssence, + newValue -> config.dungeons.dungeonChestProfit.includeEssence = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + //FIXME maybe use color controller + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralThreshold")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralThreshold.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.neutralThreshold, + () -> config.dungeons.dungeonChestProfit.neutralThreshold, + newValue -> config.dungeons.dungeonChestProfit.neutralThreshold = newValue) + .controller(IntegerFieldControllerBuilder::create) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.neutralColor")) + .binding(defaults.dungeons.dungeonChestProfit.neutralColor, + () -> config.dungeons.dungeonChestProfit.neutralColor, + newValue -> config.dungeons.dungeonChestProfit.neutralColor = newValue) + .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.profitColor")) + .binding(defaults.dungeons.dungeonChestProfit.profitColor, + () -> config.dungeons.dungeonChestProfit.profitColor, + newValue -> config.dungeons.dungeonChestProfit.profitColor = newValue) + .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.lossColor")) + .binding(defaults.dungeons.dungeonChestProfit.lossColor, + () -> config.dungeons.dungeonChestProfit.lossColor, + newValue -> config.dungeons.dungeonChestProfit.lossColor = newValue) + .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.incompleteColor")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.dungeonChestProfit.incompleteColor.@Tooltip"))) + .binding(defaults.dungeons.dungeonChestProfit.incompleteColor, + () -> config.dungeons.dungeonChestProfit.incompleteColor, + newValue -> config.dungeons.dungeonChestProfit.incompleteColor = newValue) + .controller(ConfigUtils.getEnumDropdownControllerFactory(ConfigUtils.FORMATTING_FORMATTER)) + .build()) + .build()) - .build(); - } + .build(); + } } diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java index 83a23b46..dd152089 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java @@ -18,13 +18,13 @@ public class ClientWorldMixin { /** * @implNote The {@code pos} can be mutable when this is called by chunk delta updates, so if you want to copy it into memory - * (e.g. store it in a field/list/map) make sure to duplicate it via {@link BlockPos#BlockPos(net.minecraft.util.math.Vec3i)}. + * (e.g. store it in a field/list/map) make sure to duplicate it via {@link BlockPos#toImmutable()}. */ @Inject(method = "handleBlockUpdate", at = @At("RETURN")) private void skyblocker$handleBlockUpdate(CallbackInfo ci, @Local(argsOnly = true) BlockPos pos, @Local(argsOnly = true) BlockState state) { if (Utils.isInCrimson()) { DojoManager.onBlockUpdate(pos.toImmutable(), state); - SimonSays.onBlockUpdate(pos, state); + SimonSays.onBlockUpdate(pos.toImmutable(), state); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java index 0c78c2d3..da07e13d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java @@ -9,8 +9,8 @@ import de.hysky.skyblocker.utils.Boxes; import de.hysky.skyblocker.utils.ColorUtils; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectList; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectSet; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; @@ -39,7 +39,7 @@ public class SimonSays { private static final float[] GREEN = ColorUtils.getFloatComponents(DyeColor.LIME); private static final float[] YELLOW = ColorUtils.getFloatComponents(DyeColor.YELLOW); private static final ObjectSet CLICKED_BUTTONS = new ObjectOpenHashSet<>(); - private static final Int2ObjectRBTreeMap SIMON_PATTERN = new Int2ObjectRBTreeMap<>(); + private static final ObjectList SIMON_PATTERN = new ObjectArrayList<>(); public static void init() { UseBlockCallback.EVENT.register(SimonSays::onBlockInteract); @@ -76,9 +76,7 @@ public class SimonSays { Block block = state.getBlock(); if (BOARD_AREA.contains(posVec) && block.equals(Blocks.SEA_LANTERN)) { - int nextIndex = SIMON_PATTERN.size() + 1; - - SIMON_PATTERN.put(nextIndex, new BlockPos(pos)); //Copy it because it can be mutable in chunk delta updates + SIMON_PATTERN.add(pos); } else if (BUTTONS_AREA.contains(posVec) && block.equals(Blocks.AIR)) { //Upon reaching the showing of the next sequence we need to reset the state so that we don't show old data //Otherwise, the nextIndex will go beyond 5 and that can cause bugs, it also helps with the other case noted above @@ -91,10 +89,9 @@ public class SimonSays { if (shouldProcess()) { int buttonsRendered = 0; - //Tree maps iterate in natural order of key - so it goes from the lowest to the highest int :) - for (Int2ObjectMap.Entry entry : SIMON_PATTERN.int2ObjectEntrySet()) { + for (BlockPos pos : SIMON_PATTERN) { //Offset to west (x - 1) to get the position of the button from the sea lantern block - BlockPos buttonPos = entry.getValue().west(); + BlockPos buttonPos = pos.west(); ClientWorld world = Objects.requireNonNull(MinecraftClient.getInstance().world); //Should never be null here BlockState state = world.getBlockState(buttonPos); -- cgit From c4103bd4c2a8e114806b79f693b6cb2c6552c208 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Wed, 10 Jul 2024 21:49:47 -0400 Subject: Lights On Solver --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 2 + .../config/categories/DungeonsCategory.java | 8 ++++ .../skyblocker/config/configs/DungeonsConfig.java | 3 ++ .../skyblock/dungeon/device/LightsOn.java | 46 ++++++++++++++++++++++ .../resources/assets/skyblocker/lang/en_us.json | 2 + 5 files changed, 61 insertions(+) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 5366daf7..8dd1419d 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -14,6 +14,7 @@ import de.hysky.skyblocker.skyblock.chocolatefactory.TimeTowerReminder; import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; import de.hysky.skyblocker.skyblock.dungeon.*; +import de.hysky.skyblocker.skyblock.dungeon.device.LightsOn; import de.hysky.skyblocker.skyblock.dungeon.device.SimonSays; import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; import de.hysky.skyblocker.skyblock.dungeon.puzzle.*; @@ -153,6 +154,7 @@ public class SkyblockerMod implements ClientModInitializer { IceFill.init(); DungeonScore.init(); SimonSays.init(); + LightsOn.init(); PartyFinderScreen.initClass(); ChestValue.init(); FireFreezeStaffTimer.init(); diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java index 4a804650..017e9186 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -281,6 +281,14 @@ public class DungeonsCategory { newValue -> config.dungeons.devices.solveSimonSays = newValue) .controller(ConfigUtils::createBooleanController) .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.devices.solveLightsOn")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.devices.solveLightsOn.@Tooltip"))) + .binding(defaults.dungeons.devices.solveLightsOn, + () -> config.dungeons.devices.solveLightsOn, + newValue -> config.dungeons.devices.solveLightsOn = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .build()) // Dungeon Secret Waypoints diff --git a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java index 2a3075bc..1a0cad9d 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java @@ -141,6 +141,9 @@ public class DungeonsConfig { public static class Devices { @SerialEntry public boolean solveSimonSays = true; + + @SerialEntry + public boolean solveLightsOn = true; } public static class SecretWaypoints { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java new file mode 100644 index 00000000..debbc13d --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java @@ -0,0 +1,46 @@ +package de.hysky.skyblocker.skyblock.dungeon.device; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.dungeon.DungeonBoss; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; +import de.hysky.skyblocker.utils.ColorUtils; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.render.RenderHelper; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.state.property.Properties; +import net.minecraft.util.DyeColor; +import net.minecraft.util.math.BlockPos; + +public class LightsOn { + private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); + private static final BlockPos TOP_LEFT = new BlockPos(62, 136, 142); + private static final BlockPos TOP_RIGHT = new BlockPos(58, 136, 142); + private static final BlockPos MIDDLE_TOP = new BlockPos(60, 135, 142); + private static final BlockPos MIDDLE_BOTTOM = new BlockPos(60, 134, 142); + private static final BlockPos BOTTOM_LEFT = new BlockPos(62, 133, 142); + private static final BlockPos BOTTOM_RIGHT = new BlockPos(58, 133, 142); + private static final BlockPos[] LEVERS = { TOP_LEFT, TOP_RIGHT, MIDDLE_TOP, MIDDLE_BOTTOM, BOTTOM_LEFT, BOTTOM_RIGHT }; + private static final float[] RED = ColorUtils.getFloatComponents(DyeColor.RED); + + public static void init() { + WorldRenderEvents.AFTER_TRANSLUCENT.register(LightsOn::render); + } + + private static void render(WorldRenderContext context) { + if (SkyblockerConfigManager.get().dungeons.devices.solveLightsOn && Utils.isInDungeons() && DungeonManager.isInBoss() && DungeonManager.getBoss() == DungeonBoss.MAXOR) { + for (BlockPos lever : LEVERS) { + ClientWorld world = CLIENT.world; + BlockState state = world.getBlockState(lever); + boolean powered = state.get(Properties.POWERED); + + if (!powered) { + RenderHelper.renderFilled(context, lever, RED, 0.5f, false); + } + } + } + } +} diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 2669d9e0..83063a9d 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -47,6 +47,8 @@ "skyblocker.config.dungeons.croesusHelper.@Tooltip": "Gray out chests that have already been opened.", "skyblocker.config.dungeons.devices": "Device Solvers (F7/M7)", + "skyblocker.config.dungeons.devices.solveLightsOn": "Solve Lights On", + "skyblocker.config.dungeons.devices.solveLightsOn.@Tooltip": "Highlights the correct levers to click in red", "skyblocker.config.dungeons.devices.solveSimonSays": "Solve Simon Says", "skyblocker.config.dungeons.devices.solveSimonSays.@Tooltip": "Highlights the correct button to click in green, and highlights the next one in yellow.", -- cgit From b21e5206e0f433873b71d2f5ed84ca3ccb6105a3 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Wed, 10 Jul 2024 22:00:02 -0400 Subject: Well that would've never worked ;( --- src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java | 3 ++- .../java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java index dd152089..a2d7887b 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java @@ -24,7 +24,8 @@ public class ClientWorldMixin { private void skyblocker$handleBlockUpdate(CallbackInfo ci, @Local(argsOnly = true) BlockPos pos, @Local(argsOnly = true) BlockState state) { if (Utils.isInCrimson()) { DojoManager.onBlockUpdate(pos.toImmutable(), state); - SimonSays.onBlockUpdate(pos.toImmutable(), state); } + + SimonSays.onBlockUpdate(pos, state); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java index da07e13d..5aa97dd9 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java @@ -76,7 +76,7 @@ public class SimonSays { Block block = state.getBlock(); if (BOARD_AREA.contains(posVec) && block.equals(Blocks.SEA_LANTERN)) { - SIMON_PATTERN.add(pos); + SIMON_PATTERN.add(pos.toImmutable()); //Convert to immutable because chunk delta updates use the mutable variant } else if (BUTTONS_AREA.contains(posVec) && block.equals(Blocks.AIR)) { //Upon reaching the showing of the next sequence we need to reset the state so that we don't show old data //Otherwise, the nextIndex will go beyond 5 and that can cause bugs, it also helps with the other case noted above -- cgit From 6be49ddc41c0ee9d574af9b84cfe0933f89eb162 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Thu, 11 Jul 2024 04:53:06 -0400 Subject: Fix crash when lever blocks aren't loaded --- .../java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java index debbc13d..555a8e4b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java @@ -9,6 +9,7 @@ import de.hysky.skyblocker.utils.render.RenderHelper; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; import net.minecraft.client.world.ClientWorld; import net.minecraft.state.property.Properties; @@ -35,9 +36,8 @@ public class LightsOn { for (BlockPos lever : LEVERS) { ClientWorld world = CLIENT.world; BlockState state = world.getBlockState(lever); - boolean powered = state.get(Properties.POWERED); - if (!powered) { + if (state.getBlock().equals(Blocks.LEVER) && state.contains(Properties.POWERED) && !state.get(Properties.POWERED)) { RenderHelper.renderFilled(context, lever, RED, 0.5f, false); } } -- cgit