config library implementation

This commit is contained in:
2025-11-06 22:37:53 +01:00
parent bd74bce522
commit 76ed28afeb
16 changed files with 15 additions and 556 deletions

View File

@@ -10,7 +10,6 @@ base {
archivesName = project.archives_base_name
}
repositories {
maven {
name = "Terraformers"
@@ -25,8 +24,8 @@ dependencies {
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modImplementation "com.terraformersmc:modmenu:${project.modmenu_version}"
modImplementation "com.kasetoatz:dumbassconfiglib:1.0"
}
processResources {

View File

@@ -5,7 +5,7 @@ org.gradle.jvmargs=-Xmx1G
minecraft_version=1.21.10
yarn_mappings=1.21.10+build.2
loader_version=0.17.3
loom_version=1.12-SNAPSHOT
loom_version=1.13-SNAPSHOT
# Mod Properties
mod_version=1.3
maven_group=com.kasetoatz

View File

@@ -7,3 +7,5 @@ pluginManagement {
gradlePluginPortal()
}
}
includeBuild("../DumbassConfigLib")

View File

@@ -1,9 +1,9 @@
package com.kasetoatz.fastghast;
import com.kasetoatz.fastghast.configscreen.DumbassConfig;
import com.kasetoatz.fastghast.configscreen.options.BoolOption;
import com.kasetoatz.fastghast.configscreen.options.FloatOption;
import com.kasetoatz.fastghast.configscreen.options.validators.RangeValidator;
import com.kasetoatz.dumbassconfig.DumbassConfig;
import com.kasetoatz.dumbassconfig.options.BoolOption;
import com.kasetoatz.dumbassconfig.options.FloatOption;
import com.kasetoatz.dumbassconfig.options.validators.RangeValidator;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import net.fabricmc.api.ModInitializer;
@@ -11,6 +11,7 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.entity.Leashable;
import net.minecraft.entity.passive.HappyGhastEntity;
import net.minecraft.network.packet.s2c.play.PositionFlag;
import net.minecraft.text.Text;
import java.util.EnumSet;
@@ -18,6 +19,11 @@ import static com.kasetoatz.fastghast.config.Config.load;
public class Fastghast implements ModInitializer, ModMenuApi
{
private final DumbassConfig config = DumbassConfig.builder(Text.of("TEST SCREEN"))
.withOption(new BoolOption("Test Boolean Option", "test_bool_opt", false))
.withOption(new FloatOption("Test Float Option", "test_float_opt", 1.F, new RangeValidator<>(0.F, null)))
.build();
@Override
public void onInitialize()
{
@@ -33,9 +39,6 @@ public class Fastghast implements ModInitializer, ModMenuApi
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory()
{
return DumbassConfig.builder()
.withOption(new BoolOption("Test Boolean Option", "test_bool_opt", false))
.withOption(new FloatOption("Test Float Option", "test_float_opt", 1.F, new RangeValidator<>(0.F, null)))
::build;
return this.config::getUI;
}
}

View File

@@ -1,62 +0,0 @@
package com.kasetoatz.fastghast.configscreen;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.Selectable;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.gui.widget.ElementListWidget;
import net.minecraft.client.gui.widget.TextWidget;
import java.util.ArrayList;
import java.util.List;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.*;
public class ConfigEntry extends ElementListWidget.Entry<ConfigEntry>
{
private final ArrayList<ClickableWidget> widgets = new ArrayList<>();
@Override
public List<? extends Selectable> selectableChildren()
{
return List.of();
}
@Override
public List<? extends Element> children()
{
return widgets;
}
@Override
public int getY()
{
return super.getY() - 2;
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, boolean hovered, float deltaTicks)
{
for (ClickableWidget widget : widgets)
{
if (widget instanceof TextWidget)
{
widget.setX(TEXT_LEFT);
widget.setDimensions(TEXT_WIDTH, TEXT_HEIGHT);
}
else if (widget instanceof ButtonWidget || widget instanceof InputField)
{
widget.setX(this.getWidth() - OPTION_RIGHT);
widget.setDimensions(OPTION_WIDTH, OPTION_HEIGHT);
}
widget.setY(this.getY() + (this.getHeight() - widget.getHeight()) / 2);
widget.render(context, mouseX, mouseY, deltaTicks);
}
}
public void add(ClickableWidget widget)
{
widgets.add(widget);
}
}

View File

@@ -1,73 +0,0 @@
package com.kasetoatz.fastghast.configscreen;
import com.kasetoatz.fastghast.configscreen.options.BoolOption;
import com.kasetoatz.fastghast.configscreen.options.ButtonOption;
import com.kasetoatz.fastghast.configscreen.options.InputOption;
import com.kasetoatz.fastghast.configscreen.options.Option;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.widget.*;
import java.util.List;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.BACKGROUND_COLOR_1;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.BACKGROUND_COLOR_2;
public class ConfigEntryList extends ElementListWidget<ConfigEntry>
{
public ConfigEntryList(MinecraftClient client, int width, int height, int y, int itemHeight)
{
super(client, width, height, y, itemHeight);
}
@Override
public int getRowWidth()
{
return this.width - 30;
}
@Override
protected int getContentsHeightWithPadding()
{
return super.getContentsHeightWithPadding() - 4;
}
@Override
public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta)
{
List<ConfigEntry> options = this.children();
for (int i = 0; i < options.size(); i++)
{
ConfigEntry option = options.get(i);
if (option.getY() + option.getHeight() < this.getY())
{
continue;
}
if (option.getY() > this.getY() + this.height)
{
break;
}
context.fill(0, Math.max(option.getY(), this.getY()), option.getWidth() + 30, Math.min(option.getY() + option.getHeight(), this.getY() + this.height), (i % 2 == 0) ? BACKGROUND_COLOR_1 : BACKGROUND_COLOR_2);
}
super.renderWidget(context, mouseX, mouseY, delta);
}
public void add(Option<?> option)
{
ConfigEntry entry = new ConfigEntry();
entry.add(new TextWidget(option.getText(), this.client.textRenderer));
if (option instanceof ButtonOption<?> buttonOption)
{
entry.add(ButtonWidget.builder(buttonOption.getButtonText(), buttonOption::onClick).build());
}
else if (option instanceof InputOption<?> inputOption)
{
inputOption.textField = new InputField(this.client.textRenderer, inputOption.getText());
inputOption.textField.setText(inputOption.getValue().toString());
inputOption.textField.setTextPredicate(inputOption::predicate);
inputOption.textField.setChangedListener(inputOption::changeListener);
entry.add(inputOption.textField);
}
this.addEntry(entry);
}
}

View File

@@ -1,62 +0,0 @@
package com.kasetoatz.fastghast.configscreen;
import com.kasetoatz.fastghast.configscreen.options.Option;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ThreePartsLayoutWidget;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.Text;
import java.util.List;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.DONE_BUTTON_WIDTH;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.ENTRY_HEIGHT;
public class ConfigScreen extends Screen
{
private final Screen parent;
private final List<Option<?>> options;
private final ThreePartsLayoutWidget layout = new ThreePartsLayoutWidget(this);
private ConfigEntryList body;
public ConfigScreen(Screen parent, Text title, List<Option<?>> options)
{
super(title);
this.parent = parent;
this.options = options;
}
@Override
protected void init()
{
this.layout.addHeader(this.title, this.textRenderer);
this.body = new ConfigEntryList(this.client, this.layout.getWidth(), this.layout.getContentHeight(), this.layout.getHeaderHeight(), ENTRY_HEIGHT);
for (Option<?> option : this.options)
{
this.body.add(option);
}
this.layout.addBody(body);
this.layout.addFooter(ButtonWidget.builder(ScreenTexts.DONE, button -> this.close()).width(DONE_BUTTON_WIDTH).build());
this.layout.forEachChild(this::addDrawableChild);
this.refreshWidgetPositions();
}
@Override
protected void refreshWidgetPositions()
{
this.layout.refreshPositions();
if (this.body != null)
{
this.body.position(this.width, this.layout);
}
}
@Override
public void close()
{
if (this.client != null)
{
this.client.setScreen(this.parent);
}
}
}

View File

@@ -1,50 +0,0 @@
package com.kasetoatz.fastghast.configscreen;
import com.kasetoatz.fastghast.configscreen.options.Option;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
import java.util.ArrayList;
public class DumbassConfig
{
public static int TEXT_LEFT = 20;
public static int TEXT_WIDTH = 200;
public static int TEXT_HEIGHT = 40;
public static int OPTION_RIGHT = 100;
public static int OPTION_WIDTH = 80;
public static int OPTION_HEIGHT = 40;
public static int ENTRY_HEIGHT = 50;
public static int DONE_BUTTON_WIDTH = 200;
public static int BOOLEAN_TRUE_COLOR = 0x00FF00;
public static int BOOLEAN_FALSE_COLOR = 0xFF0000;
public static int VALID_INPUT_COLOR = 0xFFFFFFFF;
public static int INVALID_INPUT_COLOR = 0xFFFF0000;
public static int BACKGROUND_COLOR_1 = 0x50555555;
public static int BACKGROUND_COLOR_2 = 0x50333333;
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
private final ArrayList<Option<?>> options = new ArrayList<>();
private Builder()
{
}
public Builder withOption(Option<?> option)
{
this.options.add(option);
return this;
}
public ConfigScreen build(Screen parent)
{
return new ConfigScreen(parent, Text.literal("TEST SCREEN"), this.options);
}
}
}

View File

@@ -1,69 +0,0 @@
package com.kasetoatz.fastghast.configscreen;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gl.RenderPipelines;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ButtonTextures;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.lang.reflect.Field;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.INVALID_INPUT_COLOR;
public class InputField extends TextFieldWidget
{
private boolean valid = true;
private final ButtonTextures textures = new ButtonTextures(Identifier.ofVanilla("widget/text_field"), Identifier.ofVanilla("widget/text_field_highlighted"));
private Field textX;
private Field textY;
public InputField(TextRenderer textRenderer, Text text)
{
super(textRenderer, 80, 40, text);
initTextPosition();
}
private void initTextPosition()
{
try
{
this.textX = TextFieldWidget.class.getDeclaredField("textX");
this.textY = TextFieldWidget.class.getDeclaredField("textY");
this.textX.setAccessible(true);
this.textY.setAccessible(true);
}
catch (NoSuchFieldException ignored) {}
}
private void updateTextPosition()
{
if (this.textX != null && this.textY != null)
{
try
{
this.textX.setInt(this, this.getX() + 4);
this.textY.setInt(this, this.getY() + (this.height - 8) / 2);
}
catch (IllegalAccessException ignored) {}
}
}
public void setValid(boolean valid)
{
this.valid = valid;
this.setDrawsBackground(valid);
}
@Override
public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta)
{
if (!this.valid)
{
updateTextPosition();
context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, textures.get(this.isInteractable(), this.isFocused()), super.getX(), super.getY(), this.getWidth(), this.getHeight(), INVALID_INPUT_COLOR);
}
super.renderWidget(context, mouseX, mouseY, delta);
}
}

