diff --git a/src/main/java/io/ix0rai/rainglow/Rainglow.java b/src/main/java/io/ix0rai/rainglow/Rainglow.java index 1efb13b..c351ed4 100644 --- a/src/main/java/io/ix0rai/rainglow/Rainglow.java +++ b/src/main/java/io/ix0rai/rainglow/Rainglow.java @@ -67,6 +67,11 @@ public static Identifier id(String id) { } public static void setMode(RainglowMode mode) { + if (mode == null) { + mode = RainglowMode.get("rainbow"); + LOGGER.warn("attempted to load missing mode, resetting to rainbow"); + } + GLOWSQUID_TEXTURES.clear(); ALLAY_TEXTURES.clear(); SLIME_TEXTURES.clear(); diff --git a/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java b/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java index 36a8ca6..6a32b05 100644 --- a/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java +++ b/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java @@ -1,86 +1,79 @@ package io.ix0rai.rainglow.config; +import io.ix0rai.rainglow.Rainglow; +import io.ix0rai.rainglow.data.RainglowColour; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.option.GameOptionsScreen; +import net.minecraft.client.gui.widget.button.ButtonWidget; +import net.minecraft.client.gui.widget.layout.GridWidget; +import net.minecraft.client.gui.widget.layout.HeaderFooterLayoutWidget; +import net.minecraft.client.gui.widget.layout.LayoutSettings; +import net.minecraft.client.gui.widget.layout.LinearLayoutWidget; +import net.minecraft.client.gui.widget.list.ButtonListWidget; +import net.minecraft.client.gui.widget.text.TextWidget; +import net.minecraft.client.option.Option; +import net.minecraft.text.CommonTexts; import net.minecraft.text.Text; -public class CustomModeScreen extends Screen { +import java.util.ArrayList; +import java.util.List; + +public class CustomModeScreen extends GameOptionsScreen { + private final ButtonWidget saveButton; + private final List> options = new ArrayList<>(); + + private static final Text TITLE = Rainglow.translatableText("config.custom"); + public CustomModeScreen(Screen parent) { - super(Text.of("fa")); + super(parent, MinecraftClient.getInstance().options, TITLE); + this.saveButton = ButtonWidget.builder(Rainglow.translatableText("config.save"), button -> { + this.save(); + this.closeScreen(); + }).build(); + this.saveButton.active = false; + } + + private void createColourToggles() { + this.options.clear(); + + for (RainglowColour colour : RainglowColour.values()) { + this.options.add(DeferredSaveOption.createDeferredBoolean( + "colour." + colour.getId(), + null, + Rainglow.CONFIG.getCustom().contains(colour), + enabled -> { + if (enabled) { + Rainglow.CONFIG.getCustom().add(colour); + } else { + Rainglow.CONFIG.getCustom().remove(colour); + } + }, + enabled -> this.saveButton.active = true + )); + } + } + + private void save() { + for (DeferredSaveOption option : this.options) { + option.save(); + } + } + + @Override + public void init() { + HeaderFooterLayoutWidget headerFooterWidget = new HeaderFooterLayoutWidget(this, 61, 33); + headerFooterWidget.addToHeader(new TextWidget(TITLE, this.textRenderer), settings -> settings.alignHorizontallyCenter().setBottomPadding(28)); + + ButtonListWidget buttonListWidget = headerFooterWidget.addToContents(new ButtonListWidget(this.client, this.width, this.height, this)); + createColourToggles(); + buttonListWidget.addEntries(this.options.toArray(new Option[0])); + + LinearLayoutWidget linearLayout = headerFooterWidget.addToFooter(LinearLayoutWidget.createHorizontal().setSpacing(8)); + linearLayout.add(ButtonWidget.builder(CommonTexts.DONE, button -> this.closeScreen()).build()); + linearLayout.add(this.saveButton); + + headerFooterWidget.visitWidgets(this::addDrawableSelectableElement); + headerFooterWidget.arrangeElements(); } -// private final SpruceOption clearOption; -// private final SpruceOption saveOption; -// private final SpruceBooleanOption[] colourToggles = new SpruceBooleanOption[RainglowColour.values().length]; -// private final boolean[] toggleStates = new boolean[RainglowColour.values().length]; -// -// public CustomModeScreen(@Nullable Screen parent) { -// super(parent, MinecraftClient.getInstance().options, Rainglow.translatableText("config.title"), -// -// ); -// -// // todo subclass option to allow saving via a save button -// // ephemeral value, not saved until a specific method is called (will happen on save pressed) -// -// // create toggles for each colour -// for (int i = 0; i < RainglowColour.values().length; i ++) { -// final RainglowColour colour = RainglowColour.values()[i]; -// final int index = i; -// -// toggleStates[index] = Rainglow.CONFIG.getCustom().contains(colour); -// -// colourToggles[index] = new SpruceBooleanOption(Rainglow.translatableTextKey("colour." + colour.getId()), -// () -> toggleStates[index], -// enable -> toggleStates[index] = enable, -// null, -// true -// ); -// } -// -// // toggles all colours to false -// this.clearOption = SpruceSimpleActionOption.of(Rainglow.translatableTextKey("config.clear"), -// btn -> { -// for (int i = 0; i < RainglowColour.values().length; i ++) { -// toggleStates[i] = false; -// } -// -// MinecraftClient client = MinecraftClient.getInstance(); -// this.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); -// }); -// -// // writes all the toggled colours to the config and reloads custom mode -// this.saveOption = SpruceSimpleActionOption.of(Rainglow.translatableTextKey("config.save"), -// buttonWidget -> { -// List newCustom = new ArrayList<>(); -// -// for (int i = 0; i < RainglowColour.values().length; i ++) { -// if (toggleStates[i]) { -// newCustom.add(RainglowColour.values()[i]); -// } -// } -// -// Rainglow.CONFIG.setCustom(newCustom); -// Rainglow.CONFIG.saveCustom(); -// this.closeScreen(); -// } -// ); -// } -// -// @Override -// protected void init() { -// super.init(); -// -// // create a list of toggles for each colour -// SpruceOptionListWidget options = new SpruceOptionListWidget(Position.of(0, 22), this.width, this.height - (35 + 22)); -// for (int i = 0; i < RainglowColour.values().length; i += 2) { -// SpruceOption secondToggle = null; -// if (i + 1 < RainglowColour.values().length) { -// secondToggle = colourToggles[i + 1]; -// } -// options.addOptionEntry(colourToggles[i], secondToggle); -// } -// this.addDrawableSelectableElement(options); -// -// // save and clear buttons -// this.addDrawableSelectableElement(this.clearOption.createWidget(Position.of(this, this.width / 2 - 155, this.height - 29), 150)); -// this.addDrawableSelectableElement(this.saveOption.createWidget(Position.of(this, this.width / 2 - 155 + 160, this.height - 29), 150)); -// } } diff --git a/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java b/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java index 83094a2..ab9c2cd 100644 --- a/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java +++ b/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java @@ -11,14 +11,16 @@ public class DeferredSaveOption extends Option { public T deferredValue; + private Consumer clickCallback; - public DeferredSaveOption(String key, TooltipSupplier tooltipSupplier, OptionTextGetter textGetter, Option.ValueSet values, T defaultValue, Consumer updateCallback) { - this(key, tooltipSupplier, textGetter, values, values.codec(), defaultValue, updateCallback); + public DeferredSaveOption(String key, TooltipSupplier tooltipSupplier, OptionTextGetter textGetter, Option.ValueSet values, T defaultValue, Consumer updateCallback, Consumer clickCallback) { + this(key, tooltipSupplier, textGetter, values, values.codec(), defaultValue, updateCallback, clickCallback); } - public DeferredSaveOption(String key, TooltipSupplier tooltipSupplier, OptionTextGetter textGetter, Option.ValueSet values, Codec codec, T defaultValue, Consumer updateCallback) { + public DeferredSaveOption(String key, TooltipSupplier tooltipSupplier, OptionTextGetter textGetter, Option.ValueSet values, Codec codec, T defaultValue, Consumer updateCallback, Consumer clickCallback) { super(key, tooltipSupplier, textGetter, values, codec, defaultValue, updateCallback); this.deferredValue = this.value; + this.clickCallback = clickCallback; } @Override @@ -33,31 +35,34 @@ public void set(T value) { } else { if (!Objects.equals(this.value, object)) { this.deferredValue = object; - // note: callback is called on save + this.clickCallback.accept(object); + // note: update callback is called on save } } } - public static DeferredSaveOption createDeferredBoolean(String key, String tooltip, boolean defaultValue, Consumer updateCallback) { + public static DeferredSaveOption createDeferredBoolean(String key, String tooltip, boolean defaultValue, Consumer updateCallback, Consumer clickCallback) { return new DeferredSaveOption<>( - Rainglow.translatableTextKey("config." + key), - Option.constantTooltip(tooltip == null ? Rainglow.translatableText("tooltip." + key) : Rainglow.translatableText(tooltip)), + Rainglow.translatableTextKey(key), + tooltip != null ? Option.constantTooltip(Rainglow.translatableText("tooltip." + key)) : Option.emptyTooltip(), (text, value) -> value ? CommonTexts.YES : CommonTexts.NO, BOOLEAN_VALUES, defaultValue, - updateCallback + updateCallback, + clickCallback ); } - public static DeferredSaveOption createDeferredRangedInt(String key, String tooltip, int defaultValue, int min, int max, Consumer updateCallback) { + public static DeferredSaveOption createDeferredRangedInt(String key, String tooltip, int defaultValue, int min, int max, Consumer updateCallback, Consumer clickCallback) { return new DeferredSaveOption<>( - Rainglow.translatableTextKey("config." + key), - Option.constantTooltip(tooltip == null ? Rainglow.translatableText("tooltip." + key) : Rainglow.translatableText(tooltip)), - (text, value) -> Rainglow.translatableText("value." + key, value), + Rainglow.translatableTextKey(key), + tooltip != null ? Option.constantTooltip(Rainglow.translatableText("tooltip." + key)) : Option.emptyTooltip(), + (text, value) -> Rainglow.translatableText(key + ".value", value), new Option.IntRangeValueSet(min, max), Codec.intRange(min, max), defaultValue, - updateCallback + updateCallback, + clickCallback ); } diff --git a/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java b/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java index 5ccc972..9a5273a 100644 --- a/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java +++ b/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java @@ -34,6 +34,7 @@ public class RainglowConfigScreen extends Screen { private final Screen parent; private final Map> toggles = new HashMap<>(); private final Map> sliders = new HashMap<>(); + private final ButtonWidget saveButton; private RainglowMode mode; private boolean isConfirming; @@ -42,6 +43,11 @@ public RainglowConfigScreen(@Nullable Screen parent) { super(TITLE); this.parent = parent; this.mode = RainglowMode.get(Rainglow.CONFIG.mode.value()); + this.saveButton = ButtonWidget.builder(Rainglow.translatableText("config.save"), button -> { + this.save(); + this.closeScreen(true); + }).build(); + this.saveButton.active = false; } @Override @@ -73,22 +79,19 @@ public void init() { } contentLayout.add(gridWidget); - contentLayout.add(ButtonWidget.builder(Rainglow.translatableText("config.custom_mode"), button -> MinecraftClient.getInstance().setScreen(new CustomModeScreen(this))).width(308).position(4, 0).build(), LayoutSettings.create().setPadding(4, 0)); + contentLayout.add(ButtonWidget.builder(Rainglow.translatableText("config.custom"), button -> MinecraftClient.getInstance().setScreen(new CustomModeScreen(this))).width(308).position(4, 0).build(), LayoutSettings.create().setPadding(4, 0)); headerFooterWidget.addToContents(contentLayout); // footer LinearLayoutWidget linearLayout = headerFooterWidget.addToFooter(LinearLayoutWidget.createHorizontal().setSpacing(8)); linearLayout.add(ButtonWidget.builder(CommonTexts.DONE, button -> this.closeScreen()).build()); - linearLayout.add(ButtonWidget.builder(Rainglow.translatableText("config.save"), button -> { - this.save(); - this.closeScreen(true); - }).build()); + linearLayout.add(this.saveButton); } else { LinearLayoutWidget contentWidget = headerFooterWidget.addToContents(new LinearLayoutWidget(250, 100, LinearLayoutWidget.Orientation.VERTICAL).setSpacing(8)); contentWidget.add(new TextWidget(Rainglow.translatableText("config.unsaved_warning"), this.textRenderer), LayoutSettings::alignHorizontallyCenter); - LinearLayoutWidget buttons = new LinearLayoutWidget(250, 20, LinearLayoutWidget.Orientation.HORIZONTAL); + LinearLayoutWidget buttons = new LinearLayoutWidget(250, 20, LinearLayoutWidget.Orientation.HORIZONTAL).setSpacing(8); buttons.add(ButtonWidget.builder(Rainglow.translatableText("config.continue_editing"), (buttonWidget) -> { this.isConfirming = false; this.clearAndInit(); @@ -104,21 +107,23 @@ public void init() { private DeferredSaveOption createEntityToggle(RainglowEntity entity) { return toggles.computeIfAbsent(entity, e -> DeferredSaveOption.createDeferredBoolean( - "enable_" + e.getId(), - "tooltip.entity_toggle", - Rainglow.CONFIG.isEntityEnabled(e), - enabled -> Rainglow.CONFIG.setEntityEnabled(e, enabled) + "config.enable_" + e.getId(), + "tooltip.entity_toggle", + Rainglow.CONFIG.isEntityEnabled(e), + enabled -> Rainglow.CONFIG.setEntityEnabled(e, enabled), + enabled -> this.saveButton.active = true )); } private DeferredSaveOption createColourRaritySlider(RainglowEntity entity) { return sliders.computeIfAbsent(entity, e -> DeferredSaveOption.createDeferredRangedInt( - e.getId() + "_rarity", + "config." + e.getId() + "_rarity", "tooltip.rarity", Rainglow.CONFIG.getRarity(e), 0, 100, - rarity -> Rainglow.CONFIG.setRarity(e, rarity) + rarity -> Rainglow.CONFIG.setRarity(e, rarity), + rarity -> this.saveButton.active = true )); } @@ -133,7 +138,10 @@ public CyclingButtonWidget createModeButton() { 308, 20, Rainglow.translatableText("config.mode"), - (cyclingButtonWidget, mode) -> RainglowConfigScreen.this.mode = mode + (cyclingButtonWidget, mode) -> { + this.saveButton.active = true; + RainglowConfigScreen.this.mode = mode; + } ); } @@ -186,7 +194,7 @@ public void closeScreen() { } public void closeScreen(boolean saved) { - if (!saved) { + if (!saved && this.saveButton.active) { this.isConfirming = true; this.clearAndInit(); } else { diff --git a/src/main/resources/assets/rainglow/lang/en_us.json b/src/main/resources/assets/rainglow/lang/en_us.json index 629ad1d..7fc9254 100644 --- a/src/main/resources/assets/rainglow/lang/en_us.json +++ b/src/main/resources/assets/rainglow/lang/en_us.json @@ -15,12 +15,11 @@ "rainglow.config.no_world": "No world loaded: only default modes are available.", "rainglow.config.unsaved_warning": "Config is not saved and changes will be lost! Leave without saving?", "rainglow.config.continue_editing": "Continue editing", - "rainglow.value.slime_rarity": "Slime rarity: %s", + "rainglow.config.slime_rarity.value": "Slime rarity: %s", "rainglow.tooltip.rarity": "Rarity determines what percent chance mobs have to spawn with a colour.", - "rainglow.value.allay_rarity": "Allay rarity: %s", - "rainglow.value.glow_squid_rarity": "Glow squid rarity: %s", - "rainglow.tooltip.mode": "Determines the possible colours for entities to have.", - "rainglow.config.cannot_be_loaded_outside_world": "Rainglow config cannot be edited through the GUI before loading a world!", + "rainglow.tooltip.entity_toggle": "Enable or disable rainbow colours for this entity.", + "rainglow.config.allay_rarity.value": "Allay rarity: %s", + "rainglow.config.glow_squid_rarity.value": "Glow squid rarity: %s", "rainglow.mode.rainbow": "Rainbow", "rainglow.mode.all_colours": "All Colours", "rainglow.mode.monochrome": "Monochrome",