瀏覽代碼

Introducing extensions

Lortseam 4 年之前
父節點
當前提交
dea25d7a6b

+ 39 - 0
src/main/java/me/lortseam/completeconfig/CompleteConfig.java

@@ -0,0 +1,39 @@
+package me.lortseam.completeconfig;
+
+import me.lortseam.completeconfig.extensions.CompleteConfigExtension;
+import me.lortseam.completeconfig.extensions.clothbasicmath.ClothBasicMathExtension;
+import net.fabricmc.api.ModInitializer;
+import net.fabricmc.loader.api.FabricLoader;
+import net.fabricmc.loader.api.entrypoint.EntrypointContainer;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.*;
+
+public final class CompleteConfig implements ModInitializer {
+
+    private static final Logger LOGGER = LogManager.getLogger();
+    private static final Map<String, CompleteConfigExtension> extensions = new HashMap<>();
+
+    public static void registerExternalExtension(String modID, Class<? extends CompleteConfigExtension> extensionClass) {
+        if(!FabricLoader.getInstance().isModLoaded(modID)) return;
+        try {
+            extensions.put(modID, extensionClass.newInstance());
+        } catch (InstantiationException | IllegalAccessException e) {
+            LOGGER.warn("[CompleteConfig] Failed to instantiate extension " + modID, e);
+        }
+    }
+
+    public static Collection<CompleteConfigExtension> getExtensions() {
+        return Collections.unmodifiableCollection(extensions.values());
+    }
+
+    @Override
+    public void onInitialize() {
+        registerExternalExtension("cloth-basic-math", ClothBasicMathExtension.class);
+        for (EntrypointContainer<CompleteConfigExtension> entrypoint : FabricLoader.getInstance().getEntrypointContainers("completeconfig-extension", CompleteConfigExtension.class)) {
+            extensions.put(entrypoint.getProvider().getMetadata().getId(), entrypoint.getEntrypoint());
+        }
+    }
+
+}

+ 0 - 62
src/main/java/me/lortseam/completeconfig/ModManager.java

@@ -1,62 +0,0 @@
-package me.lortseam.completeconfig;
-
-import lombok.Getter;
-import me.lortseam.completeconfig.util.TypeUtils;
-import net.fabricmc.loader.api.FabricLoader;
-import net.fabricmc.loader.api.ModContainer;
-import net.fabricmc.loader.api.metadata.ModMetadata;
-import org.spongepowered.configurate.serialize.TypeSerializerCollection;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-public final class ModManager {
-
-    private static final Map<String, ModManager> controllers = new HashMap<>();
-
-    /**
-     * Gets the mod manager of a loaded mod.
-     *
-     * @param id the ID of the mod
-     * @return the corresponding mod controller
-     */
-    public static ModManager of(String id) {
-        ModMetadata metadata = FabricLoader.getInstance().getModContainer(id).map(ModContainer::getMetadata).orElseThrow(() -> {
-            return new IllegalArgumentException("Mod " + id + " is not loaded");
-        });
-        if (!controllers.containsKey(metadata.getId())) {
-            ModManager controller = new ModManager(metadata);
-            controllers.put(metadata.getId(), controller);
-            return controller;
-        }
-        return controllers.get(metadata.getId());
-    }
-
-    @Getter
-    private final ModMetadata metadata;
-    @Getter
-    private TypeSerializerCollection typeSerializers;
-
-    private ModManager(ModMetadata metadata) {
-        this.metadata = metadata;
-    }
-
-    public String getID() {
-        return metadata.getId();
-    }
-
-    public String getName() {
-        return metadata.getName();
-    }
-
-    /**
-     * Registers custom type serializers, applied to all following mod configs.
-     *
-     * @param typeSerializers the type serializers
-     */
-    public void registerTypeSerializers(TypeSerializerCollection typeSerializers) {
-        this.typeSerializers = TypeUtils.mergeSerializers(this.typeSerializers, Objects.requireNonNull(typeSerializers));
-    }
-
-}

+ 6 - 3
src/main/java/me/lortseam/completeconfig/data/Config.java

@@ -1,13 +1,13 @@
 package me.lortseam.completeconfig.data;
 
 import me.lortseam.completeconfig.ConfigHandler;
-import me.lortseam.completeconfig.ModManager;
 import me.lortseam.completeconfig.api.ConfigGroup;
 import me.lortseam.completeconfig.data.text.TranslationIdentifier;
 import me.lortseam.completeconfig.gui.GuiBuilder;
 import me.lortseam.completeconfig.io.ConfigSource;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
+import net.fabricmc.loader.api.FabricLoader;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -24,6 +24,9 @@ public class Config extends CollectionMap {
      * @param modID the ID of the mod creating the config
      */
     public static Builder builder(String modID) {
+        if (!FabricLoader.getInstance().isModLoaded(Objects.requireNonNull(modID))) {
+            throw new IllegalArgumentException("Mod " + modID + " is not loaded");
+        }
         return new Builder(modID);
     }
 
@@ -63,7 +66,7 @@ public class Config extends CollectionMap {
         private GuiBuilder guiBuilder;
 
         private Builder(String modID) {
-            this.modID = Objects.requireNonNull(modID);
+            this.modID = modID;
         }
 
         /**
@@ -113,7 +116,7 @@ public class Config extends CollectionMap {
                 LOGGER.warn("[CompleteConfig] Mod " + modID + " tried to create an empty config!");
                 return null;
             }
-            return new ConfigHandler(new Config(new ConfigSource(ModManager.of(modID), branch), topLevelGroups), guiBuilder);
+            return new ConfigHandler(new Config(new ConfigSource(modID, branch), topLevelGroups), guiBuilder);
         }
 
     }

+ 8 - 4
src/main/java/me/lortseam/completeconfig/data/Entry.java

@@ -2,6 +2,7 @@ package me.lortseam.completeconfig.data;
 
 import com.google.common.collect.Lists;
 import lombok.Getter;
+import me.lortseam.completeconfig.CompleteConfig;
 import me.lortseam.completeconfig.api.ConfigEntry;
 import me.lortseam.completeconfig.api.ConfigEntryContainer;
 import me.lortseam.completeconfig.data.entry.EntryOrigin;
@@ -9,6 +10,7 @@ import me.lortseam.completeconfig.data.entry.Transformation;
 import me.lortseam.completeconfig.data.part.DataPart;
 import me.lortseam.completeconfig.data.text.TranslationIdentifier;
 import me.lortseam.completeconfig.exception.IllegalAnnotationParameterException;
+import me.lortseam.completeconfig.extensions.CompleteConfigExtension;
 import net.minecraft.text.Text;
 import net.minecraft.text.TextColor;
 import org.apache.commons.lang3.StringUtils;
@@ -50,6 +52,12 @@ public class Entry<T> extends EntryBase<T> implements DataPart {
     );
     private static final Map<Field, EntryBase> entries = new HashMap<>();
 
+    static {
+        CompleteConfig.getExtensions().stream().map(CompleteConfigExtension::getTransformations).filter(Objects::nonNull).forEach(extensionTransformations -> {
+            transformations.addAll(0, extensionTransformations);
+        });
+    }
+
     static EntryBase<?> of(String fieldName, Class<? extends ConfigEntryContainer> parentClass) {
         try {
             return of(parentClass.getDeclaredField(fieldName));
@@ -62,10 +70,6 @@ public class Entry<T> extends EntryBase<T> implements DataPart {
         return entries.computeIfAbsent(field, absentField -> new Draft<>(field));
     }
 
-    public static void registerTransformation(Transformation<?> transformation) {
-        transformations.add(0, transformation);
-    }
-
     private final ConfigEntryContainer parentObject;
     private String customID;
     @Getter

+ 23 - 0
src/main/java/me/lortseam/completeconfig/extensions/CompleteConfigExtension.java

@@ -0,0 +1,23 @@
+package me.lortseam.completeconfig.extensions;
+
+import me.lortseam.completeconfig.data.entry.Transformation;
+import me.lortseam.completeconfig.gui.cloth.extensions.CompleteConfigGuiExtension;
+import org.spongepowered.configurate.serialize.TypeSerializerCollection;
+
+import java.util.Collection;
+
+public interface CompleteConfigExtension {
+
+    default TypeSerializerCollection getTypeSerializers() {
+        return null;
+    }
+
+    default Collection<Transformation> getTransformations() {
+        return null;
+    }
+
+    default CompleteConfigGuiExtension gui() {
+        return null;
+    }
+
+}

+ 37 - 0
src/main/java/me/lortseam/completeconfig/extensions/clothbasicmath/ClothBasicMathExtension.java

@@ -0,0 +1,37 @@
+package me.lortseam.completeconfig.extensions.clothbasicmath;
+
+import com.google.common.collect.ImmutableList;
+import me.lortseam.completeconfig.data.ColorEntry;
+import me.lortseam.completeconfig.data.entry.Transformation;
+import me.lortseam.completeconfig.extensions.CompleteConfigExtension;
+import me.lortseam.completeconfig.gui.cloth.extensions.CompleteConfigGuiExtension;
+import me.lortseam.completeconfig.gui.cloth.extensions.clothbasicmath.ClothBasicMathGuiExtension;
+import me.shedaniel.math.Color;
+import org.spongepowered.configurate.serialize.TypeSerializerCollection;
+
+import java.util.Collection;
+
+public final class ClothBasicMathExtension implements CompleteConfigExtension {
+
+    private static final TypeSerializerCollection SERIALIZERS = TypeSerializerCollection.builder()
+            .registerExact(ColorSerializer.INSTANCE)
+            .build();
+
+    @Override
+    public TypeSerializerCollection getTypeSerializers() {
+        return SERIALIZERS;
+    }
+
+    @Override
+    public Collection<Transformation> getTransformations() {
+        return ImmutableList.of(
+                Transformation.ofType(Color.class, origin -> new ColorEntry<>(origin, true))
+        );
+    }
+
+    @Override
+    public CompleteConfigGuiExtension gui() {
+        return ClothBasicMathGuiExtension.INSTANCE;
+    }
+
+}

+ 32 - 0
src/main/java/me/lortseam/completeconfig/extensions/clothbasicmath/ColorSerializer.java

@@ -0,0 +1,32 @@
+package me.lortseam.completeconfig.extensions.clothbasicmath;
+
+import me.shedaniel.math.Color;
+import org.spongepowered.configurate.serialize.CoercionFailedException;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+
+import java.lang.reflect.Type;
+import java.util.function.Predicate;
+
+final class ColorSerializer extends ScalarSerializer<Color> {
+
+    static final ColorSerializer INSTANCE = new ColorSerializer();
+
+    private ColorSerializer() {
+        super(Color.class);
+    }
+
+    @Override
+    public Color deserialize(Type type, Object obj) throws SerializationException {
+        if (obj instanceof Integer) {
+            return Color.ofTransparent((Integer) obj);
+        }
+        throw new CoercionFailedException(type, obj, "TextColor");
+    }
+
+    @Override
+    protected Object serialize(Color item, Predicate<Class<?>> typeSupported) {
+        return item.getColor();
+    }
+
+}

+ 3 - 6
src/main/java/me/lortseam/completeconfig/gui/cloth/ClothGuiBuilder.java

@@ -1,7 +1,5 @@
 package me.lortseam.completeconfig.gui.cloth;
 
-import lombok.Getter;
-import me.lortseam.completeconfig.ModManager;
 import me.lortseam.completeconfig.data.Collection;
 import me.lortseam.completeconfig.data.Config;
 import me.lortseam.completeconfig.data.Entry;
@@ -14,6 +12,7 @@ import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
 import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
+import net.fabricmc.loader.api.FabricLoader;
 import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.text.TranslatableText;
 
@@ -25,8 +24,6 @@ import java.util.function.Supplier;
 public class ClothGuiBuilder implements GuiBuilder {
 
     private final Supplier<ConfigBuilder> supplier;
-    @Getter
-    private final GuiRegistry registry = new GuiRegistry();
 
     public ClothGuiBuilder(Supplier<ConfigBuilder> supplier) {
         this.supplier = supplier;
@@ -42,7 +39,7 @@ public class ClothGuiBuilder implements GuiBuilder {
                 .setParentScreen(parentScreen)
                 .setSavingRunnable(savingRunnable);
         TranslationIdentifier customTranslation = config.getTranslation().append("title");
-        builder.setTitle(customTranslation.exists() ? customTranslation.translate() : new TranslatableText("completeconfig.gui.defaultTitle", ModManager.of(config.getModID()).getName()));
+        builder.setTitle(customTranslation.exists() ? customTranslation.translate() : new TranslatableText("completeconfig.gui.defaultTitle", FabricLoader.getInstance().getModContainer(config.getModID()).get().getMetadata().getName()));
         for(Collection collection : config.values()) {
             ConfigCategory configCategory = builder.getOrCreateCategory(collection.getText());
             for (AbstractConfigListEntry<?> entry : buildCollection(collection)) {
@@ -55,7 +52,7 @@ public class ClothGuiBuilder implements GuiBuilder {
     private List<AbstractConfigListEntry> buildCollection(Collection collection) {
         List<AbstractConfigListEntry> collectionGui = new ArrayList<>();
         for (Entry entry : collection.getEntries().values()) {
-            collectionGui.add((registry.getProvider(entry)).orElseThrow(() -> {
+            collectionGui.add((GuiRegistry.getInstance().getProvider(entry)).orElseThrow(() -> {
                 return new UnsupportedOperationException("Could not find GUI provider for field " + entry.getField());
             }).build(entry));
         }

+ 13 - 6
src/main/java/me/lortseam/completeconfig/gui/cloth/GuiRegistry.java

@@ -2,10 +2,14 @@ package me.lortseam.completeconfig.gui.cloth;
 
 import com.google.common.collect.MoreCollectors;
 import com.google.common.reflect.TypeToken;
+import lombok.AccessLevel;
+import lombok.Getter;
+import me.lortseam.completeconfig.CompleteConfig;
 import me.lortseam.completeconfig.data.BoundedEntry;
 import me.lortseam.completeconfig.data.ColorEntry;
 import me.lortseam.completeconfig.data.Entry;
 import me.lortseam.completeconfig.data.EnumEntry;
+import me.lortseam.completeconfig.extensions.CompleteConfigExtension;
 import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
 import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
 import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder;
@@ -16,16 +20,16 @@ import net.minecraft.text.TextColor;
 import org.apache.commons.lang3.ArrayUtils;
 
 import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
 @Environment(EnvType.CLIENT)
 public final class GuiRegistry {
 
+    @Getter(AccessLevel.PACKAGE)
+    private static final GuiRegistry instance = new GuiRegistry();
+
     public static <T, A extends AbstractConfigListEntry> A build(Function<ConfigEntryBuilder, FieldBuilder<T, A>> builder, boolean requiresRestart) {
         FieldBuilder<T, A> fieldBuilder = builder.apply(ConfigEntryBuilder.create());
         fieldBuilder.requireRestart(requiresRestart);
@@ -34,8 +38,11 @@ public final class GuiRegistry {
 
     private final List<GuiProviderRegistration> registrations = new ArrayList<>();
 
-    GuiRegistry() {
+    private GuiRegistry() {
         registerDefaultProviders();
+        CompleteConfig.getExtensions().stream().map(CompleteConfigExtension::gui).filter(Objects::nonNull).forEach(guiExtension -> {
+            guiExtension.registerProviders(this);
+        });
     }
 
     public void registerProvider(GuiProvider<?> provider, Predicate<Entry<?>> predicate, Type... types) {
@@ -63,7 +70,7 @@ public final class GuiRegistry {
     }
 
     public void registerColorProvider(GuiProvider<? extends ColorEntry<?>> provider, boolean alphaModeSupported, Type... types) {
-        registerProvider(provider, entry -> entry instanceof ColorEntry<?> && (!((ColorEntry) entry).isAlphaMode() || alphaModeSupported), types);
+        registerProvider(provider, entry -> entry instanceof ColorEntry<?> && (!((ColorEntry<?>) entry).isAlphaMode() || alphaModeSupported), types);
     }
 
     private void registerDefaultProviders() {

+ 9 - 0
src/main/java/me/lortseam/completeconfig/gui/cloth/extensions/CompleteConfigGuiExtension.java

@@ -0,0 +1,9 @@
+package me.lortseam.completeconfig.gui.cloth.extensions;
+
+import me.lortseam.completeconfig.gui.cloth.GuiRegistry;
+
+public interface CompleteConfigGuiExtension {
+
+    void registerProviders(GuiRegistry registry);
+
+}

+ 28 - 0
src/main/java/me/lortseam/completeconfig/gui/cloth/extensions/clothbasicmath/ClothBasicMathGuiExtension.java

@@ -0,0 +1,28 @@
+package me.lortseam.completeconfig.gui.cloth.extensions.clothbasicmath;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import me.lortseam.completeconfig.data.ColorEntry;
+import me.lortseam.completeconfig.gui.cloth.GuiRegistry;
+import me.lortseam.completeconfig.gui.cloth.extensions.CompleteConfigGuiExtension;
+import me.shedaniel.math.Color;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ClothBasicMathGuiExtension implements CompleteConfigGuiExtension {
+
+    public static final ClothBasicMathGuiExtension INSTANCE = new ClothBasicMathGuiExtension();
+
+    @Override
+    public void registerProviders(GuiRegistry registry) {
+        registry.registerColorProvider((ColorEntry<Color> entry) -> GuiRegistry.build(
+                builder -> builder
+                        .startColorField(entry.getText(), entry.getValue())
+                        .setAlphaMode(entry.isAlphaMode())
+                        .setDefaultValue(entry.getDefaultValue().getColor())
+                        .setTooltip(entry.getTooltip())
+                        .setSaveConsumer2(entry::setValue),
+                entry.requiresRestart()
+        ), true, Color.class);
+    }
+
+}

+ 6 - 4
src/main/java/me/lortseam/completeconfig/io/ConfigSource.java

@@ -2,8 +2,9 @@ package me.lortseam.completeconfig.io;
 
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
-import me.lortseam.completeconfig.ModManager;
+import me.lortseam.completeconfig.CompleteConfig;
 import me.lortseam.completeconfig.data.Config;
+import me.lortseam.completeconfig.extensions.CompleteConfigExtension;
 import net.fabricmc.loader.api.FabricLoader;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.logging.log4j.LogManager;
@@ -17,6 +18,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Objects;
 import java.util.Set;
 
 @EqualsAndHashCode(onlyExplicitlyIncluded = true)
@@ -35,8 +37,8 @@ public final class ConfigSource {
     private final String[] branch;
     private final HoconConfigurationLoader loader;
 
-    public ConfigSource(ModManager mod, String[] branch) {
-        this.modID = mod.getID();
+    public ConfigSource(String modID, String[] branch) {
+        this.modID = modID;
         this.branch = branch;
         if (!sources.add(this)) {
             throw new IllegalArgumentException("A config of the mod " + modID + " with the specified branch " + Arrays.toString(branch) + " already exists!");
@@ -48,7 +50,7 @@ public final class ConfigSource {
                 .path(filePath)
                 .defaultOptions(options -> options.serializers(builder -> {
                     builder.registerAll(GLOBAL_TYPE_SERIALIZERS);
-                    builder.registerAll(mod.getTypeSerializers());
+                    CompleteConfig.getExtensions().stream().map(CompleteConfigExtension::getTypeSerializers).filter(Objects::nonNull).forEach(builder::registerAll);
                 }))
                 .build();
     }

+ 5 - 1
src/main/resources/fabric.mod.json

@@ -17,7 +17,11 @@
   "license": "Apache-2.0",
 
   "environment": "*",
-  "entrypoints": {},
+  "entrypoints": {
+    "main": [
+      "me.lortseam.completeconfig.CompleteConfig"
+    ]
+  },
   "depends": {
     "fabricloader": ">=0.9.0"
   },