View File

@@ -1,28 +0,0 @@
package com.kasetoatz.fastghast.configscreen.options;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.text.Text;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.BOOLEAN_FALSE_COLOR;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.BOOLEAN_TRUE_COLOR;
public class BoolOption extends ButtonOption<Boolean>
{
public BoolOption(String text, String key, boolean defaultValue)
{
super(text, key, defaultValue);
}
@Override
public Text getButtonText()
{
return this.getValue() ? Text.literal("True").withColor(BOOLEAN_TRUE_COLOR) : Text.literal("False").withColor(BOOLEAN_FALSE_COLOR);
}
@Override
public void onClick(ButtonWidget button)
{
this.setValue(!this.getValue());
button.setMessage(this.getButtonText());
}
}

View File

@@ -1,15 +0,0 @@
package com.kasetoatz.fastghast.configscreen.options;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.text.Text;
public abstract class ButtonOption<T> extends Option<T>
{
public ButtonOption(String text, String key, T defaultValue)
{
super(text, key, defaultValue);
}
public abstract Text getButtonText();
public abstract void onClick(ButtonWidget button);
}

View File

@@ -1,40 +0,0 @@
package com.kasetoatz.fastghast.configscreen.options;
import com.kasetoatz.fastghast.configscreen.options.validators.Validator;
public class FloatOption extends InputOption<Float>
{
public FloatOption(String text, String key, Float defaultValue, Validator<Float> validator)
{
super(text, key, defaultValue, validator);
}
public FloatOption(String text, String key, Float defaultValue)
{
super(text, key, defaultValue);
}
@Override
public boolean predicate(String text)
{
if (text.isEmpty() || text.equals(".") || text.equals("-"))
{
return true;
}
try
{
Float.parseFloat(text);
return true;
}
catch (NumberFormatException exc)
{
return false;
}
}
@Override
public void changeListener(String text)
{
this.onChange((text.isEmpty() || text.equals(".") || text.equals("-")) ? 0.F : Float.parseFloat(text));
}
}

View File

@@ -1,49 +0,0 @@
package com.kasetoatz.fastghast.configscreen.options;
import com.kasetoatz.fastghast.configscreen.InputField;
import com.kasetoatz.fastghast.configscreen.options.validators.Validator;
import net.minecraft.client.gui.tooltip.Tooltip;
import net.minecraft.text.Text;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.INVALID_INPUT_COLOR;
import static com.kasetoatz.fastghast.configscreen.DumbassConfig.VALID_INPUT_COLOR;
public abstract class InputOption<T> extends Option<T>
{
public InputField textField;
private Validator<T> validator;
public InputOption(String text, String key, T defaultValue, Validator<T> validator)
{
super(text, key, defaultValue);
this.validator = validator;
}
public InputOption(String text, String key, T defaultValue)
{
super(text, key, defaultValue);
}
public void onChange(T value)
{
if (validator != null && !validator.isValid(value))
{
onError(validator.getErrorMessage());
return;
}
this.textField.setValid(true);
this.textField.setEditableColor(VALID_INPUT_COLOR);
this.textField.setTooltip(null);
this.setValue(value);
}
public void onError(String message)
{
this.textField.setValid(false);
this.textField.setEditableColor(INVALID_INPUT_COLOR);
this.textField.setTooltip(Tooltip.of(Text.literal(message).withColor(INVALID_INPUT_COLOR)));
}
public abstract boolean predicate(String value);
public abstract void changeListener(String value);
}

View File

@@ -1,44 +0,0 @@
package com.kasetoatz.fastghast.configscreen.options;
import net.minecraft.text.Text;
public abstract class Option<T>
{
private final Text text;
private final String key;
private final T defaultValue;
private T value;
public Option(String text, String key, T defaultValue)
{
this.text = Text.of(text);
this.key = key;
this.defaultValue = defaultValue;
this.value = defaultValue;
}
public Text getText()
{
return this.text;
}
public String getKey()
{
return this.key;
}
public T getDefaultValue()
{
return this.defaultValue;
}
public T getValue()
{
return this.value;
}
public void setValue(T value)
{
this.value = value;
}
}

View File

@@ -1,46 +0,0 @@
package com.kasetoatz.fastghast.configscreen.options.validators;
public class RangeValidator<T extends Number & Comparable<T>> extends Validator<T>
{
private final T min;
private final T max;
public RangeValidator(T minInclusive, T maxInclusive)
{
if (minInclusive == null && maxInclusive == null)
{
throw new IllegalArgumentException("Min and max cannot both be null");
}
if (minInclusive != null && maxInclusive != null && minInclusive.compareTo(maxInclusive) > 0)
{
throw new IllegalArgumentException("Min cannot be greater than max");
}
this.min = minInclusive;
this.max = maxInclusive;
}
@Override
public boolean isValid(T value)
{
return ((min == null) || value.compareTo(min) > 0) && ((max == null) || value.compareTo(max) < 0);
}
@Override
public String getErrorMessage()
{
String error = "Number must be ";
if (min == null && max != null)
{
error += "smaller than " + max;
}
else if (min != null && max == null)
{
error += "larger than " + min;
}
else
{
error += "between " + min + " and " + max;
}
return error;
}
}

View File

@@ -1,7 +0,0 @@
package com.kasetoatz.fastghast.configscreen.options.validators;
public abstract class Validator<T>
{
public abstract boolean isValid(T value);
public abstract String getErrorMessage();
}