diff --git a/build.gradle.kts b/build.gradle.kts index d8b38106..893dcc9b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,6 +15,7 @@ repositories { maven("https://repo.hypixel.net/repository/Hypixel/") maven("https://repo.cookies.codes/releases") maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1") + maven("https://maven.isxander.dev/releases") } fabricApi { @@ -49,6 +50,8 @@ dependencies { modImplementation("net.fabricmc:fabric-loader:${project.properties["loader_version"]}") modImplementation("net.fabricmc.fabric-api:fabric-api:${project.properties["fabric_version"]}") modRuntimeOnly("me.djtheredstoner:DevAuth-fabric:1.2.1") + + modImplementation("dev.isxander:yet-another-config-lib:3.6.1+1.21.2-fabric") } tasks.withType().configureEach { diff --git a/src/main/java/codes/cookies/mod/CookiesMod.java b/src/main/java/codes/cookies/mod/CookiesMod.java index 7d193a2d..83ee819a 100644 --- a/src/main/java/codes/cookies/mod/CookiesMod.java +++ b/src/main/java/codes/cookies/mod/CookiesMod.java @@ -9,6 +9,7 @@ import codes.cookies.mod.commands.system.CommandManager; import codes.cookies.mod.config.ConfigManager; import codes.cookies.mod.config.screen.ConfigScreen; +import codes.cookies.mod.config.system.yacl.YaclConfigReader; import codes.cookies.mod.data.cookiesmoddata.CookieDataManager; import codes.cookies.mod.data.profile.ProfileStorage; import codes.cookies.mod.events.EventLoader; @@ -22,6 +23,7 @@ import codes.cookies.mod.services.mining.CrystalStatusService; import codes.cookies.mod.utils.UpdateChecker; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -30,6 +32,7 @@ import codes.cookies.mod.utils.skyblock.LocationUtils; import codes.cookies.mod.utils.skyblock.MayorUtils; import codes.cookies.mod.utils.skyblock.playerlist.PlayerListUtils; +import dev.isxander.yacl3.api.YetAnotherConfigLib; import lombok.Getter; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; @@ -60,6 +63,16 @@ public class CookiesMod implements ClientModInitializer { * Opens the config screen. */ public static void openConfig() { + if (ConfigManager.getConfigReader() instanceof YaclConfigReader yaclConfigReader) { + final CompletableFuture finalConfig = yaclConfigReader.getFinalConfig(); + if (finalConfig.isDone()) { + final YetAnotherConfigLib join = finalConfig.join().build(); + final Screen screen = join.generateScreen(MinecraftClient.getInstance().currentScreen); + openScreen(screen); + return; + } + } + openScreen(new ConfigScreen(ConfigManager.getConfigReader())); } diff --git a/src/main/java/codes/cookies/mod/config/ConfigManager.java b/src/main/java/codes/cookies/mod/config/ConfigManager.java index 3a7080d8..33de07ea 100644 --- a/src/main/java/codes/cookies/mod/config/ConfigManager.java +++ b/src/main/java/codes/cookies/mod/config/ConfigManager.java @@ -1,5 +1,6 @@ package codes.cookies.mod.config; +import codes.cookies.mod.config.system.yacl.YaclConfigReader; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; @@ -62,7 +63,7 @@ public static boolean isLoaded() { public static void processConfig() { config = new CookiesConfig(); reload(); - configReader = new ConfigReader(); + configReader = new YaclConfigReader(); ConfigProcessor.processConfig(config, configReader); } diff --git a/src/main/java/codes/cookies/mod/config/system/parsed/ConfigReader.java b/src/main/java/codes/cookies/mod/config/system/parsed/ConfigReader.java index 9a0fbe27..b00bb06f 100644 --- a/src/main/java/codes/cookies/mod/config/system/parsed/ConfigReader.java +++ b/src/main/java/codes/cookies/mod/config/system/parsed/ConfigReader.java @@ -23,7 +23,7 @@ /** * Config reader to correctly parse a config from its source. */ -public class ConfigReader { +public abstract class ConfigReader { private static final Logger logger = LoggerFactory.getLogger(ConfigReader.class); @Getter @@ -70,19 +70,19 @@ public void endParent() { * * @param foldable The foldable to open. */ - public void beginFoldable(Foldable foldable) { - //noinspection rawtypes - - ProcessedOption processedOption = new ProcessedOption<>(new FoldableOption( - foldable, - foldableId.incrementAndGet() - )); - if (!this.foldableStack.isEmpty()) { + public FoldableOption beginFoldable(Foldable foldable) { + final FoldableOption foldableOption = new FoldableOption( + foldable, + foldableId.incrementAndGet() + ); + ProcessedOption processedOption = new ProcessedOption<>(foldableOption); + if (!this.foldableStack.isEmpty()) { processedOption.setFoldable(this.foldableStack.peek()); } this.currentCategory.addOption(processedOption); this.foldableStack.push(this.foldableId.get()); - } + return foldableOption; + } /** * Ends a foldable. diff --git a/src/main/java/codes/cookies/mod/config/system/yacl/YaclConfigReader.java b/src/main/java/codes/cookies/mod/config/system/yacl/YaclConfigReader.java new file mode 100644 index 00000000..e70bdec0 --- /dev/null +++ b/src/main/java/codes/cookies/mod/config/system/yacl/YaclConfigReader.java @@ -0,0 +1,199 @@ +package codes.cookies.mod.config.system.yacl; + +import java.awt.*; +import java.util.Stack; +import java.util.concurrent.CompletableFuture; + +import codes.cookies.mod.config.system.Category; +import codes.cookies.mod.config.system.Config; +import codes.cookies.mod.config.system.Foldable; +import codes.cookies.mod.config.system.Option; +import codes.cookies.mod.config.system.options.BooleanOption; +import codes.cookies.mod.config.system.options.ButtonOption; +import codes.cookies.mod.config.system.options.ColorOption; +import codes.cookies.mod.config.system.options.EnumCycleOption; +import codes.cookies.mod.config.system.options.FoldableOption; +import codes.cookies.mod.config.system.options.SliderOption; +import codes.cookies.mod.config.system.options.StringInputOption; +import codes.cookies.mod.config.system.options.TextDisplayOption; +import codes.cookies.mod.config.system.parsed.ConfigReader; +import codes.cookies.mod.config.system.parsed.ProcessedOption; +import dev.isxander.yacl3.api.ConfigCategory; +import dev.isxander.yacl3.api.LabelOption; +import dev.isxander.yacl3.api.Option.Builder; +import dev.isxander.yacl3.api.OptionDescription; +import dev.isxander.yacl3.api.OptionGroup; +import dev.isxander.yacl3.api.YetAnotherConfigLib; +import dev.isxander.yacl3.api.controller.ColorControllerBuilder; +import dev.isxander.yacl3.api.controller.DoubleSliderControllerBuilder; +import dev.isxander.yacl3.api.controller.EnumControllerBuilder; +import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder; +import dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder; +import dev.isxander.yacl3.api.controller.LongSliderControllerBuilder; +import dev.isxander.yacl3.api.controller.StringControllerBuilder; +import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import net.minecraft.text.Text; + +@Slf4j +public class YaclConfigReader extends ConfigReader { + + @Getter + final CompletableFuture finalConfig = new CompletableFuture<>(); + final Stack optionGroups = new Stack<>(); + YetAnotherConfigLib.Builder builder; + ConfigCategory.Builder categoryBuilder; + + @Override + public void beginConfig(Config config) { + super.beginConfig(config); + + builder = YetAnotherConfigLib.createBuilder(); + builder.title(Text.literal("Cookies Mod")); + } + + @Override + public void beginCategory(Category category) { + super.beginCategory(category); + categoryBuilder = ConfigCategory.createBuilder(); + categoryBuilder.name(category.getName()); + categoryBuilder.tooltip(category.getDescription()); + } + + @Override + public void endCategory() { + super.endCategory(); + builder.category(categoryBuilder.build()); + categoryBuilder = null; + } + + private void addOption(dev.isxander.yacl3.api.Option builder) { + if (!optionGroups.isEmpty()) { + final OptionGroup.Builder peek = optionGroups.peek(); + peek.option(builder); + } else { + categoryBuilder.option(builder); + } + } + + /** + * GOD THIS IS HORRIBLE QWQ + */ + @SuppressWarnings("unchecked") + private void configureSliderOption(SliderOption option) { + + if (option.getValue() instanceof Double) { + final SliderOption option1 = (SliderOption) option; + final Builder basicBuilder = createBasicBuilder(option1); + basicBuilder.controller(doubleOption -> DoubleSliderControllerBuilder.create(doubleOption) + .range(option1.getMin(), option1.getMax())); + addOption(basicBuilder.build()); + } else if (option.getValue() instanceof Integer) { + final SliderOption option1 = (SliderOption) option; + final Builder basicBuilder = createBasicBuilder(option1); + basicBuilder.controller(doubleOption -> IntegerSliderControllerBuilder.create(doubleOption) + .range(option1.getMin(), option1.getMax())); + addOption(basicBuilder.build()); + } else if (option.getValue() instanceof Float) { + final SliderOption option1 = (SliderOption) option; + final Builder basicBuilder = createBasicBuilder(option1); + basicBuilder.controller(doubleOption -> FloatSliderControllerBuilder.create(doubleOption) + .range(option1.getMin(), option1.getMax())); + addOption(basicBuilder.build()); + } else if (option.getValue() instanceof Long) { + final SliderOption option1 = (SliderOption) option; + final Builder basicBuilder = createBasicBuilder(option1); + basicBuilder.controller(doubleOption -> LongSliderControllerBuilder.create(doubleOption) + .range(option1.getMin(), option1.getMax())); + addOption(basicBuilder.build()); + } + + } + + private Builder createBasicBuilder(Option option) { + final var yaclOption = dev.isxander.yacl3.api.Option.createBuilder(); + yaclOption.name(option.getName()); + yaclOption.description(OptionDescription.createBuilder().text(option.getDescription()).build()); + yaclOption.binding(option.getValue(), option::getValue, option::setValue); + return yaclOption; + } + + private > void addEnumCycle(EnumCycleOption option) { + final Builder basicBuilder = createBasicBuilder(option); + basicBuilder.controller(opt -> EnumControllerBuilder.create(opt) + .enumClass(option.getValue().getDeclaringClass()) + .formatValue(option.getTextSupplier()::supplyText)); + addOption(basicBuilder.build()); + } + + @Override + public > ProcessedOption processOption(Option option, String fieldName) { + if (option instanceof ButtonOption buttonOption) { + addOption(dev.isxander.yacl3.api.ButtonOption.createBuilder() + .name(buttonOption.getName()) + .description(OptionDescription.createBuilder().text(option.getDescription()).build()) + .action((yaclScreen, buttonOption1) -> buttonOption.getValue().run()).build()); + return super.processOption(option, fieldName); + } else if (option instanceof TextDisplayOption textDisplayOption) { + addOption(LabelOption.create(textDisplayOption.getName())); + return super.processOption(option, fieldName); + } + + final Builder basicBuilder = createBasicBuilder(option); + + switch (option) { + case BooleanOption booleanOption -> { + ((Builder) basicBuilder).controller(TickBoxControllerBuilder::create); + } + case SliderOption sliderOption -> { + configureSliderOption(sliderOption); + return super.processOption(option, fieldName); + } + case ColorOption colorOption -> { + ((Builder) basicBuilder).controller(opt -> ColorControllerBuilder.create(opt) + .allowAlpha(colorOption.isAllowAlpha())); + } + case StringInputOption stringInputOption -> { + ((Builder) basicBuilder).controller(StringControllerBuilder::create); + } + case EnumCycleOption> enumCycleOption -> { + addEnumCycle(enumCycleOption); + return super.processOption(option, fieldName); + } + default -> { + System.err.println("Unhandled option: " + fieldName + ": " + option); + } + } + + addOption(basicBuilder.build()); + + return super.processOption(option, fieldName); + } + + @Override + public FoldableOption beginFoldable(Foldable foldable) { + final FoldableOption foldableOption = super.beginFoldable(foldable); + final OptionGroup.Builder categoryBuilder = OptionGroup.createBuilder(); + categoryBuilder.name(foldableOption.getName()); + categoryBuilder.description(OptionDescription.createBuilder().text(foldableOption.getDescription()).build()); + categoryBuilder.collapsed(true); + optionGroups.push(categoryBuilder); + + return foldableOption; + } + + @Override + public void endFoldable() { + super.endFoldable(); + final OptionGroup.Builder pop = optionGroups.pop(); + categoryBuilder.group(pop.build()); + } + + @Override + public void endConfig() { + super.endConfig(); + finalConfig.complete(builder); + } +}