[config] Category support pt 1
This commit is contained in:
parent
2e3d0f0e70
commit
9b28e3fadb
|
@ -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.TYPE)
|
||||
public @interface Category {
|
||||
}
|
|
@ -21,4 +21,6 @@ public interface ConfigInstance {
|
|||
List<EntryInfo> getEntries();
|
||||
Map<String, Runnable> getPresets();
|
||||
List<String> getReferencedConfigs();
|
||||
Map<String, ConfigInstance> getCategories();
|
||||
String getCategoryPath();
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class ConfigHolderImpl implements ConfigHolder {
|
|||
else {
|
||||
LibJf.LOGGER.warn("Attempted to register config for a mod that is not installed: " + modId);
|
||||
}
|
||||
ConfigInstanceImpl instance = new ConfigInstanceImpl(modId, config, meta.sanitize());
|
||||
ConfigInstanceRoot instance = new ConfigInstanceRoot(modId, config, meta.sanitize());
|
||||
configs.put(modId, instance);
|
||||
configsByPath.put(instance.path, instance);
|
||||
}
|
||||
|
|
|
@ -1,38 +1,28 @@
|
|||
package io.gitlab.jfronny.libjf.config.impl;
|
||||
|
||||
import io.gitlab.jfronny.libjf.LibJf;
|
||||
import io.gitlab.jfronny.libjf.config.api.ConfigInstance;
|
||||
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 io.gitlab.jfronny.libjf.config.api.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/** Based on https://github.com/TeamMidnightDust/MidnightLib which is based on https://github.com/Minenash/TinyConfig
|
||||
* Credits to TeamMidnightDust and Minenash */
|
||||
|
||||
public class ConfigInstanceImpl implements ConfigInstance {
|
||||
public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
||||
public final String modId;
|
||||
private final String categoryPath;
|
||||
public final Class<?> configClass;
|
||||
public final List<String> referencedConfigs;
|
||||
public final List<EntryInfo> entries = new ArrayList<>();
|
||||
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 Class<?> configClass;
|
||||
public final List<String> referencedConfigs;
|
||||
|
||||
public ConfigInstanceImpl(String modid, Class<?> config, AuxiliaryMetadata meta) {
|
||||
this.modid = modid;
|
||||
configClass = config;
|
||||
referencedConfigs = List.copyOf(meta.referencedConfigs);
|
||||
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
|
||||
|
||||
for (Field field : config.getFields()) {
|
||||
public final Map<String, ConfigInstance> subcategories = new LinkedHashMap<>();
|
||||
public ConfigInstanceAbstract(String modId, String categoryPath, Class<?> configClass, AuxiliaryMetadata meta) {
|
||||
this.modId = modId;
|
||||
this.categoryPath = categoryPath;
|
||||
this.configClass = configClass;
|
||||
this.referencedConfigs = List.copyOf(meta.referencedConfigs);
|
||||
for (Field field : configClass.getFields()) {
|
||||
EntryInfo info = new EntryInfo();
|
||||
info.field = field;
|
||||
if (field.isAnnotationPresent(Entry.class)) {
|
||||
|
@ -52,9 +42,10 @@ public class ConfigInstanceImpl implements ConfigInstance {
|
|||
}
|
||||
}
|
||||
});
|
||||
for (Method method : config.getMethods()) {
|
||||
|
||||
for (Method method : configClass.getMethods()) {
|
||||
if (method.isAnnotationPresent(Preset.class)) {
|
||||
presets.put(modid + ".jfconfig." + method.getName(), () -> {
|
||||
presets.put(modId + ".jfconfig." + method.getName(), () -> {
|
||||
try {
|
||||
method.invoke(null);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
|
@ -101,19 +92,14 @@ public class ConfigInstanceImpl implements ConfigInstance {
|
|||
}
|
||||
}
|
||||
});
|
||||
load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
try {
|
||||
LibJf.GSON.fromJson(Files.newBufferedReader(path), configClass);
|
||||
for (Class<?> categoryClass : configClass.getClasses()) {
|
||||
if (categoryClass.isAnnotationPresent(Category.class)) {
|
||||
String path = categoryPath + categoryClass.getSimpleName() + ".";
|
||||
//TODO allow custom auxiliary metadata
|
||||
subcategories.put(path, new ConfigInstanceCategory(this, modId, path, categoryClass, new AuxiliaryMetadata().sanitize()));
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
LibJf.LOGGER.error("Could not read config", e);
|
||||
}
|
||||
syncFromClass();
|
||||
write();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -126,6 +112,9 @@ public class ConfigInstanceImpl implements ConfigInstance {
|
|||
}
|
||||
}
|
||||
syncFromClass();
|
||||
for (ConfigInstance instance : subcategories.values()) {
|
||||
instance.syncToClass();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -142,30 +131,26 @@ public class ConfigInstanceImpl implements ConfigInstance {
|
|||
LibJf.LOGGER.error("Could not read value", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write() {
|
||||
try {
|
||||
JfConfigWatchService.lock(path, () -> {
|
||||
if (!Files.exists(path)) Files.createFile(path);
|
||||
Files.write(path, LibJf.GSON.toJson(configClass.getDeclaredConstructor().newInstance()).getBytes());
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
for (ConfigInstance instance : subcategories.values()) {
|
||||
instance.syncFromClass();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModId() {
|
||||
return modid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesConfigClass(Class<?> candidate) {
|
||||
return candidate != null && candidate.isAssignableFrom(configClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModId() {
|
||||
return modId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategoryPath() {
|
||||
return categoryPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EntryInfo> getEntries() {
|
||||
return entries;
|
||||
|
@ -180,4 +165,9 @@ public class ConfigInstanceImpl implements ConfigInstance {
|
|||
public List<String> getReferencedConfigs() {
|
||||
return referencedConfigs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ConfigInstance> getCategories() {
|
||||
return subcategories;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package io.gitlab.jfronny.libjf.config.impl;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.api.ConfigInstance;
|
||||
|
||||
public class ConfigInstanceCategory extends ConfigInstanceAbstract {
|
||||
private final ConfigInstance parent;
|
||||
|
||||
public ConfigInstanceCategory(ConfigInstance parent, String modId, String categoryPath, Class<?> configClass, AuxiliaryMetadata meta) {
|
||||
super(modId, categoryPath, configClass, meta);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
parent.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write() {
|
||||
parent.write();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package io.gitlab.jfronny.libjf.config.impl;
|
||||
|
||||
import io.gitlab.jfronny.libjf.LibJf;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/** Based on https://github.com/TeamMidnightDust/MidnightLib which is based on https://github.com/Minenash/TinyConfig
|
||||
* Credits to TeamMidnightDust and Minenash */
|
||||
public class ConfigInstanceRoot extends ConfigInstanceAbstract {
|
||||
public final Path path;
|
||||
|
||||
public ConfigInstanceRoot(String modId, Class<?> config, AuxiliaryMetadata meta) {
|
||||
super(modId, "", config, meta);
|
||||
path = FabricLoader.getInstance().getConfigDir().resolve(modId + ".json");
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
try {
|
||||
LibJf.GSON.fromJson(Files.newBufferedReader(path), configClass);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LibJf.LOGGER.error("Could not read config", e);
|
||||
}
|
||||
syncFromClass();
|
||||
write();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write() {
|
||||
try {
|
||||
JfConfigWatchService.lock(path, () -> {
|
||||
if (!Files.exists(path)) Files.createFile(path);
|
||||
Files.write(path, LibJf.GSON.toJson(configClass.getDeclaredConstructor().newInstance()).getBytes());
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LibJf.LOGGER.error("Could not write config", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,13 +23,14 @@ import java.util.function.BiFunction;
|
|||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
//TODO fix missing controls for subcategories
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class TinyConfigScreen extends Screen {
|
||||
public TinyConfigScreen(ConfigInstance config, Screen parent) {
|
||||
super(new TranslatableText(config.getModId() + ".jfconfig." + "title"));
|
||||
super(new TranslatableText(config.getModId() + ".jfconfig." + config.getCategoryPath() + "title"));
|
||||
this.parent = parent;
|
||||
this.config = config;
|
||||
this.translationPrefix = config.getModId() + ".jfconfig.";
|
||||
this.translationPrefix = config.getModId() + ".jfconfig." + config.getCategoryPath();
|
||||
}
|
||||
private final String translationPrefix;
|
||||
private final Screen parent;
|
||||
|
@ -65,6 +66,11 @@ public class TinyConfigScreen extends Screen {
|
|||
|
||||
this.list = new MidnightConfigListWidget(this.client, this.width, this.height, 32, this.height - 32, 25);
|
||||
this.addSelectableChild(this.list);
|
||||
for (Map.Entry<String, ConfigInstance> entry : config.getCategories().entrySet()) {
|
||||
this.list.addReference(width / 2,
|
||||
new TranslatableText(entry.getValue().getModId() + ".jfconfig." + entry.getValue().getCategoryPath() + "title"),
|
||||
() -> new TinyConfigScreen(entry.getValue(), this));
|
||||
}
|
||||
for (EntryInfo info : config.getEntries()) {
|
||||
TranslatableText name = new TranslatableText(translationPrefix + info.field.getName());
|
||||
ButtonWidget resetButton = new ButtonWidget(width - 155, 0, 40, 20, new LiteralText("Reset").formatted(Formatting.RED), (button -> {
|
||||
|
@ -95,7 +101,7 @@ public class TinyConfigScreen extends Screen {
|
|||
ConfigInstance ci = ConfigHolder.getInstance().get(referencedConfig);
|
||||
if (ci != null) {
|
||||
this.list.addReference(width / 2,
|
||||
new TranslatableText("libjf-config-v0.see-also", new TranslatableText(ci.getModId() + ".jfconfig.title")),
|
||||
new TranslatableText("libjf-config-v0.see-also", new TranslatableText(ci.getModId() + ".jfconfig." + ci.getCategoryPath() + "title")),
|
||||
() -> new TinyConfigScreen(ci, this));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package io.gitlab.jfronny.libjf.config.test;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.api.JfConfig;
|
||||
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.config.api.*;
|
||||
import io.gitlab.jfronny.libjf.gson.GsonHidden;
|
||||
|
||||
public class TestConfig implements JfConfig {
|
||||
|
@ -35,4 +32,15 @@ public class TestConfig implements JfConfig {
|
|||
public enum Test {
|
||||
Test, ER
|
||||
}
|
||||
|
||||
@Category
|
||||
public static class Subcategory {
|
||||
@Entry public static boolean boolInSub = false;
|
||||
@Entry public static int intIbSub = 15;
|
||||
|
||||
@Category
|
||||
public static class Inception {
|
||||
@Entry public static Test yesEnum = Test.ER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.libjf.data.manipulation.api;
|
||||
|
||||
import io.gitlab.jfronny.libjf.LibJf;
|
||||
import io.gitlab.jfronny.libjf.data.manipulation.impl.ResourcePackHook;
|
||||
import io.gitlab.jfronny.libjf.interfaces.LazySupplier;
|
||||
import io.gitlab.jfronny.libjf.interfaces.ThrowingRunnable;
|
||||
|
@ -63,7 +64,7 @@ public class UserResourceEvents {
|
|||
try {
|
||||
return listener.open(type, id, supplier, pack);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LibJf.LOGGER.error("Could not call ResourcePack.OPEN listener", e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
@ -79,7 +80,7 @@ public class UserResourceEvents {
|
|||
try {
|
||||
return listener.openRoot(fileName, supplier, pack);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LibJf.LOGGER.error("Could not call ResourcePack.OPEN_ROOT listener", e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -115,7 +115,7 @@ public class AsmTransformer implements IMixinTransformer {
|
|||
if (!Files.exists(path)) Files.createDirectories(path.getParent());
|
||||
Files.write(path, classBytes);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LibJf.LOGGER.error("Could not export modified bytecode", e);
|
||||
}
|
||||
}
|
||||
return classBytes;
|
||||
|
|
|
@ -17,13 +17,13 @@ public class DefaultFileHost implements WebInit {
|
|||
try {
|
||||
Files.createDirectory(p);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LibJf.LOGGER.error("Could not create wwwroot", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
LibJf.LOGGER.info(api.registerDir("/", p, false));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LibJf.LOGGER.error("Could not register wwwroot", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.libjf.web.impl;
|
||||
|
||||
import io.gitlab.jfronny.libjf.LibJf;
|
||||
import io.gitlab.jfronny.libjf.config.api.ConfigHolder;
|
||||
import io.gitlab.jfronny.libjf.config.api.Entry;
|
||||
import io.gitlab.jfronny.libjf.config.api.JfConfig;
|
||||
|
@ -24,7 +25,7 @@ public class JfWebConfig implements JfConfig {
|
|||
try (ServerSocket socket = new ServerSocket(0)) {
|
||||
port = socket.getLocalPort();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LibJf.LOGGER.error("Could not bind port to identify available", e);
|
||||
}
|
||||
ConfigHolder.getInstance().getRegistered().get("libjf-web-v0").write();
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ public class JfWebServer implements WebServer {
|
|||
try {
|
||||
registerFile(wp, s, false);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LibJf.LOGGER.error("Could not register static file", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,13 +14,13 @@ import java.nio.file.Path;
|
|||
public class WebTest implements WebInit {
|
||||
@Override
|
||||
public void register(WebServer api) {
|
||||
Path sourcePath = FabricLoader.getInstance().getModContainer("libjf-web-v0-testmod").get().getPath("test.html");
|
||||
Path sourcePath = FabricLoader.getInstance().getModContainer("libjf-web-v0-testmod").get().findPath("test.html").get();
|
||||
LibJf.LOGGER.info(api.register("/test/0.html", request -> new HttpResponse(HttpStatusCode.OK).setData(Files.readString(sourcePath))));
|
||||
try {
|
||||
LibJf.LOGGER.info(api.registerFile("/test/1.html", sourcePath, false));
|
||||
LibJf.LOGGER.info(api.registerFile("/test/2.html", sourcePath, true));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Could not register hosted files", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue