[config] Remove internal APIs from interfaces to allow reusing the related systems elsewhere
This commit is contained in:
parent
06bd6a1961
commit
f53e9b74b6
|
@ -47,7 +47,7 @@ Enum keys are translated as follows: `<mod id>.jfconfig.enum.<enum class name>.<
|
|||
|
||||
## Categories
|
||||
Categories can be added by creating public static subclasses in your config class and annotating them with @Category.
|
||||
Entries will be read as before, however translations for fields will use `jfconfig.<category>.<field name>` instead of `jfconfig.<field name>`
|
||||
Entries will be read as before, however the translation prefix will be `jfconfig.<category>.` instead of `jfconfig.`
|
||||
|
||||
## Presets
|
||||
libjf-config-v0 provides a preset system to automatically fill in certain values based on a function.
|
||||
|
|
|
@ -15,6 +15,7 @@ public class LibJf {
|
|||
|
||||
static {
|
||||
GsonHolder.modifyBuilder((final GsonBuilder builder) -> {
|
||||
builder.setOmitQuotes();
|
||||
for (GsonAdapter adapter : FabricLoader.getInstance().getEntrypoints(MOD_ID + ":gson_adapter", GsonAdapter.class)) {
|
||||
adapter.apply(builder);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
package io.gitlab.jfronny.libjf.config.api;
|
||||
|
||||
import io.gitlab.jfronny.gson.JsonObject;
|
||||
import io.gitlab.jfronny.gson.stream.JsonWriter;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -17,15 +12,20 @@ public interface ConfigInstance {
|
|||
}
|
||||
void load();
|
||||
void write();
|
||||
String getModId();
|
||||
String getId();
|
||||
String getCategoryPath();
|
||||
default String getTranslationPrefix() {
|
||||
return getId() + ".jfconfig." + getCategoryPath();
|
||||
}
|
||||
List<EntryInfo<?>> getEntries();
|
||||
Map<String, Runnable> getPresets();
|
||||
List<String> getReferencedConfigs();
|
||||
default List<ConfigInstance> getReferencedConfigs() {
|
||||
return List.of();
|
||||
}
|
||||
Map<String, ConfigInstance> getCategories();
|
||||
|
||||
@ApiStatus.Internal void verify();
|
||||
@ApiStatus.Internal boolean matchesConfigClass(Class<?> candidate);
|
||||
@ApiStatus.Internal void loadFrom(JsonObject source);
|
||||
@ApiStatus.Internal void writeTo(JsonWriter writer) throws IOException;
|
||||
@ApiStatus.Internal String getCategoryPath();
|
||||
default void fix() {
|
||||
for (EntryInfo<?> entry : getEntries()) {
|
||||
entry.fix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,26 +2,10 @@ package io.gitlab.jfronny.libjf.config.api;
|
|||
|
||||
import io.gitlab.jfronny.gson.JsonElement;
|
||||
import io.gitlab.jfronny.gson.stream.JsonWriter;
|
||||
import io.gitlab.jfronny.libjf.config.impl.EntryInfoImpl;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public interface EntryInfo<T> {
|
||||
static <T> @Nullable EntryInfo<T> fromField(Field field) {
|
||||
if (!field.isAnnotationPresent(Entry.class)) {
|
||||
return null;
|
||||
}
|
||||
EntryInfoImpl<T> info = new EntryInfoImpl<>();
|
||||
info.field = field;
|
||||
info.entry = field.getAnnotation(Entry.class);
|
||||
try {
|
||||
info.defaultValue = (T) field.get(null);
|
||||
} catch (IllegalAccessException ignored) {}
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Get the default value of this entry
|
||||
*/
|
||||
|
|
|
@ -24,7 +24,7 @@ public class ConfigHolderImpl implements ConfigHolder {
|
|||
@Override
|
||||
public void register(String modId, Class<?> config) {
|
||||
if (isRegistered(modId)) {
|
||||
if (get(modId).matchesConfigClass(config)) {
|
||||
if (get(modId) instanceof ConfigInstanceAbstract instance && instance.matchesConfigClass(config)) {
|
||||
SafeLog.warn("Attempted to set config of " + modId + " twice, skipping");
|
||||
return;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public class ConfigHolderImpl implements ConfigHolder {
|
|||
@Override
|
||||
public ConfigInstance get(Class<?> configClass) {
|
||||
for (ConfigInstance value : configs.values()) {
|
||||
if (value.matchesConfigClass(configClass))
|
||||
if (value instanceof ConfigInstanceAbstract instance && instance.matchesConfigClass(configClass))
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
|
@ -80,7 +80,7 @@ public class ConfigHolderImpl implements ConfigHolder {
|
|||
@Override
|
||||
public boolean isRegistered(Class<?> config) {
|
||||
for (ConfigInstance value : configs.values()) {
|
||||
if (value.matchesConfigClass(config))
|
||||
if (value instanceof ConfigInstanceAbstract instance && instance.matchesConfigClass(config))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -29,8 +29,8 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
|||
this.configClass = configClass;
|
||||
this.referencedConfigs = List.copyOf(meta.referencedConfigs);
|
||||
for (Field field : configClass.getFields()) {
|
||||
EntryInfo<?> newInfo = EntryInfo.fromField(field);
|
||||
if (newInfo != null) entries.add(newInfo);
|
||||
if (field.isAnnotationPresent(Entry.class))
|
||||
entries.add(new EntryInfoImpl<>(field));
|
||||
}
|
||||
presets.put(CONFIG_PRESET_DEFAULT, () -> {
|
||||
for (EntryInfo<?> entry : entries) {
|
||||
|
@ -62,11 +62,6 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
|||
});
|
||||
}
|
||||
}
|
||||
verifiers.add(() -> {
|
||||
for (EntryInfo<?> entry : entries) {
|
||||
entry.fix();
|
||||
}
|
||||
});
|
||||
|
||||
for (Class<?> categoryClass : configClass.getClasses()) {
|
||||
if (categoryClass.isAnnotationPresent(Category.class)) {
|
||||
|
@ -88,7 +83,6 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
|||
return Character.toLowerCase(source.charAt(0)) + source.substring(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFrom(JsonObject source) {
|
||||
for (EntryInfo<?> entry : entries) {
|
||||
if (source.has(entry.getName())) {
|
||||
|
@ -100,17 +94,16 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
|||
} else SafeLog.error("Config does not contain entry for " + entry.getName());
|
||||
}
|
||||
for (Map.Entry<String, ConfigInstance> entry : subcategories.entrySet()) {
|
||||
if (source.has(entry.getKey())) {
|
||||
if (entry.getValue() instanceof ConfigInstanceAbstract instance && source.has(entry.getKey())) {
|
||||
JsonElement el = source.get(entry.getKey());
|
||||
if (el.isJsonObject()) entry.getValue().loadFrom(el.getAsJsonObject());
|
||||
if (el.isJsonObject()) instance.loadFrom(el.getAsJsonObject());
|
||||
else SafeLog.error("Config category is not a JSON object, skipping");
|
||||
} else SafeLog.error("Config does not contain entry for subcategory " + entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(JsonWriter writer) throws IOException {
|
||||
verify();
|
||||
fix();
|
||||
writer.beginObject();
|
||||
String val;
|
||||
for (EntryInfo<?> entry : entries) {
|
||||
|
@ -121,26 +114,27 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
|||
}
|
||||
}
|
||||
for (Map.Entry<String, ConfigInstance> entry : subcategories.entrySet()) {
|
||||
if (!(entry.getValue() instanceof ConfigInstanceAbstract instance)) continue;
|
||||
if ((val = JfConfigSafe.TRANSLATION_SUPPLIER.apply(modId + ".jfconfig." + categoryPath + entry.getKey() + ".title")) != null)
|
||||
writer.comment(val);
|
||||
writer.name(entry.getKey());
|
||||
entry.getValue().writeTo(writer);
|
||||
instance.writeTo(writer);
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verify() {
|
||||
public void fix() {
|
||||
for (Runnable verifier : verifiers) verifier.run();
|
||||
for (EntryInfo<?> entry : entries) entry.fix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesConfigClass(Class<?> candidate) {
|
||||
return candidate != null && candidate.isAssignableFrom(configClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModId() {
|
||||
public String getId() {
|
||||
return modId;
|
||||
}
|
||||
|
||||
|
@ -160,8 +154,13 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<String> getReferencedConfigs() {
|
||||
return referencedConfigs;
|
||||
public List<ConfigInstance> getReferencedConfigs() {
|
||||
List<ConfigInstance> result = new LinkedList<>();
|
||||
for (String referencedConfig : referencedConfigs) {
|
||||
ConfigInstance ci = ConfigHolder.getInstance().get(referencedConfig);
|
||||
if (ci != null) result.add(ci);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,7 +18,12 @@ public class EntryInfoImpl<T> implements EntryInfo<T> {
|
|||
public T defaultValue;
|
||||
public Entry entry;
|
||||
|
||||
public EntryInfoImpl() {
|
||||
public EntryInfoImpl(Field field) {
|
||||
this.field = field;
|
||||
this.entry = field.getAnnotation(Entry.class);
|
||||
try {
|
||||
this.defaultValue = (T) field.get(null);
|
||||
} catch (IllegalAccessException ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,14 +3,13 @@ package io.gitlab.jfronny.libjf.config.impl.client;
|
|||
import io.gitlab.jfronny.libjf.LibJf;
|
||||
import io.gitlab.jfronny.libjf.config.api.ConfigHolder;
|
||||
import io.gitlab.jfronny.libjf.config.api.ConfigInstance;
|
||||
import io.gitlab.jfronny.libjf.config.impl.client.gui.EntryInfoWidgetBuilder;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
|
||||
public class JfConfigClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
for (ConfigInstance config : ConfigHolder.getInstance().getRegistered().values()) {
|
||||
LibJf.LOGGER.info("Registering config UI for " + config.getModId());
|
||||
LibJf.LOGGER.info("Registering config UI for " + config.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class EntryInfoWidgetBuilder {
|
|||
factory = toggle(info, state, value -> {
|
||||
int index = values.indexOf(value) + 1;
|
||||
return values.get(index >= values.size() ? 0 : index);
|
||||
}, value -> Text.translatable(config.getModId() + ".jfconfig.enum." + type.getSimpleName() + "." + state.cachedValue));
|
||||
}, value -> Text.translatable(config.getTranslationPrefix() + "enum." + type.getSimpleName() + "." + state.cachedValue));
|
||||
} else {
|
||||
LibJf.LOGGER.error("Invalid entry type in " + info.getName() + ": " + type.getName());
|
||||
factory = ((screenWidth, textRenderer, done) -> new WidgetFactory.Widget(() -> {}, new ButtonWidget(-10, 0, 0, 0, Text.of(""), null)));
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.libjf.config.impl.client.gui;
|
||||
|
||||
import io.gitlab.jfronny.commons.throwable.Try;
|
||||
import io.gitlab.jfronny.libjf.config.api.ConfigHolder;
|
||||
import io.gitlab.jfronny.libjf.config.api.ConfigInstance;
|
||||
import io.gitlab.jfronny.libjf.config.api.WidgetFactory;
|
||||
import io.gitlab.jfronny.libjf.config.impl.client.gui.presets.PresetsScreen;
|
||||
|
@ -21,11 +20,11 @@ import java.util.*;
|
|||
@Environment(EnvType.CLIENT)
|
||||
public class TinyConfigScreen extends Screen {
|
||||
public TinyConfigScreen(ConfigInstance config, Screen parent) {
|
||||
super(Text.translatable(config.getModId() + ".jfconfig." + config.getCategoryPath() + "title"));
|
||||
super(Text.translatable(config.getTranslationPrefix() + "title"));
|
||||
this.parent = parent;
|
||||
this.config = config;
|
||||
this.widgets = EntryInfoWidgetBuilder.buildWidgets(config);
|
||||
this.translationPrefix = config.getModId() + ".jfconfig." + config.getCategoryPath();
|
||||
this.translationPrefix = config.getTranslationPrefix();
|
||||
}
|
||||
private final String translationPrefix;
|
||||
private final Screen parent;
|
||||
|
@ -37,7 +36,7 @@ public class TinyConfigScreen extends Screen {
|
|||
protected void init() {
|
||||
super.init();
|
||||
|
||||
config.verify();
|
||||
config.fix();
|
||||
|
||||
this.addDrawableChild(new ButtonWidget(4, 6, 80, 20, Text.translatable("libjf-config-v0.presets"), button -> {
|
||||
MinecraftClient.getInstance().setScreen(new PresetsScreen(this, config));
|
||||
|
@ -60,7 +59,7 @@ public class TinyConfigScreen extends Screen {
|
|||
this.addSelectableChild(this.list);
|
||||
for (Map.Entry<String, ConfigInstance> entry : config.getCategories().entrySet()) {
|
||||
this.list.addReference(width / 2,
|
||||
Text.translatable(entry.getValue().getModId() + ".jfconfig." + entry.getValue().getCategoryPath() + "title"),
|
||||
Text.translatable(entry.getValue().getTranslationPrefix() + "title"),
|
||||
() -> new TinyConfigScreen(entry.getValue(), this));
|
||||
}
|
||||
for (WidgetState<?> info : widgets) {
|
||||
|
@ -76,11 +75,10 @@ public class TinyConfigScreen extends Screen {
|
|||
return visible;
|
||||
}, name);
|
||||
}
|
||||
for (String referencedConfig : config.getReferencedConfigs()) {
|
||||
ConfigInstance ci = ConfigHolder.getInstance().get(referencedConfig);
|
||||
for (ConfigInstance ci : config.getReferencedConfigs()) {
|
||||
if (ci != null) {
|
||||
this.list.addReference(width / 2,
|
||||
Text.translatable("libjf-config-v0.see-also", Text.translatable(ci.getModId() + ".jfconfig." + ci.getCategoryPath() + "title")),
|
||||
Text.translatable("libjf-config-v0.see-also", Text.translatable(ci.getTranslationPrefix() + "title")),
|
||||
() -> new TinyConfigScreen(ci, this));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public class PresetsScreen extends Screen {
|
|||
button -> {
|
||||
LibJf.LOGGER.info("Preset selected: " + entry.getKey());
|
||||
entry.getValue().run();
|
||||
config.verify();
|
||||
config.fix();
|
||||
MinecraftClient.getInstance().setScreen(parent);
|
||||
}));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue