فهرست منبع

Config manager restructure

Lortseam 4 سال پیش
والد
کامیت
6f688705db

+ 5 - 6
src/main/java/me/lortseam/completeconfig/CompleteConfig.java

@@ -3,26 +3,25 @@ package me.lortseam.completeconfig;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 
-import java.util.HashSet;
+import java.util.HashMap;
 import java.util.Optional;
-import java.util.Set;
 
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public final class CompleteConfig {
 
-    private static final Set<ConfigManager> managers = new HashSet<>();
+    private static final HashMap<String, ConfigManager> MANAGERS = new HashMap<>();
 
     public static ConfigManager register(String modID) {
-        if (getManager(modID).isPresent()) {
+        if (MANAGERS.containsKey(modID)) {
             throw new IllegalArgumentException("A manager with this mod ID is already registered");
         }
         ConfigManager manager = new ConfigManager(modID);
-        managers.add(manager);
+        MANAGERS.put(modID, manager);
         return manager;
     }
 
     public static Optional<ConfigManager> getManager(String modID) {
-        return managers.stream().filter(manager -> manager.getModID().equals(modID)).findAny();
+        return Optional.ofNullable(MANAGERS.get(modID));
     }
 
 }

+ 9 - 79
src/main/java/me/lortseam/completeconfig/ConfigManager.java

@@ -4,53 +4,31 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonNull;
-import lombok.AccessLevel;
-import lombok.Getter;
 import me.lortseam.completeconfig.api.ConfigCategory;
-import me.lortseam.completeconfig.api.ConfigEntryContainer;
-import me.lortseam.completeconfig.collection.Collection;
-import me.lortseam.completeconfig.entry.Entry;
+import me.lortseam.completeconfig.gui.GuiBuilder;
 import me.lortseam.completeconfig.gui.GuiRegistry;
 import me.lortseam.completeconfig.serialization.CollectionSerializer;
 import me.lortseam.completeconfig.serialization.EntrySerializer;
-import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
 import me.shedaniel.clothconfig2.api.ConfigBuilder;
-import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
-import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder;
 import net.fabricmc.loader.api.FabricLoader;
 import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.client.resource.language.I18n;
-import net.minecraft.text.Text;
-import net.minecraft.text.TranslatableText;
-import org.apache.commons.lang3.ArrayUtils;
 
 import java.io.*;
-import java.lang.reflect.Method;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.*;
 import java.util.function.Supplier;
-import java.util.stream.Collectors;
 
 public class ConfigManager {
 
-    private static String joinIDs(String... ids) {
-        return String.join(".", ids);
-    }
-
-    @Getter(AccessLevel.PACKAGE)
-    private final String modID;
     private final Path jsonPath;
     private final Config config;
-    @Getter
-    private final GuiRegistry guiRegistry = new GuiRegistry();
-    private Supplier<ConfigBuilder> guiBuilder = ConfigBuilder::create;
+    private final GuiBuilder guiBuilder;
 
     ConfigManager(String modID) {
-        this.modID = modID;
         jsonPath = Paths.get(FabricLoader.getInstance().getConfigDir().toString(), modID + ".json");
         config = new Config(load());
+        guiBuilder = new GuiBuilder(modID, config);
     }
 
     private JsonElement load() {
@@ -70,64 +48,16 @@ public class ConfigManager {
         }
     }
 
-    private String buildTranslationKey(String... ids) {
-        return joinIDs("config", modID, joinIDs(ids));
-    }
-
-    public void setCustomGuiBuilder(Supplier<ConfigBuilder> guiBuilder) {
-        this.guiBuilder = guiBuilder;
+    public GuiRegistry getGuiRegistry() {
+        return guiBuilder.getRegistry();
     }
 
-    //TODO: Rename to buildScreen(Screen parent)
-    public Screen getConfigScreen(Screen parentScreen) {
-        ConfigBuilder builder = guiBuilder.get();
-        builder.setParentScreen(parentScreen)
-                .setTitle(new TranslatableText(buildTranslationKey("title")))
-                .setSavingRunnable(this::save);
-        config.forEach((categoryID, category) -> {
-            me.shedaniel.clothconfig2.api.ConfigCategory configCategory = builder.getOrCreateCategory(new TranslatableText(buildTranslationKey(categoryID)));
-            for (AbstractConfigListEntry entry : buildCollection(categoryID, category)) {
-                configCategory.addEntry(entry);
-            }
-        });
-        return builder.build();
+    public void setCustomGuiSupplier(Supplier<ConfigBuilder> supplier) {
+        guiBuilder.setSupplier(supplier);
     }
 
-    private List<AbstractConfigListEntry> buildCollection(String parentID, Collection collection) {
-        List<AbstractConfigListEntry> list = new ArrayList<>();
-        collection.getEntries().forEach((entryID, entry) -> {
-            String translationKey = entry.getCustomTranslationKey() != null ? buildTranslationKey(entry.getCustomTranslationKey()) : buildTranslationKey(parentID, entryID);
-            String[] tooltipKeys = entry.getCustomTooltipKeys();
-            if (tooltipKeys != null) {
-                tooltipKeys = Arrays.stream(tooltipKeys).map(this::buildTranslationKey).toArray(String[]::new);
-            } else {
-                String defaultTooltipKey = joinIDs(translationKey, "tooltip");
-                if (I18n.hasTranslation(defaultTooltipKey)) {
-                    tooltipKeys = new String[] {defaultTooltipKey};
-                } else {
-                    for(int i = 0;; i++) {
-                        String key = joinIDs(defaultTooltipKey, String.valueOf(i));
-                        if(I18n.hasTranslation(key)) {
-                            if (tooltipKeys == null) {
-                                tooltipKeys = new String[]{key};
-                            } else {
-                                tooltipKeys = ArrayUtils.add(tooltipKeys, key);
-                            }
-                        } else {
-                            break;
-                        }
-                    }
-                }
-            }
-            list.add(guiRegistry.getProvider(entry).build(new TranslatableText(translationKey), entry.getField(), entry.getValue(), entry.getDefaultValue(), tooltipKeys != null ? Optional.of(Arrays.stream(tooltipKeys).map(TranslatableText::new).toArray(Text[]::new)) : Optional.empty(), entry.getExtras(), entry::setValue));
-        });
-        collection.getCollections().forEach((subcategoryID, c) -> {
-            String id = joinIDs(parentID, subcategoryID);
-            SubCategoryBuilder subBuilder = ConfigEntryBuilder.create().startSubCategory(new TranslatableText(buildTranslationKey(id)));
-            subBuilder.addAll(buildCollection(id, c));
-            list.add(subBuilder.build());
-        });
-        return list;
+    public Screen buildScreen(Screen parent) {
+        return guiBuilder.buildScreen(parent, this::save);
     }
 
     public void save() {

+ 24 - 0
src/main/java/me/lortseam/completeconfig/ConfigMap.java

@@ -1,7 +1,31 @@
 package me.lortseam.completeconfig;
 
+import org.apache.commons.lang3.StringUtils;
+
 import java.util.LinkedHashMap;
+import java.util.Map;
 
 public abstract class ConfigMap<T> extends LinkedHashMap<String, T> {
 
+    @Override
+    public T put(String id, T value) {
+        check(id, value);
+        return super.put(id, value);
+    }
+
+    @Override
+    public void putAll(Map<? extends String, ? extends T> m) {
+        m.forEach(this::check);
+        super.putAll(m);
+    }
+
+    private void check(String id, T value) {
+        if (StringUtils.isBlank(id)) {
+            throw new IllegalArgumentException("ID of type " + value.getClass().getSimpleName() + " must not be null or blank");
+        }
+        if (containsKey(id)) {
+            throw new UnsupportedOperationException("A value of type " + value.getClass().getSimpleName() + " with ID " + id + " already exists in the corresponding structure");
+        }
+    }
+
 }

+ 0 - 1
src/main/java/me/lortseam/completeconfig/api/ConfigEntryContainer.java

@@ -30,7 +30,6 @@ public interface ConfigEntryContainer {
         Class<? extends ConfigEntryContainer> clazz = getClass();
         while (clazz != null) {
             classes.add(clazz);
-            //TODO: Testen: Entries aus Superklassen die nicht ConfigEntryContainer implementieren sollten nun nicht mehr beachtet werden
             if (!ConfigEntryContainer.class.isAssignableFrom(clazz.getSuperclass())) {
                 break;
             }

+ 0 - 4
src/main/java/me/lortseam/completeconfig/collection/Collection.java

@@ -24,10 +24,6 @@ public class Collection {
     }
 
     private void fill(ConfigEntryContainer container) {
-        //TODO
-        /*if (!findEntries(config, container.getClass()).isEmpty()) {
-            throw new UnsupportedOperationException("An instance of " + container.getClass() + " is already registered");
-        }*/
         entries.fill(container);
         List<ConfigEntryContainer> containers = new ArrayList<>();
         for (Class<? extends ConfigEntryContainer> clazz : container.getClasses()) {

+ 5 - 10
src/main/java/me/lortseam/completeconfig/collection/CollectionMap.java

@@ -2,23 +2,18 @@ package me.lortseam.completeconfig.collection;
 
 import me.lortseam.completeconfig.ConfigMap;
 import me.lortseam.completeconfig.api.ConfigCategory;
-import me.lortseam.completeconfig.exception.IllegalReturnValueException;
-import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 public class CollectionMap extends ConfigMap<Collection> {
 
+    private static final Logger LOGGER = LogManager.getLogger();
+
     protected void fill(ConfigCategory category) {
         String categoryID = category.getConfigCategoryID();
-        if (StringUtils.isBlank(categoryID)) {
-            throw new IllegalReturnValueException("Category ID of " + category.getClass() + " must not be null or blank");
-        }
-        if (containsKey(categoryID)) {
-            throw new IllegalStateException("Duplicate category ID found: " + categoryID);
-        }
         Collection collection = new Collection(category);
         if (collection.getEntries().isEmpty() && collection.getCollections().isEmpty()) {
-            //TODO
-            //LOGGER.warn()
+            LOGGER.warn("[CompleteConfig] Category " + categoryID + " is empty!");
             return;
         }
         put(categoryID, collection);

+ 3 - 11
src/main/java/me/lortseam/completeconfig/collection/EntryMap.java

@@ -5,16 +5,15 @@ import me.lortseam.completeconfig.ConfigMap;
 import me.lortseam.completeconfig.api.ConfigEntry;
 import me.lortseam.completeconfig.api.ConfigEntryContainer;
 import me.lortseam.completeconfig.api.ConfigEntryListener;
-import me.lortseam.completeconfig.entry.Bounds;
 import me.lortseam.completeconfig.entry.Entry;
 import me.lortseam.completeconfig.exception.IllegalAnnotationParameterException;
 import me.lortseam.completeconfig.exception.IllegalAnnotationTargetException;
 import me.lortseam.completeconfig.exception.IllegalModifierException;
-import me.lortseam.completeconfig.listener.Listener;
 import org.apache.commons.lang3.StringUtils;
 
 import java.lang.reflect.Modifier;
-import java.util.*;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
 
 public class EntryMap extends ConfigMap<Entry> {
 
@@ -126,20 +125,13 @@ public class EntryMap extends ConfigMap<Entry> {
                     ConfigEntry.Bounded.Double bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Double.class);
                     entry.getExtras().setBounds(bounds.min(), bounds.max());
                 }
-                //TODO
-                /*if (guiRegistry.getProvider(entry) == null) {
-                    throw new UnsupportedOperationException("Could not find gui provider for field type " + entry.getType());
-                }*/
                 clazzEntries.put(field.getName(), entry);
             });
-            /*if (!listeners.isEmpty()) {
-                Listener listener = listeners.iterator().next();
-                throw new IllegalAnnotationParameterException("Could not find field " + listener.getFieldName() + " in " + clazz + " requested by listener method " + listener.getMethod());
-            }*/
             //TODO: Quite hacky solution to sort the entries (superclasses first)
             clazzEntries.putAll(containerEntries);
             containerEntries = clazzEntries;
         }
+        putAll(containerEntries);
     }
 
 }

+ 6 - 21
src/main/java/me/lortseam/completeconfig/entry/Entry.java

@@ -20,10 +20,9 @@ public class Entry<T> {
 
     public static Entry<?> of(String fieldName, Class<? extends ConfigEntryContainer> parentClass) {
         try {
-            Field field = parentClass.getField(fieldName);
+            Field field = parentClass.getDeclaredField(fieldName);
             return of(field);
         } catch (NoSuchFieldException e) {
-            //TODO
             throw new RuntimeException(e);
         }
     }
@@ -63,17 +62,6 @@ public class Entry<T> {
     @Setter
     private boolean forceUpdate;
 
-    /*private Entry(Field field, Class<T> type, ConfigEntryContainer parentObject, String customTranslationKey, String[] customTooltipKeys, Extras<T> extras, boolean forceUpdate) {
-        this.field = field;
-        this.type = type;
-        this.parentObject = parentObject;
-        this.customTranslationKey = customTranslationKey;
-        this.customTooltipKeys = customTooltipKeys;
-        this.extras = extras;
-        this.forceUpdate = forceUpdate;
-        defaultValue = getValue();
-    }*/
-
     public T getValue() {
         if (updateValueIfNecessary()) {
             return getValue();
@@ -122,19 +110,16 @@ public class Entry<T> {
                 throw new RuntimeException(e);
             }
         }
-        if (!listeners.isEmpty()) {
-            for (Listener listener : listeners) {
-                try {
-                    listener.method.invoke(listener.parentObject, value);
-                } catch (IllegalAccessException | InvocationTargetException e) {
-                    throw new RuntimeException(e);
-                }
+        for (Listener listener : listeners) {
+            try {
+                listener.method.invoke(listener.parentObject, value);
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new RuntimeException(e);
             }
         }
     }
 
     public void addListener(Method method, ConfigEntryContainer parentObject) {
-
         listeners.add(new Listener(method, parentObject));
     }
 

+ 4 - 2
src/main/java/me/lortseam/completeconfig/entry/Extras.java

@@ -3,7 +3,7 @@ package me.lortseam.completeconfig.entry;
 import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
-import lombok.Setter;
+import org.apache.commons.lang3.ClassUtils;
 
 @RequiredArgsConstructor(access = AccessLevel.PACKAGE)
 public class Extras<T> {
@@ -13,7 +13,9 @@ public class Extras<T> {
     private Bounds<T> bounds;
 
     public <N extends Number> void setBounds(N min, N max) {
-        //TODO: Check for correct min/max type
+        if (!ClassUtils.isAssignable(entry.getType(), min.getClass()) || !ClassUtils.isAssignable(entry.getType(), max.getClass())) {
+            throw new IllegalArgumentException();
+        }
         bounds = new Bounds<>((T) min, (T) max);
     }
 

+ 0 - 9
src/main/java/me/lortseam/completeconfig/exception/IllegalReturnValueException.java

@@ -1,9 +0,0 @@
-package me.lortseam.completeconfig.exception;
-
-public class IllegalReturnValueException extends RuntimeException {
-
-    public IllegalReturnValueException(String message) {
-        super(message);
-    }
-
-}

+ 99 - 0
src/main/java/me/lortseam/completeconfig/gui/GuiBuilder.java

@@ -0,0 +1,99 @@
+package me.lortseam.completeconfig.gui;
+
+import lombok.Getter;
+import lombok.Setter;
+import me.lortseam.completeconfig.CompleteConfig;
+import me.lortseam.completeconfig.Config;
+import me.lortseam.completeconfig.collection.Collection;
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import me.shedaniel.clothconfig2.api.ConfigBuilder;
+import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
+import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.resource.language.I18n;
+import net.minecraft.text.Text;
+import net.minecraft.text.TranslatableText;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+public class GuiBuilder {
+
+    private static String joinIDs(String... ids) {
+        return String.join(".", ids);
+    }
+
+    private final String modID;
+    private final Config config;
+    @Setter
+    private Supplier<ConfigBuilder> supplier = ConfigBuilder::create;
+    @Getter
+    private final GuiRegistry registry = new GuiRegistry();
+
+    public GuiBuilder(String modID, Config config) {
+        this.modID = modID;
+        this.config = config;
+    }
+
+    private String buildTranslationKey(String... ids) {
+        return joinIDs("config", modID, joinIDs(ids));
+    }
+
+    public Screen buildScreen(Screen parent, Runnable savingRunnable) {
+        ConfigBuilder builder = supplier.get();
+        builder.setParentScreen(parent)
+                .setTitle(new TranslatableText(buildTranslationKey("title")))
+                .setSavingRunnable(savingRunnable);
+        config.forEach((categoryID, category) -> {
+            me.shedaniel.clothconfig2.api.ConfigCategory configCategory = builder.getOrCreateCategory(new TranslatableText(buildTranslationKey(categoryID)));
+            for (AbstractConfigListEntry entry : buildCollection(categoryID, category)) {
+                configCategory.addEntry(entry);
+            }
+        });
+        return builder.build();
+    }
+
+    private List<AbstractConfigListEntry> buildCollection(String parentID, Collection collection) {
+        List<AbstractConfigListEntry> list = new ArrayList<>();
+        collection.getEntries().forEach((entryID, entry) -> {
+            String translationKey = entry.getCustomTranslationKey() != null ? buildTranslationKey(entry.getCustomTranslationKey()) : buildTranslationKey(parentID, entryID);
+            String[] tooltipKeys = entry.getCustomTooltipKeys();
+            if (tooltipKeys != null) {
+                tooltipKeys = Arrays.stream(tooltipKeys).map(this::buildTranslationKey).toArray(String[]::new);
+            } else {
+                String defaultTooltipKey = joinIDs(translationKey, "tooltip");
+                if (I18n.hasTranslation(defaultTooltipKey)) {
+                    tooltipKeys = new String[] {defaultTooltipKey};
+                } else {
+                    for(int i = 0;; i++) {
+                        String key = joinIDs(defaultTooltipKey, String.valueOf(i));
+                        if(I18n.hasTranslation(key)) {
+                            if (tooltipKeys == null) {
+                                tooltipKeys = new String[]{key};
+                            } else {
+                                tooltipKeys = ArrayUtils.add(tooltipKeys, key);
+                            }
+                        } else {
+                            break;
+                        }
+                    }
+                }
+            }
+            list.add(((Optional<GuiProvider>) CompleteConfig.getManager(modID).get().getGuiRegistry().getProvider(entry)).orElseGet(() -> {
+                throw new UnsupportedOperationException("Could not find gui provider for field type " + entry.getType());
+            }).build(new TranslatableText(translationKey), entry.getField(), entry.getValue(), entry.getDefaultValue(), tooltipKeys != null ? Optional.of(Arrays.stream(tooltipKeys).map(TranslatableText::new).toArray(Text[]::new)) : Optional.empty(), entry.getExtras(), entry::setValue));
+        });
+        collection.getCollections().forEach((subcategoryID, c) -> {
+            String id = joinIDs(parentID, subcategoryID);
+            SubCategoryBuilder subBuilder = ConfigEntryBuilder.create().startSubCategory(new TranslatableText(buildTranslationKey(id)));
+            subBuilder.addAll(buildCollection(id, c));
+            list.add(subBuilder.build());
+        });
+        return list;
+    }
+    
+}

+ 5 - 8
src/main/java/me/lortseam/completeconfig/gui/GuiRegistry.java

@@ -6,16 +6,13 @@ import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
 import net.minecraft.text.TranslatableText;
 import org.apache.commons.lang3.ArrayUtils;
 
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.Map;
+import java.util.*;
 
 public class GuiRegistry {
 
     private final LinkedHashMap<GuiProviderPredicate, GuiProvider> guiProviders = new LinkedHashMap<>();
 
-    public GuiRegistry() {
+    GuiRegistry() {
         registerDefaultProviders();
     }
 
@@ -142,15 +139,15 @@ public class GuiRegistry {
         );
     }
 
-    public <T> GuiProvider<T> getProvider(Entry<T> entry) {
+    <T> Optional<GuiProvider<T>> getProvider(Entry<T> entry) {
         Iterator<Map.Entry<GuiProviderPredicate, GuiProvider>> iter = new LinkedList<>(guiProviders.entrySet()).descendingIterator();
         while (iter.hasNext()) {
             Map.Entry<GuiProviderPredicate, GuiProvider> mapEntry = iter.next();
             if (mapEntry.getKey().test(entry.getField(), entry.getExtras())) {
-                return mapEntry.getValue();
+                return Optional.of(mapEntry.getValue());
             }
         }
-        return null;
+        return Optional.empty();
     }
 
 }