Add verifiers and presets to JfConfig
This commit is contained in:
parent
7b43af0450
commit
3fb16789b9
@ -31,8 +31,40 @@ To register a config, add a `libjf:config` entrypoint pointing to its class to y
|
|||||||
To manually register a config or save changes, use `io.gitlab.jfronny.libjf.config.api.ConfigHolder`
|
To manually register a config or save changes, use `io.gitlab.jfronny.libjf.config.api.ConfigHolder`
|
||||||
For example, to save a config for a mod titled `yourmod`:
|
For example, to save a config for a mod titled `yourmod`:
|
||||||
```java
|
```java
|
||||||
ConfigHolder.getInstance().getRegistered().get("yourmod").write();
|
ConfigHolder.getInstance().get("yourmod").write();
|
||||||
```
|
```
|
||||||
|
|
||||||
LibJF config is only intended for simple config screens, it does not support nested classes, multiple pages or controls like sliders.
|
LibJF config is only intended for simple config screens, it does not support nested classes, multiple pages or controls like sliders.
|
||||||
Use something else for those
|
Use something else for those
|
||||||
|
|
||||||
|
## Presets
|
||||||
|
libjf-config-v0 provides a preset system to automatically fill in certain values based on a function.
|
||||||
|
To add a snippet, add a public static method to your config class and annotate it with @Preset.
|
||||||
|
If your preset is selected, the method will be executed.
|
||||||
|
You may assign a name by using your language file, the format for names is `<mod id>.jfconfig.<method name>`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```java
|
||||||
|
@Preset
|
||||||
|
public static void moskau() {
|
||||||
|
disablePacks = true;
|
||||||
|
disablePacks2 = true;
|
||||||
|
intTest = -5;
|
||||||
|
floatTest = -6;
|
||||||
|
doubleTest = 4;
|
||||||
|
dieStr = "Moskau";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verifiers
|
||||||
|
If you need to manually validate config values outside of minimums or maximums, you may add a public static method
|
||||||
|
and annotate it with @Verifier. This method will be executed whenever your config changes, which might happen often.
|
||||||
|
Be careful to write performant code here!
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```java
|
||||||
|
@Verifier
|
||||||
|
public static void setIntTestIfDisable() {
|
||||||
|
if (disablePacks) intTest = 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# libjf-devutil-v0
|
# libjf-devutil-v0
|
||||||
LibJF devutil is intended to be used as `runtimeOnly`.
|
LibJF devutil is intended to be used as `runtimeOnly`.
|
||||||
It marks the running minecraft instance as a development instance and disables the UserApi (removing that Yggdrasil error message)
|
It marks the running minecraft instance as a development instance (for example, this removes the need for eula.txt)
|
||||||
|
and disables the UserApi (removing that Yggdrasil error message)
|
||||||
It does not provide any useful functionality to end users
|
It does not provide any useful functionality to end users
|
||||||
|
|
||||||
It depends on libjf-base
|
It depends on libjf-base
|
@ -11,5 +11,7 @@ public interface ConfigHolder {
|
|||||||
}
|
}
|
||||||
void register(String modId, Class<?> config);
|
void register(String modId, Class<?> config);
|
||||||
Map<String, Config> getRegistered();
|
Map<String, Config> getRegistered();
|
||||||
|
Config get(Class<?> configClass);
|
||||||
|
Config get(String configClass);
|
||||||
boolean isRegistered(Class<?> config);
|
boolean isRegistered(Class<?> config);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package io.gitlab.jfronny.libjf.config.api;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface Preset {
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package io.gitlab.jfronny.libjf.config.api;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface Verifier {
|
||||||
|
}
|
@ -2,20 +2,27 @@ package io.gitlab.jfronny.libjf.config.impl;
|
|||||||
|
|
||||||
import io.gitlab.jfronny.libjf.LibJf;
|
import io.gitlab.jfronny.libjf.LibJf;
|
||||||
import io.gitlab.jfronny.libjf.config.api.Entry;
|
import io.gitlab.jfronny.libjf.config.api.Entry;
|
||||||
|
import io.gitlab.jfronny.libjf.config.api.Preset;
|
||||||
|
import io.gitlab.jfronny.libjf.config.api.Verifier;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/** Based on https://github.com/TeamMidnightDust/MidnightLib which is based on https://github.com/Minenash/TinyConfig
|
/** Based on https://github.com/TeamMidnightDust/MidnightLib which is based on https://github.com/Minenash/TinyConfig
|
||||||
* Credits to TeamMidnightDust and Minenash */
|
* Credits to TeamMidnightDust and Minenash */
|
||||||
|
|
||||||
public class Config {
|
public class Config {
|
||||||
public final List<EntryInfo> entries = new ArrayList<>();
|
public final List<EntryInfo> entries = new ArrayList<>();
|
||||||
public Path path;
|
public final Map<String, Runnable> presets = new LinkedHashMap<>();
|
||||||
|
public final Set<Runnable> verifiers = new LinkedHashSet<>();
|
||||||
|
public final Path path;
|
||||||
public final String modid;
|
public final String modid;
|
||||||
public final Class<?> configClass;
|
public final Class<?> configClass;
|
||||||
|
|
||||||
@ -27,19 +34,106 @@ public class Config {
|
|||||||
for (Field field : config.getFields()) {
|
for (Field field : config.getFields()) {
|
||||||
EntryInfo info = new EntryInfo();
|
EntryInfo info = new EntryInfo();
|
||||||
info.field = field;
|
info.field = field;
|
||||||
if (field.isAnnotationPresent(Entry.class))
|
if (field.isAnnotationPresent(Entry.class)) {
|
||||||
|
info.entry = field.getAnnotation(Entry.class);
|
||||||
try {
|
try {
|
||||||
info.defaultValue = field.get(null);
|
info.defaultValue = field.get(null);
|
||||||
} catch (IllegalAccessException ignored) {}
|
} catch (IllegalAccessException ignored) {}
|
||||||
|
}
|
||||||
entries.add(info);
|
entries.add(info);
|
||||||
}
|
}
|
||||||
|
presets.put("libjf-config-v0.default", () -> {
|
||||||
|
for (EntryInfo entry : entries) {
|
||||||
try {
|
try {
|
||||||
LibJf.GSON.fromJson(Files.newBufferedReader(path), config); }
|
entry.field.set(null, entry.defaultValue);
|
||||||
catch (Exception e) { write(); }
|
} catch (IllegalAccessException e) {
|
||||||
|
LibJf.LOGGER.error("Could not reload default values", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (Method method : config.getMethods()) {
|
||||||
|
if (method.isAnnotationPresent(Preset.class)) {
|
||||||
|
presets.put(modid + ".jfconfig." + method.getName(), () -> {
|
||||||
|
try {
|
||||||
|
method.invoke(null);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
LibJf.LOGGER.error("Could not apply preset", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (method.isAnnotationPresent(Verifier.class)) {
|
||||||
|
verifiers.add(() -> {
|
||||||
|
try {
|
||||||
|
method.invoke(null);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
LibJf.LOGGER.error("Could not run verifier", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verifiers.add(() -> {
|
||||||
|
for (EntryInfo entry : entries) {
|
||||||
|
Object value;
|
||||||
|
try {
|
||||||
|
value = entry.field.get(null);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
LibJf.LOGGER.error("Could not read value", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final Object valueOriginal = value;
|
||||||
|
if (value instanceof final Integer v) {
|
||||||
|
if (v < entry.entry.min()) value = (int)entry.entry.min();
|
||||||
|
if (v > entry.entry.max()) value = (int)entry.entry.max();
|
||||||
|
} else if (value instanceof final Float v) {
|
||||||
|
if (v < entry.entry.min()) value = (float)entry.entry.min();
|
||||||
|
if (v > entry.entry.max()) value = (float)entry.entry.max();
|
||||||
|
} else if (value instanceof final Double v) {
|
||||||
|
if (v < entry.entry.min()) value = entry.entry.min();
|
||||||
|
if (v > entry.entry.max()) value = entry.entry.max();
|
||||||
|
}
|
||||||
|
if (valueOriginal != value) {
|
||||||
|
try {
|
||||||
|
entry.field.set(null, value);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
LibJf.LOGGER.error("Could not write value", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
LibJf.GSON.fromJson(Files.newBufferedReader(path), config);
|
||||||
|
syncFromClass();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void syncToClass() {
|
||||||
|
for (EntryInfo info : entries) {
|
||||||
|
try {
|
||||||
|
info.field.set(null, info.value);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
LibJf.LOGGER.error("Could not write value", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syncFromClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void syncFromClass() {
|
||||||
|
for (Runnable verifier : verifiers) {
|
||||||
|
verifier.run();
|
||||||
|
}
|
||||||
|
for (EntryInfo info : entries) {
|
||||||
|
try {
|
||||||
|
info.value = info.field.get(null);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
LibJf.LOGGER.error("Could not read value", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write() {
|
public void write() {
|
||||||
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
|
|
||||||
try {
|
try {
|
||||||
if (!Files.exists(path)) Files.createFile(path);
|
if (!Files.exists(path)) Files.createFile(path);
|
||||||
Files.write(path, LibJf.GSON.toJson(configClass.getDeclaredConstructor().newInstance()).getBytes());
|
Files.write(path, LibJf.GSON.toJson(configClass.getDeclaredConstructor().newInstance()).getBytes());
|
||||||
|
@ -2,12 +2,14 @@ package io.gitlab.jfronny.libjf.config.impl;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import io.gitlab.jfronny.libjf.config.api.ConfigHolder;
|
import io.gitlab.jfronny.libjf.config.api.ConfigHolder;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ConfigHolderImpl implements ConfigHolder {
|
public class ConfigHolderImpl implements ConfigHolder {
|
||||||
@Deprecated public static final ConfigHolderImpl INSTANCE = new ConfigHolderImpl();
|
@ApiStatus.Internal
|
||||||
|
public static final ConfigHolderImpl INSTANCE = new ConfigHolderImpl();
|
||||||
private ConfigHolderImpl() {}
|
private ConfigHolderImpl() {}
|
||||||
private final Map<String, Config> configs = new HashMap<>();
|
private final Map<String, Config> configs = new HashMap<>();
|
||||||
|
|
||||||
@ -22,6 +24,20 @@ public class ConfigHolderImpl implements ConfigHolder {
|
|||||||
return ImmutableMap.copyOf(configs);
|
return ImmutableMap.copyOf(configs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Config get(Class<?> configClass) {
|
||||||
|
for (Config value : configs.values()) {
|
||||||
|
if (value.configClass.equals(configClass))
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Config get(String configClass) {
|
||||||
|
return configs.get(configClass);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isRegistered(Class<?> config) {
|
public boolean isRegistered(Class<?> config) {
|
||||||
for (Config value : configs.values()) {
|
for (Config value : configs.values()) {
|
||||||
if (value.configClass.equals(config))
|
if (value.configClass.equals(config))
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.gitlab.jfronny.libjf.config.impl;
|
package io.gitlab.jfronny.libjf.config.impl;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.libjf.config.api.Entry;
|
||||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
@ -15,4 +16,5 @@ public class EntryInfo {
|
|||||||
public Object value;
|
public Object value;
|
||||||
public String tempValue;
|
public String tempValue;
|
||||||
public boolean inLimits = true;
|
public boolean inLimits = true;
|
||||||
|
public Entry entry;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
public class ButtonEntry extends ElementListWidget.Entry<ButtonEntry> {
|
public class ConfigScreenEntry extends ElementListWidget.Entry<ConfigScreenEntry> {
|
||||||
private static final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
|
private static final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
|
||||||
public final List<ClickableWidget> buttons = new ArrayList<>();
|
public final List<ClickableWidget> buttons = new ArrayList<>();
|
||||||
private final List<ClickableWidget> resetButtons = new ArrayList<>();
|
private final List<ClickableWidget> resetButtons = new ArrayList<>();
|
||||||
@ -26,7 +26,7 @@ public class ButtonEntry extends ElementListWidget.Entry<ButtonEntry> {
|
|||||||
private final List<ClickableWidget> buttonsWithResetButtons = new ArrayList<>();
|
private final List<ClickableWidget> buttonsWithResetButtons = new ArrayList<>();
|
||||||
public static final Map<ClickableWidget, Text> buttonsWithText = new HashMap<>();
|
public static final Map<ClickableWidget, Text> buttonsWithText = new HashMap<>();
|
||||||
|
|
||||||
private ButtonEntry(ClickableWidget button, Text text, ClickableWidget resetButton) {
|
private ConfigScreenEntry(ClickableWidget button, Text text, ClickableWidget resetButton) {
|
||||||
buttonsWithText.put(button,text);
|
buttonsWithText.put(button,text);
|
||||||
this.buttons.add(button);
|
this.buttons.add(button);
|
||||||
this.resetButtons.add(resetButton);
|
this.resetButtons.add(resetButton);
|
||||||
@ -34,8 +34,8 @@ public class ButtonEntry extends ElementListWidget.Entry<ButtonEntry> {
|
|||||||
this.buttonsWithResetButtons.add(button);
|
this.buttonsWithResetButtons.add(button);
|
||||||
this.buttonsWithResetButtons.add(resetButton);
|
this.buttonsWithResetButtons.add(resetButton);
|
||||||
}
|
}
|
||||||
public static ButtonEntry create(ClickableWidget button, Text text, ClickableWidget resetButton) {
|
public static ConfigScreenEntry create(ClickableWidget button, Text text, ClickableWidget resetButton) {
|
||||||
return new ButtonEntry(button, text, resetButton);
|
return new ConfigScreenEntry(button, text, resetButton);
|
||||||
}
|
}
|
||||||
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
||||||
this.buttons.forEach((button) -> {
|
this.buttons.forEach((button) -> {
|
@ -39,15 +39,14 @@ public class EntryInfoWidgetBuilder {
|
|||||||
private static void initEntry(Config config, EntryInfo info) {
|
private static void initEntry(Config config, EntryInfo info) {
|
||||||
if (!(info.field.isAnnotationPresent(io.gitlab.jfronny.libjf.config.api.Entry.class) || info.field.isAnnotationPresent(GsonHidden.class))) return;
|
if (!(info.field.isAnnotationPresent(io.gitlab.jfronny.libjf.config.api.Entry.class) || info.field.isAnnotationPresent(GsonHidden.class))) return;
|
||||||
Class<?> type = info.field.getType();
|
Class<?> type = info.field.getType();
|
||||||
io.gitlab.jfronny.libjf.config.api.Entry e = info.field.getAnnotation(Entry.class);
|
info.width = info.entry != null ? info.entry.width() : 0;
|
||||||
info.width = e != null ? e.width() : 0;
|
|
||||||
|
|
||||||
if (e == null) return;
|
if (info.entry == null) return;
|
||||||
|
|
||||||
if (type == int.class || type == Integer.class) textField(config, info, Integer::parseInt, INTEGER_ONLY, e.min(), e.max(), true);
|
if (type == int.class || type == Integer.class) textField(config, info, Integer::parseInt, INTEGER_ONLY, info.entry.min(), info.entry.max(), true);
|
||||||
else if (type == float.class || type == Float.class) textField(config, info, Float::parseFloat, DECIMAL_ONLY, e.min(), e.max(),false);
|
else if (type == float.class || type == Float.class) textField(config, info, Float::parseFloat, DECIMAL_ONLY, info.entry.min(), info.entry.max(),false);
|
||||||
else if (type == double.class || type == Double.class) textField(config, info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(),false);
|
else if (type == double.class || type == Double.class) textField(config, info, Double::parseDouble, DECIMAL_ONLY, info.entry.min(), info.entry.max(),false);
|
||||||
else if (type == String.class) textField(config, info, String::length, null, Math.min(e.min(),0), Math.max(e.max(),1),true);
|
else if (type == String.class) textField(config, info, String::length, null, Math.min(info.entry.min(),0), Math.max(info.entry.max(),1),true);
|
||||||
else if (type == boolean.class || type == Boolean.class) {
|
else if (type == boolean.class || type == Boolean.class) {
|
||||||
Function<Object, Text> func = value -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED);
|
Function<Object, Text> func = value -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED);
|
||||||
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
|
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
|
||||||
|
@ -11,7 +11,7 @@ import net.minecraft.text.Text;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
public class MidnightConfigListWidget extends ElementListWidget<ButtonEntry> {
|
public class MidnightConfigListWidget extends ElementListWidget<ConfigScreenEntry> {
|
||||||
TextRenderer textRenderer;
|
TextRenderer textRenderer;
|
||||||
|
|
||||||
public MidnightConfigListWidget(MinecraftClient minecraftClient, int i, int j, int k, int l, int m) {
|
public MidnightConfigListWidget(MinecraftClient minecraftClient, int i, int j, int k, int l, int m) {
|
||||||
@ -23,12 +23,13 @@ public class MidnightConfigListWidget extends ElementListWidget<ButtonEntry> {
|
|||||||
public int getScrollbarPositionX() { return this.width -7; }
|
public int getScrollbarPositionX() { return this.width -7; }
|
||||||
|
|
||||||
public void addButton(ClickableWidget button, ClickableWidget resetButton, Text text) {
|
public void addButton(ClickableWidget button, ClickableWidget resetButton, Text text) {
|
||||||
this.addEntry(ButtonEntry.create(button, text, resetButton));
|
this.addEntry(ConfigScreenEntry.create(button, text, resetButton));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int getRowWidth() { return 10000; }
|
public int getRowWidth() { return 10000; }
|
||||||
|
|
||||||
public Optional<ClickableWidget> getHoveredButton(double mouseY) {
|
public Optional<ClickableWidget> getHoveredButton(double mouseY) {
|
||||||
for (ButtonEntry buttonEntry : this.children()) {
|
for (ConfigScreenEntry buttonEntry : this.children()) {
|
||||||
for (ClickableWidget button : buttonEntry.buttons) {
|
for (ClickableWidget button : buttonEntry.buttons) {
|
||||||
if (button.visible && mouseY >= button.y && mouseY < button.y + itemHeight) {
|
if (button.visible && mouseY >= button.y && mouseY < button.y + itemHeight) {
|
||||||
return Optional.of(button);
|
return Optional.of(button);
|
||||||
|
@ -4,8 +4,10 @@ import io.gitlab.jfronny.libjf.LibJf;
|
|||||||
import io.gitlab.jfronny.libjf.config.impl.Config;
|
import io.gitlab.jfronny.libjf.config.impl.Config;
|
||||||
import io.gitlab.jfronny.libjf.config.api.Entry;
|
import io.gitlab.jfronny.libjf.config.api.Entry;
|
||||||
import io.gitlab.jfronny.libjf.config.impl.EntryInfo;
|
import io.gitlab.jfronny.libjf.config.impl.EntryInfo;
|
||||||
|
import io.gitlab.jfronny.libjf.config.impl.gui.presets.PresetsScreen;
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
import net.minecraft.client.gui.screen.ScreenTexts;
|
import net.minecraft.client.gui.screen.ScreenTexts;
|
||||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
@ -40,15 +42,19 @@ public class TinyConfigScreen extends Screen {
|
|||||||
// Real Time config update //
|
// Real Time config update //
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
for (EntryInfo info : config.entries)
|
config.syncToClass();
|
||||||
try { info.field.set(null, info.value); }
|
|
||||||
catch (IllegalAccessException ignored) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init() {
|
protected void init() {
|
||||||
super.init();
|
super.init();
|
||||||
|
|
||||||
|
config.syncFromClass();
|
||||||
|
|
||||||
|
this.addDrawableChild(new ButtonWidget(4, 6, 80, 20, new TranslatableText("libjf-config-v0.presets"), button -> {
|
||||||
|
MinecraftClient.getInstance().setScreen(new PresetsScreen(this, config));
|
||||||
|
}));
|
||||||
|
|
||||||
this.addDrawableChild(new ButtonWidget(this.width / 2 - 154, this.height - 28, 150, 20, ScreenTexts.CANCEL, button -> {
|
this.addDrawableChild(new ButtonWidget(this.width / 2 - 154, this.height - 28, 150, 20, ScreenTexts.CANCEL, button -> {
|
||||||
try {
|
try {
|
||||||
LibJf.GSON.fromJson(Files.newBufferedReader(config.path), config.configClass); }
|
LibJf.GSON.fromJson(Files.newBufferedReader(config.path), config.configClass); }
|
||||||
@ -67,10 +73,7 @@ public class TinyConfigScreen extends Screen {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
ButtonWidget done = this.addDrawableChild(new ButtonWidget(this.width / 2 + 4, this.height - 28, 150, 20, ScreenTexts.DONE, (button) -> {
|
ButtonWidget done = this.addDrawableChild(new ButtonWidget(this.width / 2 + 4, this.height - 28, 150, 20, ScreenTexts.DONE, (button) -> {
|
||||||
for (EntryInfo info : config.entries)
|
config.syncToClass();
|
||||||
try {
|
|
||||||
info.field.set(null, info.value);
|
|
||||||
} catch (IllegalAccessException ignored) {}
|
|
||||||
config.write();
|
config.write();
|
||||||
Objects.requireNonNull(client).setScreen(parent);
|
Objects.requireNonNull(client).setScreen(parent);
|
||||||
}));
|
}));
|
||||||
@ -103,8 +106,8 @@ public class TinyConfigScreen extends Screen {
|
|||||||
this.list.addButton(dummy,dummy,name);
|
this.list.addButton(dummy,dummy,name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
||||||
this.renderBackground(matrices);
|
this.renderBackground(matrices);
|
||||||
@ -116,7 +119,7 @@ public class TinyConfigScreen extends Screen {
|
|||||||
if (widget.isPresent()) {
|
if (widget.isPresent()) {
|
||||||
for (EntryInfo info : config.entries) {
|
for (EntryInfo info : config.entries) {
|
||||||
ClickableWidget buttonWidget = widget.get();
|
ClickableWidget buttonWidget = widget.get();
|
||||||
Text text = ButtonEntry.buttonsWithText.get(buttonWidget);
|
Text text = ConfigScreenEntry.buttonsWithText.get(buttonWidget);
|
||||||
TranslatableText name = new TranslatableText(this.translationPrefix + info.field.getName());
|
TranslatableText name = new TranslatableText(this.translationPrefix + info.field.getName());
|
||||||
boolean showTooltip = text.equals(name);
|
boolean showTooltip = text.equals(name);
|
||||||
String tooltipKey = translationPrefix + info.field.getName() + ".tooltip";
|
String tooltipKey = translationPrefix + info.field.getName() + ".tooltip";
|
||||||
@ -135,4 +138,9 @@ public class TinyConfigScreen extends Screen {
|
|||||||
}
|
}
|
||||||
super.render(matrices,mouseX,mouseY,delta);
|
super.render(matrices,mouseX,mouseY,delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
MinecraftClient.getInstance().setScreen(parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package io.gitlab.jfronny.libjf.config.impl.gui.presets;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.Element;
|
||||||
|
import net.minecraft.client.gui.Selectable;
|
||||||
|
import net.minecraft.client.gui.widget.ClickableWidget;
|
||||||
|
import net.minecraft.client.gui.widget.ElementListWidget;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PresetEntry extends ElementListWidget.Entry<PresetEntry> {
|
||||||
|
private final ClickableWidget button;
|
||||||
|
public PresetEntry(ClickableWidget button) {
|
||||||
|
this.button = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends Selectable> selectableChildren() {
|
||||||
|
return List.of(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends Element> children() {
|
||||||
|
return List.of(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
||||||
|
button.y = y;
|
||||||
|
button.render(matrices, mouseX, mouseY, tickDelta);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package io.gitlab.jfronny.libjf.config.impl.gui.presets;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.widget.ClickableWidget;
|
||||||
|
import net.minecraft.client.gui.widget.ElementListWidget;
|
||||||
|
|
||||||
|
public class PresetListWidget extends ElementListWidget<PresetEntry> {
|
||||||
|
public PresetListWidget(MinecraftClient client, int i, int j, int k, int l, int m) {
|
||||||
|
super(client, i, j, k, l, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addButton(ClickableWidget button) {
|
||||||
|
addEntry(new PresetEntry(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScrollbarPositionX() { return this.width -7; }
|
||||||
|
@Override
|
||||||
|
public int getRowWidth() { return 10000; }
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package io.gitlab.jfronny.libjf.config.impl.gui.presets;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.libjf.LibJf;
|
||||||
|
import io.gitlab.jfronny.libjf.config.impl.Config;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.text.TranslatableText;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class PresetsScreen extends Screen {
|
||||||
|
private final Screen parent;
|
||||||
|
private final Config config;
|
||||||
|
private PresetListWidget list;
|
||||||
|
|
||||||
|
public PresetsScreen(Screen parent, Config config) {
|
||||||
|
super(new TranslatableText("libjf-config-v0.presets"));
|
||||||
|
this.parent = parent;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
super.init();
|
||||||
|
this.list = new PresetListWidget(this.client, this.width, this.height, 32, this.height - 32, 25);
|
||||||
|
for (Map.Entry<String, Runnable> entry : config.presets.entrySet()) {
|
||||||
|
this.list.addButton(new ButtonWidget(width / 2 - 100, 0, 200, 20,
|
||||||
|
new TranslatableText(entry.getKey()),
|
||||||
|
button -> {
|
||||||
|
LibJf.LOGGER.info("Preset selected: " + entry.getKey());
|
||||||
|
entry.getValue().run();
|
||||||
|
config.syncFromClass();
|
||||||
|
MinecraftClient.getInstance().setScreen(parent);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
this.addSelectableChild(this.list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
MinecraftClient.getInstance().setScreen(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
||||||
|
this.renderBackground(matrices);
|
||||||
|
this.list.render(matrices, mouseX, mouseY, delta);
|
||||||
|
|
||||||
|
drawCenteredText(matrices, textRenderer, title, width / 2, 15, 0xFFFFFF);
|
||||||
|
|
||||||
|
super.render(matrices, mouseX, mouseY, delta);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"libjf-config-v0.presets": "Presets",
|
||||||
|
"libjf-config-v0.default": "Default"
|
||||||
|
}
|
@ -2,6 +2,8 @@ package io.gitlab.jfronny.libjf.config.test;
|
|||||||
|
|
||||||
import io.gitlab.jfronny.libjf.config.api.JfConfig;
|
import io.gitlab.jfronny.libjf.config.api.JfConfig;
|
||||||
import io.gitlab.jfronny.libjf.config.api.Entry;
|
import io.gitlab.jfronny.libjf.config.api.Entry;
|
||||||
|
import io.gitlab.jfronny.libjf.config.api.Preset;
|
||||||
|
import io.gitlab.jfronny.libjf.config.api.Verifier;
|
||||||
import io.gitlab.jfronny.libjf.gson.GsonHidden;
|
import io.gitlab.jfronny.libjf.gson.GsonHidden;
|
||||||
|
|
||||||
public class TestConfig implements JfConfig {
|
public class TestConfig implements JfConfig {
|
||||||
@ -15,6 +17,21 @@ public class TestConfig implements JfConfig {
|
|||||||
public static String gsonOnlyStr = "lolz";
|
public static String gsonOnlyStr = "lolz";
|
||||||
@Entry public static Test enumTest = Test.Test;
|
@Entry public static Test enumTest = Test.Test;
|
||||||
|
|
||||||
|
@Preset
|
||||||
|
public static void moskau() {
|
||||||
|
disablePacks = true;
|
||||||
|
disablePacks2 = true;
|
||||||
|
intTest = -5;
|
||||||
|
floatTest = -6;
|
||||||
|
doubleTest = 4;
|
||||||
|
dieStr = "Moskau";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Verifier
|
||||||
|
public static void setIntTestIfDisable() {
|
||||||
|
if (disablePacks) intTest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public enum Test {
|
public enum Test {
|
||||||
Test, ER
|
Test, ER
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,6 @@
|
|||||||
"libjf-config-v0-testmod.jfconfig.enumTest": "Enum Test",
|
"libjf-config-v0-testmod.jfconfig.enumTest": "Enum Test",
|
||||||
"libjf-config-v0-testmod.jfconfig.enumTest.tooltip": "Enum Test Tooltip",
|
"libjf-config-v0-testmod.jfconfig.enumTest.tooltip": "Enum Test Tooltip",
|
||||||
"libjf-config-v0-testmod.jfconfig.enum.Test.Test": "Test",
|
"libjf-config-v0-testmod.jfconfig.enum.Test.Test": "Test",
|
||||||
"libjf-config-v0-testmod.jfconfig.enum.Test.ER": "ER"
|
"libjf-config-v0-testmod.jfconfig.enum.Test.ER": "ER",
|
||||||
|
"libjf-config-v0-testmod.jfconfig.moskau": "Moskau"
|
||||||
}
|
}
|
@ -39,7 +39,7 @@ public class UserResourceEvents {
|
|||||||
|
|
||||||
public static final Event<Contains> CONTAINS = EventFactory.createArrayBacked(Contains.class,
|
public static final Event<Contains> CONTAINS = EventFactory.createArrayBacked(Contains.class,
|
||||||
(listeners) -> (type, id, previous, pack) -> {
|
(listeners) -> (type, id, previous, pack) -> {
|
||||||
LazySupplier<Boolean> lazy = new LazySupplier<>(previous); //TODO make initial value lazy properly
|
LazySupplier<Boolean> lazy = new LazySupplier<>(previous);
|
||||||
for (Contains listener : listeners) {
|
for (Contains listener : listeners) {
|
||||||
lazy = lazy.andThen(supplier -> listener.contains(type, id, supplier, pack));
|
lazy = lazy.andThen(supplier -> listener.contains(type, id, supplier, pack));
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ public class UserResourceEvents {
|
|||||||
|
|
||||||
public static final Event<FindResource> FIND_RESOURCE = EventFactory.createArrayBacked(FindResource.class,
|
public static final Event<FindResource> FIND_RESOURCE = EventFactory.createArrayBacked(FindResource.class,
|
||||||
(listeners) -> ((type, namespace, prefix, maxDepth, pathFilter, previous, pack) -> {
|
(listeners) -> ((type, namespace, prefix, maxDepth, pathFilter, previous, pack) -> {
|
||||||
LazySupplier<Collection<Identifier>> lazy = new LazySupplier<>(previous); //TODO make initial value lazy properly
|
LazySupplier<Collection<Identifier>> lazy = new LazySupplier<>(previous);
|
||||||
for (FindResource listener : listeners) {
|
for (FindResource listener : listeners) {
|
||||||
lazy = lazy.andThen(supplier -> listener.findResources(type, namespace, prefix, maxDepth, pathFilter, supplier, pack));
|
lazy = lazy.andThen(supplier -> listener.findResources(type, namespace, prefix, maxDepth, pathFilter, supplier, pack));
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ public class UserResourceEvents {
|
|||||||
|
|
||||||
public static final Event<Open> OPEN = EventFactory.createArrayBacked(Open.class,
|
public static final Event<Open> OPEN = EventFactory.createArrayBacked(Open.class,
|
||||||
(listeners) -> ((type, id, previous, pack) -> {
|
(listeners) -> ((type, id, previous, pack) -> {
|
||||||
LazySupplier<InputStream> lazy = new LazySupplier<>(previous); //TODO make initial value lazy properly
|
LazySupplier<InputStream> lazy = new LazySupplier<>(previous);
|
||||||
for (Open listener : listeners) {
|
for (Open listener : listeners) {
|
||||||
lazy = lazy.andThen(supplier -> {
|
lazy = lazy.andThen(supplier -> {
|
||||||
try {
|
try {
|
||||||
@ -73,7 +73,7 @@ public class UserResourceEvents {
|
|||||||
|
|
||||||
public static final Event<OpenRoot> OPEN_ROOT = EventFactory.createArrayBacked(OpenRoot.class,
|
public static final Event<OpenRoot> OPEN_ROOT = EventFactory.createArrayBacked(OpenRoot.class,
|
||||||
(listeners) -> ((fileName, previous, pack) -> {
|
(listeners) -> ((fileName, previous, pack) -> {
|
||||||
LazySupplier<InputStream> lazy = new LazySupplier<>(previous); //TODO make initial value lazy properly
|
LazySupplier<InputStream> lazy = new LazySupplier<>(previous);
|
||||||
for (OpenRoot listener : listeners) {
|
for (OpenRoot listener : listeners) {
|
||||||
lazy = lazy.andThen(supplier -> {
|
lazy = lazy.andThen(supplier -> {
|
||||||
try {
|
try {
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
"package": "io.gitlab.jfronny.libjf.devutil.mixin",
|
"package": "io.gitlab.jfronny.libjf.devutil.mixin",
|
||||||
"compatibilityLevel": "JAVA_16",
|
"compatibilityLevel": "JAVA_16",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"MinecraftClientMixin"
|
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
|
"MinecraftClientMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
Loading…
Reference in New Issue
Block a user