浏览代码

Merge Auto Config + setup my maven

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 4 年之前
父节点
当前提交
d7db9700a7
共有 100 个文件被更改,包括 4003 次插入105 次删除
  1. 4 5
      .github/workflows/publish.yml
  2. 0 29
      .github/workflows/snapshot.yml
  3. 16 0
      HEADER
  4. 21 36
      build.gradle
  5. 16 0
      common/build.gradle
  6. 104 0
      common/src/main/java/me/shedaniel/autoconfig/AutoConfig.java
  7. 39 0
      common/src/main/java/me/shedaniel/autoconfig/ConfigData.java
  8. 47 0
      common/src/main/java/me/shedaniel/autoconfig/ConfigHolder.java
  9. 134 0
      common/src/main/java/me/shedaniel/autoconfig/ConfigManager.java
  10. 69 0
      common/src/main/java/me/shedaniel/autoconfig/annotation/Config.java
  11. 157 0
      common/src/main/java/me/shedaniel/autoconfig/annotation/ConfigEntry.java
  12. 66 0
      common/src/main/java/me/shedaniel/autoconfig/event/ConfigSerializeEvent.java
  13. 132 0
      common/src/main/java/me/shedaniel/autoconfig/example/ExampleConfig.java
  14. 59 0
      common/src/main/java/me/shedaniel/autoconfig/example/ExampleInits.java
  15. 162 0
      common/src/main/java/me/shedaniel/autoconfig/gui/ConfigScreenProvider.java
  16. 419 0
      common/src/main/java/me/shedaniel/autoconfig/gui/DefaultGuiProviders.java
  17. 140 0
      common/src/main/java/me/shedaniel/autoconfig/gui/DefaultGuiTransformers.java
  18. 69 0
      common/src/main/java/me/shedaniel/autoconfig/gui/registry/ComposedGuiRegistryAccess.java
  19. 54 0
      common/src/main/java/me/shedaniel/autoconfig/gui/registry/DefaultGuiRegistryAccess.java
  20. 174 0
      common/src/main/java/me/shedaniel/autoconfig/gui/registry/GuiRegistry.java
  21. 39 0
      common/src/main/java/me/shedaniel/autoconfig/gui/registry/api/GuiProvider.java
  22. 40 0
      common/src/main/java/me/shedaniel/autoconfig/gui/registry/api/GuiRegistryAccess.java
  23. 40 0
      common/src/main/java/me/shedaniel/autoconfig/gui/registry/api/GuiTransformer.java
  24. 44 0
      common/src/main/java/me/shedaniel/autoconfig/serializer/ConfigSerializer.java
  25. 50 0
      common/src/main/java/me/shedaniel/autoconfig/serializer/DummyConfigSerializer.java
  26. 94 0
      common/src/main/java/me/shedaniel/autoconfig/serializer/GsonConfigSerializer.java
  27. 87 0
      common/src/main/java/me/shedaniel/autoconfig/serializer/JanksonConfigSerializer.java
  28. 146 0
      common/src/main/java/me/shedaniel/autoconfig/serializer/PartitioningSerializer.java
  29. 86 0
      common/src/main/java/me/shedaniel/autoconfig/serializer/Toml4jConfigSerializer.java
  30. 84 0
      common/src/main/java/me/shedaniel/autoconfig/serializer/YamlConfigSerializer.java
  31. 98 0
      common/src/main/java/me/shedaniel/autoconfig/util/Utils.java
  32. 22 12
      common/src/main/java/me/shedaniel/clothconfig2/ClothConfigDemo.java
  33. 20 1
      common/src/main/java/me/shedaniel/clothconfig2/ClothConfigInitializer.java
  34. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigEntry.java
  35. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigListEntry.java
  36. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/ConfigBuilder.java
  37. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/ConfigCategory.java
  38. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/ConfigEntryBuilder.java
  39. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/ConfigScreen.java
  40. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/Expandable.java
  41. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/LazyResettable.java
  42. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/Modifier.java
  43. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/ModifierKeyCode.java
  44. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/QueuedTooltip.java
  45. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/ReferenceBuildingConfigScreen.java
  46. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/ReferenceProvider.java
  47. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/ScissorsHandler.java
  48. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/ScissorsScreen.java
  49. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/TabbedConfigScreen.java
  50. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/api/Tooltip.java
  51. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/AbstractConfigScreen.java
  52. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/AbstractTabbedConfigScreen.java
  53. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/ClothConfigScreen.java
  54. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/ClothConfigTabButton.java
  55. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/ClothRequiresRestartScreen.java
  56. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/GlobalizedClothConfigScreen.java
  57. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/AbstractListListEntry.java
  58. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/AbstractTextFieldListListEntry.java
  59. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BaseListCell.java
  60. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BaseListEntry.java
  61. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BooleanListEntry.java
  62. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/ColorEntry.java
  63. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/DoubleListEntry.java
  64. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/DoubleListListEntry.java
  65. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/DropdownBoxEntry.java
  66. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/EnumListEntry.java
  67. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/FloatListEntry.java
  68. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/FloatListListEntry.java
  69. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/IntegerListEntry.java
  70. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/IntegerListListEntry.java
  71. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/IntegerSliderEntry.java
  72. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/KeyCodeEntry.java
  73. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/LongListEntry.java
  74. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/LongListListEntry.java
  75. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/LongSliderEntry.java
  76. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/MultiElementListEntry.java
  77. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/NestedListListEntry.java
  78. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/SelectionListEntry.java
  79. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/StringListEntry.java
  80. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/StringListListEntry.java
  81. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/SubCategoryListEntry.java
  82. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TextFieldListEntry.java
  83. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TextListEntry.java
  84. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TooltipListEntry.java
  85. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/widget/ColorDisplayWidget.java
  86. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicElementListWidget.java
  87. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicEntryListWidget.java
  88. 17 22
      common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicNewSmoothScrollingEntryListWidget.java
  89. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/ConfigBuilderImpl.java
  90. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/ConfigCategoryImpl.java
  91. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/ConfigEntryBuilderImpl.java
  92. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/EasingMethod.java
  93. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/EasingMethods.java
  94. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/GameOptionsHooks.java
  95. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/KeyBindingHooks.java
  96. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/ModifierKeyCodeImpl.java
  97. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/ScissorsHandlerImpl.java
  98. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/builders/BooleanToggleBuilder.java
  99. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/builders/ColorFieldBuilder.java
  100. 19 0
      common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleFieldBuilder.java

+ 4 - 5
.github/workflows/publish.yml

@@ -7,7 +7,7 @@ on:
             - '**.properties'
             - '**.properties'
             - '**/src/**'
             - '**/src/**'
         branches:
         branches:
-            - "4.9"
+            - v4
 
 
 jobs:
 jobs:
     build:
     build:
@@ -18,11 +18,10 @@ jobs:
               uses: actions/setup-java@v1
               uses: actions/setup-java@v1
               with:
               with:
                   java-version: 1.8
                   java-version: 1.8
-            - name: Upload to Bintray
-              run: ./gradlew bintrayUpload curseforgePublish --stacktrace
+            - name: Upload to Maven
+              run: ./gradlew publish curseforgePublish --stacktrace
               if: |
               if: |
                   !contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.pull_request.title, '[ci skip]')
                   !contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.pull_request.title, '[ci skip]')
               env:
               env:
-                  BINTRAY_USER: shedaniel
-                  BINTRAY_KEY: ${{ secrets.BINTRAY_KEY }}
+                  MAVEN_PASS: ${{ secrets.MAVEN_PASS }}
                   curse_api_key: ${{ secrets.CURSE_API_KEY }}
                   curse_api_key: ${{ secrets.CURSE_API_KEY }}

+ 0 - 29
.github/workflows/snapshot.yml

@@ -1,29 +0,0 @@
-name: Snapshot Compile & Release
-
-on:
-    pull_request:
-        paths:
-            - '**.gradle'
-            - '**.properties'
-            - '**/src/**'
-        types: [ opened, synchronize, reopened ]
-
-jobs:
-    build:
-
-        runs-on: ubuntu-latest
-
-        steps:
-            - uses: actions/checkout@v1
-            - name: Set up JDK 1.8
-              uses: actions/setup-java@v1
-              with:
-                  java-version: 1.8
-            - name: Upload to Bintray
-              run: ./gradlew bintrayUpload --stacktrace
-              if: |
-                  !contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.pull_request.title, '[ci skip]')
-              env:
-                  BINTRAY_USER: shedaniel
-                  BINTRAY_KEY: ${{ secrets.BINTRAY_KEY }}
-                  PR_NUM: ${{github.event.number}}

+ 16 - 0
HEADER

@@ -0,0 +1,16 @@
+This file is part of Cloth Config.
+Copyright (C) ${year} ${name}
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 3 of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

+ 21 - 36
build.gradle

@@ -1,9 +1,9 @@
 plugins {
 plugins {
-    id "architectury-plugin" version "2.0.65"
-    id "forgified-fabric-loom" version "0.6.54" apply false
-    id 'com.jfrog.bintray' version '1.8.4'
-    id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
-    id 'maven-publish'
+    id "architectury-plugin" version "2.0.68"
+    id "forgified-fabric-loom" version "0.6.64" apply false
+    id "com.matthewprenger.cursegradle" version "1.4.0" apply false
+    id "maven-publish"
+    id "org.cadixdev.licenser" version "0.5.0" apply false
 }
 }
 
 
 architectury {
 architectury {
@@ -22,20 +22,12 @@ subprojects {
 allprojects {
 allprojects {
     apply plugin: 'java'
     apply plugin: 'java'
     apply plugin: 'architectury-plugin'
     apply plugin: 'architectury-plugin'
-
-    ext {
-        isSnapshot = System.getenv("PR_NUM") != null
-    }
+    apply plugin: 'org.cadixdev.licenser'
 
 
     def runNumber = (System.getenv("GITHUB_RUN_NUMBER") == null ? "9999" : System.getenv("GITHUB_RUN_NUMBER"))
     def runNumber = (System.getenv("GITHUB_RUN_NUMBER") == null ? "9999" : System.getenv("GITHUB_RUN_NUMBER"))
 
 
-    if (!ext.isSnapshot) {
-        version = rootProject.base_version + "." + runNumber
-        archivesBaseName = rootProject.archives_base_name
-    } else {
-        version = rootProject.base_version + "-PR." + System.getenv("PR_NUM") + "." + runNumber
-        archivesBaseName = rootProject.archives_base_name_snapshot
-    }
+    version = rootProject.base_version + "." + runNumber
+    archivesBaseName = rootProject.archives_base_name
 
 
     group = rootProject.maven_group
     group = rootProject.maven_group
 
 
@@ -51,27 +43,20 @@ allprojects {
         }
         }
     }
     }
 
 
-}
+    license {
+        header = rootProject.file("HEADER")
 
 
-bintray {
-    user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
-    key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_KEY')
-    publications = ["mavenCommon", "mavenFabric", "mavenForge"]
-    publish = true
-    pkg {
-        repo = "cloth-config-2"
-        name = "config-2"
-        userOrg = "shedaniel"
-        licenses = ["LPGL v3"]
-        version {
-            name = project.version
-            vcsTag = project.version
-            released = new Date()
-            desc = "Cloth Config API for Minecraft"
-            githubRepo = 'architectury/ClothConfig'
-            websiteUrl = 'https://github.com/architectury/ClothConfig'
-            issueTrackerUrl = 'https://github.com/architectury/ClothConfig/issues'
-            vcsUrl = 'https://github.com/architectury/ClothConfig.git'
+        ext {
+            name = "shedaniel"
+            year = "2020 - 2021"
         }
         }
+
+        include "**/*.java"
+        exclude "**/ScrollingContainer.java"
+
+        ignoreFailures = true
     }
     }
 }
 }
+
+task licenseFormatAll
+subprojects { licenseFormatAll.dependsOn("${path}:licenseFormat") }

+ 16 - 0
common/build.gradle

@@ -10,6 +10,10 @@ dependencies {
     modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
     modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
 
 
     implementation("me.shedaniel.cloth:basic-math:0.5.1")
     implementation("me.shedaniel.cloth:basic-math:0.5.1")
+
+    implementation("blue.endless:jankson:${rootProject.jankson_version}")
+    implementation("com.moandjiezana.toml:toml4j:${rootProject.toml4j_version}")
+    implementation("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
 }
 }
 
 
 architectury {
 architectury {
@@ -43,4 +47,16 @@ publishing {
             artifact javadocsJar
             artifact javadocsJar
         }
         }
     }
     }
+    
+    repositories {
+        if (System.getenv("MAVEN_PASS") != null) {
+            maven {
+                url = "https://deploy.shedaniel.me/"
+                credentials {
+                    username = "shedaniel"
+                    password = System.getenv("MAVEN_PASS")
+                }
+            }
+        }
+    }
 }
 }

+ 104 - 0
common/src/main/java/me/shedaniel/autoconfig/AutoConfig.java

@@ -0,0 +1,104 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig;
+
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.gui.ConfigScreenProvider;
+import me.shedaniel.autoconfig.gui.DefaultGuiProviders;
+import me.shedaniel.autoconfig.gui.DefaultGuiTransformers;
+import me.shedaniel.autoconfig.gui.registry.ComposedGuiRegistryAccess;
+import me.shedaniel.autoconfig.gui.registry.DefaultGuiRegistryAccess;
+import me.shedaniel.autoconfig.gui.registry.GuiRegistry;
+import me.shedaniel.autoconfig.serializer.ConfigSerializer;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.gui.screens.Screen;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+public class AutoConfig {
+    public static final String MOD_ID = "autoconfig1u";
+    
+    private static final Map<Class<? extends ConfigData>, ConfigHolder<?>> holders = new HashMap<>();
+    private static final Map<Class<? extends ConfigData>, GuiRegistry> guiRegistries = new HashMap<>();
+    
+    private AutoConfig() {
+    }
+    
+    public static <T extends ConfigData> ConfigHolder<T> register(
+            Class<T> configClass,
+            ConfigSerializer.Factory<T> serializerFactory
+    ) {
+        Objects.requireNonNull(configClass);
+        Objects.requireNonNull(serializerFactory);
+        
+        if (holders.containsKey(configClass)) {
+            throw new RuntimeException(String.format("Config '%s' already registered", configClass));
+        }
+        
+        Config definition = configClass.getAnnotation(Config.class);
+        
+        if (definition == null) {
+            throw new RuntimeException(String.format("No @Config annotation on %s!", configClass));
+        }
+        
+        ConfigSerializer<T> serializer = serializerFactory.create(definition, configClass);
+        ConfigManager<T> manager = new ConfigManager<>(definition, configClass, serializer);
+        holders.put(configClass, manager);
+        
+        return manager;
+    }
+    
+    public static <T extends ConfigData> ConfigHolder<T> getConfigHolder(Class<T> configClass) {
+        Objects.requireNonNull(configClass);
+        if (holders.containsKey(configClass)) {
+            return (ConfigHolder<T>) holders.get(configClass);
+        } else {
+            throw new RuntimeException(String.format("Config '%s' has not been registered", configClass));
+        }
+    }
+    
+    @Environment(EnvType.CLIENT)
+    public static <T extends ConfigData> GuiRegistry getGuiRegistry(Class<T> configClass) {
+        return guiRegistries.computeIfAbsent(configClass, n -> new GuiRegistry());
+    }
+    
+    @Environment(EnvType.CLIENT)
+    public static <T extends ConfigData> Supplier<Screen> getConfigScreen(Class<T> configClass, Screen parent) {
+        return new ConfigScreenProvider<>(
+                (ConfigManager<T>) AutoConfig.getConfigHolder(configClass),
+                new ComposedGuiRegistryAccess(
+                        getGuiRegistry(configClass),
+                        ClientOnly.defaultGuiRegistry,
+                        new DefaultGuiRegistryAccess()
+                ),
+                parent
+        );
+    }
+    
+    @Environment(EnvType.CLIENT)
+    private static class ClientOnly {
+        private static final GuiRegistry defaultGuiRegistry =
+                DefaultGuiTransformers.apply(DefaultGuiProviders.apply(new GuiRegistry()));
+    }
+}

+ 39 - 0
common/src/main/java/me/shedaniel/autoconfig/ConfigData.java

@@ -0,0 +1,39 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig;
+
+public interface ConfigData {
+    default void validatePostLoad() throws ValidationException {
+    }
+    
+    class ValidationException extends Exception {
+        public ValidationException(String message) {
+            super(message);
+        }
+        
+        public ValidationException(String message, Throwable cause) {
+            super(message, cause);
+        }
+        
+        public ValidationException(Throwable cause) {
+            super(cause);
+        }
+    }
+}

+ 47 - 0
common/src/main/java/me/shedaniel/autoconfig/ConfigHolder.java

@@ -0,0 +1,47 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig;
+
+import me.shedaniel.autoconfig.event.ConfigSerializeEvent;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.Supplier;
+
+@ApiStatus.NonExtendable
+public interface ConfigHolder<T extends ConfigData> extends Supplier<T> {
+    @NotNull
+    Class<T> getConfigClass();
+    
+    void save();
+    
+    boolean load();
+    
+    T getConfig();
+    
+    void registerSaveListener(ConfigSerializeEvent.Save<T> save);
+    
+    void registerLoadListener(ConfigSerializeEvent.Load<T> load);
+    
+    @Override
+    default T get() {
+        return getConfig();
+    }
+}

+ 134 - 0
common/src/main/java/me/shedaniel/autoconfig/ConfigManager.java

@@ -0,0 +1,134 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig;
+
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.event.ConfigSerializeEvent;
+import me.shedaniel.autoconfig.serializer.ConfigSerializer;
+import net.minecraft.world.InteractionResult;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@ApiStatus.Internal
+public class ConfigManager<T extends ConfigData> implements ConfigHolder<T> {
+    private final Logger logger;
+    private final Config definition;
+    private final Class<T> configClass;
+    private final ConfigSerializer<T> serializer;
+    
+    private final List<ConfigSerializeEvent.Save<T>> saveEvent = new ArrayList<>();
+    private final List<ConfigSerializeEvent.Load<T>> loadEvent = new ArrayList<>();
+    
+    private T config;
+    
+    ConfigManager(Config definition, Class<T> configClass, ConfigSerializer<T> serializer) {
+        logger = LogManager.getLogger();
+        
+        this.definition = definition;
+        this.configClass = configClass;
+        this.serializer = serializer;
+        
+        if (load()) {
+            save();
+        }
+    }
+    
+    public Config getDefinition() {
+        return definition;
+    }
+    
+    @Override
+    @NotNull
+    public Class<T> getConfigClass() {
+        return configClass;
+    }
+    
+    public ConfigSerializer<T> getSerializer() {
+        return serializer;
+    }
+    
+    @Override
+    public void save() {
+        for (ConfigSerializeEvent.Save<T> save : saveEvent) {
+            InteractionResult result = save.onSave(this, config);
+            if (result == InteractionResult.FAIL) {
+                return;
+            } else if (result != InteractionResult.PASS) {
+                break;
+            }
+        }
+        try {
+            serializer.serialize(config);
+        } catch (ConfigSerializer.SerializationException e) {
+            logger.error("Failed to save config '{}'", configClass, e);
+        }
+    }
+    
+    @Override
+    public boolean load() {
+        try {
+            T deserialized = serializer.deserialize();
+            
+            for (ConfigSerializeEvent.Load<T> load : loadEvent) {
+                InteractionResult result = load.onLoad(this, deserialized);
+                if (result == InteractionResult.FAIL) {
+                    config = serializer.createDefault();
+                    config.validatePostLoad();
+                    return false;
+                } else if (result != InteractionResult.PASS) {
+                    break;
+                }
+            }
+            
+            config = deserialized;
+            config.validatePostLoad();
+            return true;
+        } catch (ConfigSerializer.SerializationException | ConfigData.ValidationException e) {
+            logger.error("Failed to load config '{}', using default!", configClass, e);
+            config = serializer.createDefault();
+            try {
+                config.validatePostLoad();
+            } catch (ConfigData.ValidationException v) {
+                throw new RuntimeException("result of createDefault() was invalid!", v);
+            }
+            return false;
+        }
+    }
+    
+    @Override
+    public T getConfig() {
+        return config;
+    }
+    
+    @Override
+    public void registerLoadListener(ConfigSerializeEvent.Load<T> load) {
+        this.loadEvent.add(load);
+    }
+    
+    @Override
+    public void registerSaveListener(ConfigSerializeEvent.Save<T> save) {
+        this.saveEvent.add(save);
+    }
+}

+ 69 - 0
common/src/main/java/me/shedaniel/autoconfig/annotation/Config.java

@@ -0,0 +1,69 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * Attach this to your config POJO.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Config {
+    
+    String name();
+    
+    class Gui {
+        private Gui() {
+        }
+        
+        /**
+         * Sets the background in the config GUI
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.TYPE)
+        public @interface Background {
+            String TRANSPARENT = "cloth-config2:transparent";
+            
+            String value();
+        }
+        
+        /**
+         * Sets the background of a specific category in the config GUI
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.TYPE)
+        @Repeatable(CategoryBackgrounds.class)
+        public @interface CategoryBackground {
+            String category();
+            
+            String background();
+        }
+        
+        /**
+         * Do not use.
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.TYPE)
+        public @interface CategoryBackgrounds {
+            @SuppressWarnings("unused") CategoryBackground[] value();
+        }
+    }
+}

+ 157 - 0
common/src/main/java/me/shedaniel/autoconfig/annotation/ConfigEntry.java

@@ -0,0 +1,157 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+public class ConfigEntry {
+    
+    private ConfigEntry() {
+    }
+    
+    /**
+     * Sets the category name of the config entry. Categories are created in order.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public @interface Category {
+        String value();
+    }
+    
+    /**
+     * Applies to int and long fields.
+     * Sets the GUI to a slider.
+     * In a future version it will enforce bounds at deserialization.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public @interface BoundedDiscrete {
+        long min() default 0;
+        
+        long max();
+    }
+    
+    /**
+     * Applies to int fields.
+     * Sets the GUI to a color picker.
+     * In a future version it will enforce bounds at deserialization.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public @interface ColorPicker {
+        boolean allowAlpha() default false;
+    }
+
+//    /**
+//     * Applies to float and double fields.
+//     * In a future version it will enforce bounds at deserialization.
+//     */
+//    @Retention(RetentionPolicy.RUNTIME)
+//    @Target(ElementType.FIELD)
+//    public @interface BoundedFloating {
+//        double min() default 0;
+//
+//        double max();
+//    }
+    
+    public static class Gui {
+        private Gui() {
+        }
+        
+        /**
+         * Removes the field from the config GUI.
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.FIELD)
+        public @interface Excluded {
+        }
+        
+        /**
+         * Applies to objects.
+         * Adds GUI entries for the field's inner fields at the same level as this field.
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.FIELD)
+        public @interface TransitiveObject {
+        }
+        
+        /**
+         * Applies to objects.
+         * Adds GUI entries for the field's inner fields in a collapsible section.
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.FIELD)
+        public @interface CollapsibleObject {
+            boolean startExpanded() default false;
+        }
+        
+        /**
+         * Applies a tooltip to list entries that support it, defined in your lang file.
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.FIELD)
+        public @interface Tooltip {
+            int count() default 1;
+        }
+        
+        /**
+         * Applies no tooltip to list entries that support it, defined in your lang file.
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.FIELD)
+        public @interface NoTooltip {
+            
+        }
+        
+        /**
+         * Applies a section of text right before this entry, defined in your lang file.
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.FIELD)
+        public @interface PrefixText {
+        }
+        
+        /**
+         * Requires restart if the field is modified.
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.FIELD)
+        public @interface RequiresRestart {
+            boolean value() default true;
+        }
+        
+        /**
+         * Defines how an enum is handled
+         */
+        @Retention(RetentionPolicy.RUNTIME)
+        @Target(ElementType.FIELD)
+        public @interface EnumHandler {
+            EnumDisplayOption option() default EnumDisplayOption.DROPDOWN;
+            
+            enum EnumDisplayOption {
+                DROPDOWN,
+                BUTTON
+            }
+        }
+    }
+}

+ 66 - 0
common/src/main/java/me/shedaniel/autoconfig/event/ConfigSerializeEvent.java

@@ -0,0 +1,66 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.event;
+
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.ConfigHolder;
+import net.minecraft.world.InteractionResult;
+
+public final class ConfigSerializeEvent {
+    private ConfigSerializeEvent() {}
+    
+    @FunctionalInterface
+    public interface Save<T extends ConfigData> {
+        /**
+         * Callback that is called before the config manager serializes its config values
+         * This is called on initialization or when the config screen is saved.
+         * <p>
+         * The callback uses an ActionResult to determine further actions
+         * - SUCCESS stops any extra processing and uses the default behavior along
+         * - PASS falls back to further processing and defaults to SUCCESS if no other listeners are available
+         * - FAIL cancels further processing (the equivalent of returning the method)
+         * <p>
+         * Also avoid calling {@link ConfigHolder#save()} in this callback, as it
+         * will result in an exception
+         * <p>
+         */
+        InteractionResult onSave(ConfigHolder<T> manager, T data);
+    }
+    
+    @FunctionalInterface
+    public interface Load<T extends ConfigData> {
+        /**
+         * Callback that is called after the config manager deserializes its config values
+         * This is called on initialization or when the config screen is loaded.
+         * <p>
+         * This is also called in {@link ConfigHolder#load()} if the config file was edited
+         * manually.
+         * <p>
+         * The callback uses an ActionResult to determine further actions
+         * - SUCCESS stops any extra processing and uses the default behavior along
+         * - PASS falls back to further processing and defaults to SUCCESS if no other listeners are available
+         * - FAIL cancels further processing (the equivalent of returning the method)
+         * <p>
+         * Also avoid calling {@link ConfigHolder#load()} in this callback, as it
+         * will result in an exception
+         */
+        InteractionResult onLoad(ConfigHolder<T> manager, T newData);
+    }
+}

+ 132 - 0
common/src/main/java/me/shedaniel/autoconfig/example/ExampleConfig.java

@@ -0,0 +1,132 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.example;
+
+import blue.endless.jankson.Comment;
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.annotation.ConfigEntry;
+import me.shedaniel.autoconfig.serializer.PartitioningSerializer;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.Arrays;
+import java.util.List;
+
+@SuppressWarnings({"unused", "FieldMayBeFinal"})
+@ApiStatus.Internal
+@Config(name = "autoconfig1u_example")
+@Config.Gui.Background("minecraft:textures/block/oak_planks.png")
+@Config.Gui.CategoryBackground(category = "b", background = "minecraft:textures/block/stone.png")
+public class ExampleConfig extends PartitioningSerializer.GlobalData {
+    @ConfigEntry.Category("a")
+    @ConfigEntry.Gui.TransitiveObject
+    public ModuleA moduleA = new ModuleA();
+    
+    @ConfigEntry.Category("a")
+    @ConfigEntry.Gui.TransitiveObject
+    public Empty empty = new Empty();
+    
+    @ConfigEntry.Category("b")
+    @ConfigEntry.Gui.TransitiveObject
+    public ModuleB moduleB = new ModuleB();
+    
+    enum ExampleEnum {
+        FOO,
+        BAR,
+        BAZ
+    }
+    
+    @Config(name = "module_a")
+    public static class ModuleA implements ConfigData {
+        @ConfigEntry.Gui.PrefixText
+        public boolean aBoolean = true;
+        
+        @ConfigEntry.Gui.Tooltip(count = 2)
+        public ExampleEnum anEnum = ExampleEnum.FOO;
+        
+        @ConfigEntry.Gui.Tooltip(count = 2)
+        @ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
+        public ExampleEnum anEnumWithButton = ExampleEnum.FOO;
+        
+        @Comment("This tooltip was automatically applied from a Jankson @Comment")
+        public String aString = "hello";
+        
+        @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
+        public PairOfIntPairs anObject = new PairOfIntPairs(new PairOfInts(), new PairOfInts(3, 4));
+    
+        public List<Integer> list = Arrays.asList(1, 2, 3);
+    
+        public List<PairOfInts> complexList = Arrays.asList(new PairOfInts(0, 1), new PairOfInts(3, 7));
+    }
+    
+    @Config(name = "module_b")
+    public static class ModuleB implements ConfigData {
+        @ConfigEntry.BoundedDiscrete(min = -1000, max = 2000)
+        public int intSlider = 500;
+        
+        @ConfigEntry.BoundedDiscrete(min = -1000, max = 2000)
+        public Long longSlider = 500L;
+        
+        @ConfigEntry.Gui.TransitiveObject
+        public PairOfIntPairs anObject = new PairOfIntPairs(new PairOfInts(), new PairOfInts(3, 4));
+        
+        @ConfigEntry.Gui.Excluded
+        public List<PairOfInts> aList = Arrays.asList(new PairOfInts(), new PairOfInts(3, 4));
+        
+        @ConfigEntry.ColorPicker
+        public int color = 0xFFFFFF;
+    }
+    
+    @Config(name = "empty")
+    public static class Empty implements ConfigData {
+        
+    }
+    
+    public static class PairOfInts {
+        public int foo;
+        public int bar;
+    
+        public PairOfInts() {
+            this(1, 2);
+        }
+    
+        public PairOfInts(int foo, int bar) {
+            this.foo = foo;
+            this.bar = bar;
+        }
+    }
+    
+    public static class PairOfIntPairs {
+        @ConfigEntry.Gui.CollapsibleObject()
+        public PairOfInts first;
+        
+        @ConfigEntry.Gui.CollapsibleObject()
+        public PairOfInts second;
+    
+        public PairOfIntPairs() {
+            this(new PairOfInts(), new PairOfInts());
+        }
+    
+        public PairOfIntPairs(PairOfInts first, PairOfInts second) {
+            this.first = first;
+            this.second = second;
+        }
+    }
+}

+ 59 - 0
common/src/main/java/me/shedaniel/autoconfig/example/ExampleInits.java

@@ -0,0 +1,59 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.example;
+
+import me.shedaniel.autoconfig.AutoConfig;
+import me.shedaniel.autoconfig.ConfigHolder;
+import me.shedaniel.autoconfig.serializer.DummyConfigSerializer;
+import me.shedaniel.autoconfig.serializer.PartitioningSerializer;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.world.InteractionResult;
+import org.jetbrains.annotations.ApiStatus;
+
+@ApiStatus.Internal
+public class ExampleInits {
+    public static void exampleCommonInit() {
+        // how to register a config:
+        ConfigHolder<ExampleConfig> holder = AutoConfig.register(
+                ExampleConfig.class,
+                PartitioningSerializer.wrap(DummyConfigSerializer::new)
+        );
+        
+        // how to read a config:
+        holder.getConfig();
+        // or (please cache this value, and listen to load to re-cache)
+        AutoConfig.getConfigHolder(ExampleConfig.class).getConfig();
+        // this event allows you to change or register specific listeners
+        // for when the config has changed
+        AutoConfig.getConfigHolder(ExampleConfig.class).registerSaveListener((manager, data) -> {
+            return InteractionResult.SUCCESS;
+        });
+        AutoConfig.getConfigHolder(ExampleConfig.class).registerLoadListener((manager, newData) -> {
+            return InteractionResult.SUCCESS;
+        });
+    }
+    
+    @Environment(EnvType.CLIENT)
+    public static void exampleClientInit() {
+        // how to get the gui registry for custom gui handlers
+        AutoConfig.getGuiRegistry(ExampleConfig.class);
+    }
+}

+ 162 - 0
common/src/main/java/me/shedaniel/autoconfig/gui/ConfigScreenProvider.java

@@ -0,0 +1,162 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.gui;
+
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.ConfigManager;
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.annotation.ConfigEntry;
+import me.shedaniel.autoconfig.gui.registry.api.GuiRegistryAccess;
+import me.shedaniel.clothconfig2.api.ConfigBuilder;
+import me.shedaniel.clothconfig2.api.ConfigCategory;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.TranslatableComponent;
+import net.minecraft.resources.ResourceLocation;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import static java.util.stream.Collectors.*;
+
+@Environment(EnvType.CLIENT)
+public class ConfigScreenProvider<T extends ConfigData> implements Supplier<Screen> {
+    
+    private static final ResourceLocation TRANSPARENT_BACKGROUND = new ResourceLocation(Config.Gui.Background.TRANSPARENT);
+    
+    private final ConfigManager<T> manager;
+    private final GuiRegistryAccess registry;
+    private final Screen parent;
+    private Function<ConfigManager<T>, String> i13nFunction = manager -> String.format("text.autoconfig.%s", manager.getDefinition().name());
+    private Function<ConfigBuilder, Screen> buildFunction = ConfigBuilder::build;
+    private BiFunction<String, Field, String> optionFunction = (baseI13n, field) -> String.format("%s.option.%s", baseI13n, field.getName());
+    private BiFunction<String, String, String> categoryFunction = (baseI13n, categoryName) -> String.format("%s.category.%s", baseI13n, categoryName);
+    
+    public ConfigScreenProvider(
+            ConfigManager<T> manager,
+            GuiRegistryAccess registry,
+            Screen parent
+    ) {
+        this.manager = manager;
+        this.registry = registry;
+        this.parent = parent;
+    }
+    
+    @Deprecated
+    public void setI13nFunction(Function<ConfigManager<T>, String> i13nFunction) {
+        this.i13nFunction = i13nFunction;
+    }
+    
+    @Deprecated
+    public void setBuildFunction(Function<ConfigBuilder, Screen> buildFunction) {
+        this.buildFunction = buildFunction;
+    }
+    
+    @Deprecated
+    public void setCategoryFunction(BiFunction<String, String, String> categoryFunction) {
+        this.categoryFunction = categoryFunction;
+    }
+    
+    @Deprecated
+    public void setOptionFunction(BiFunction<String, Field, String> optionFunction) {
+        this.optionFunction = optionFunction;
+    }
+    
+    @Override
+    public Screen get() {
+        T config = manager.getConfig();
+        T defaults = manager.getSerializer().createDefault();
+        
+        String i13n = i13nFunction.apply(manager);
+        
+        ConfigBuilder builder = ConfigBuilder.create().setParentScreen(parent).setTitle(new TranslatableComponent(String.format("%s.title", i13n))).setSavingRunnable(manager::save);
+        
+        Class<T> configClass = manager.getConfigClass();
+        
+        if (configClass.isAnnotationPresent(Config.Gui.Background.class)) {
+            String bg = configClass.getAnnotation(Config.Gui.Background.class).value();
+            ResourceLocation bgId = ResourceLocation.tryParse(bg);
+            if (TRANSPARENT_BACKGROUND.equals(bgId))
+                builder.transparentBackground();
+            else
+                builder.setDefaultBackgroundTexture(bgId);
+        }
+        
+        Map<String, ResourceLocation> categoryBackgrounds =
+                Arrays.stream(configClass.getAnnotationsByType(Config.Gui.CategoryBackground.class))
+                        .collect(
+                                toMap(
+                                        Config.Gui.CategoryBackground::category,
+                                        ann -> new ResourceLocation(ann.background())
+                                )
+                        );
+        
+        Arrays.stream(configClass.getDeclaredFields())
+                .collect(
+                        groupingBy(
+                                field -> getOrCreateCategoryForField(field, builder, categoryBackgrounds, i13n),
+                                LinkedHashMap::new,
+                                toList()
+                        )
+                )
+                .forEach(
+                        (key, value) -> value.forEach(
+                                field -> {
+                                    String optionI13n = optionFunction.apply(i13n, field);
+                                    registry.getAndTransform(optionI13n, field, config, defaults, registry)
+                                            .forEach(key::addEntry);
+                                }
+                        )
+                );
+        
+        return buildFunction.apply(builder);
+    }
+    
+    private ConfigCategory getOrCreateCategoryForField(
+            Field field,
+            ConfigBuilder screenBuilder,
+            Map<String, ResourceLocation> backgroundMap,
+            String baseI13n
+    ) {
+        String categoryName = "default";
+        
+        if (field.isAnnotationPresent(ConfigEntry.Category.class))
+            categoryName = field.getAnnotation(ConfigEntry.Category.class).value();
+        
+        Component categoryKey = new TranslatableComponent(categoryFunction.apply(baseI13n, categoryName));
+        
+        if (!screenBuilder.hasCategory(categoryKey)) {
+            ConfigCategory category = screenBuilder.getOrCreateCategory(categoryKey);
+            if (backgroundMap.containsKey(categoryName)) {
+                category.setCategoryBackground(backgroundMap.get(categoryName));
+            }
+            return category;
+        }
+        
+        return screenBuilder.getOrCreateCategory(categoryKey);
+    }
+}

+ 419 - 0
common/src/main/java/me/shedaniel/autoconfig/gui/DefaultGuiProviders.java

@@ -0,0 +1,419 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.gui;
+
+import com.google.common.collect.Lists;
+import me.shedaniel.autoconfig.annotation.ConfigEntry;
+import me.shedaniel.autoconfig.gui.registry.GuiRegistry;
+import me.shedaniel.autoconfig.gui.registry.api.GuiRegistryAccess;
+import me.shedaniel.autoconfig.util.Utils;
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
+import me.shedaniel.clothconfig2.gui.entries.MultiElementListEntry;
+import me.shedaniel.clothconfig2.gui.entries.NestedListListEntry;
+import me.shedaniel.clothconfig2.gui.entries.SelectionListEntry;
+import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.resources.language.I18n;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.TextComponent;
+import net.minecraft.network.chat.TranslatableComponent;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.*;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static me.shedaniel.autoconfig.util.Utils.getUnsafely;
+import static me.shedaniel.autoconfig.util.Utils.setUnsafely;
+
+@Environment(EnvType.CLIENT)
+public class DefaultGuiProviders {
+    
+    private static final ConfigEntryBuilder ENTRY_BUILDER = ConfigEntryBuilder.create();
+    private static final Function<Enum<?>, Component> DEFAULT_NAME_PROVIDER = t -> new TranslatableComponent(t instanceof SelectionListEntry.Translatable ? ((SelectionListEntry.Translatable) t).getKey() : t.toString());
+    
+    private DefaultGuiProviders() {
+    }
+    
+    public static GuiRegistry apply(GuiRegistry registry) {
+        registry.registerAnnotationProvider(
+                (i13n, field, config, defaults, guiProvider) -> Collections.emptyList(),
+                ConfigEntry.Gui.Excluded.class
+        );
+        
+        registry.registerAnnotationProvider(
+                (i13n, field, config, defaults, guiProvider) -> {
+                    ConfigEntry.BoundedDiscrete bounds
+                            = field.getAnnotation(ConfigEntry.BoundedDiscrete.class);
+                    
+                    return Collections.singletonList(
+                            ENTRY_BUILDER.startIntSlider(
+                                    new TranslatableComponent(i13n),
+                                    getUnsafely(field, config, 0),
+                                    (int) bounds.min(),
+                                    (int) bounds.max()
+                            )
+                                    .setDefaultValue(() -> getUnsafely(field, defaults))
+                                    .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                    .build()
+                    );
+                },
+                field -> field.getType() == int.class || field.getType() == Integer.class,
+                ConfigEntry.BoundedDiscrete.class
+        );
+        
+        registry.registerAnnotationProvider(
+                (i13n, field, config, defaults, guiProvider) -> {
+                    ConfigEntry.BoundedDiscrete bounds
+                            = field.getAnnotation(ConfigEntry.BoundedDiscrete.class);
+                    
+                    return Collections.singletonList(
+                            ENTRY_BUILDER.startLongSlider(
+                                    new TranslatableComponent(i13n),
+                                    getUnsafely(field, config, 0L),
+                                    bounds.min(),
+                                    bounds.max()
+                            )
+                                    .setDefaultValue(() -> getUnsafely(field, defaults))
+                                    .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                    .build()
+                    );
+                },
+                field -> field.getType() == long.class || field.getType() == Long.class,
+                ConfigEntry.BoundedDiscrete.class
+        );
+        
+        registry.registerAnnotationProvider(
+                (i13n, field, config, defaults, guiProvider) -> {
+                    ConfigEntry.ColorPicker colorPicker
+                            = field.getAnnotation(ConfigEntry.ColorPicker.class);
+                    
+                    return Collections.singletonList(
+                            ENTRY_BUILDER.startColorField(
+                                    new TranslatableComponent(i13n),
+                                    getUnsafely(field, config, 0)
+                            )
+                                    .setAlphaMode(colorPicker.allowAlpha())
+                                    .setDefaultValue(() -> getUnsafely(field, defaults))
+                                    .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                    .build()
+                    );
+                },
+                field -> field.getType() == int.class || field.getType() == Integer.class,
+                ConfigEntry.ColorPicker.class
+        );
+        
+        registry.registerAnnotationProvider(
+                DefaultGuiProviders::getChildren,
+                field -> !field.getType().isPrimitive(),
+                ConfigEntry.Gui.TransitiveObject.class
+        );
+        
+        registry.registerAnnotationProvider(
+                (i13n, field, config, defaults, guiProvider) -> Collections.singletonList(
+                        ENTRY_BUILDER.startSubCategory(
+                                new TranslatableComponent(i13n),
+                                getChildren(i13n, field, config, defaults, guiProvider)
+                        )
+                                .setExpanded(field.getAnnotation(ConfigEntry.Gui.CollapsibleObject.class).startExpanded())
+                                .build()
+                ),
+                field -> !field.getType().isPrimitive(),
+                ConfigEntry.Gui.CollapsibleObject.class
+        );
+        
+        registry.registerPredicateProvider(
+                (i13n, field, config, defaults, guiProvider) -> {
+                    Object[] enumConstants = field.getType().getEnumConstants();
+                    Enum[] enums = new Enum[enumConstants.length];
+                    for (int i = 0; i < enumConstants.length; i++) {
+                        enums[i] = (Enum) enumConstants[i];
+                    }
+                    return Collections.singletonList(
+                            ENTRY_BUILDER.startSelector(
+                                    new TranslatableComponent(i13n),
+                                    enums,
+                                    getUnsafely(field, config, getUnsafely(field, defaults))
+                            )
+                                    .setDefaultValue(() -> getUnsafely(field, defaults))
+                                    .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                    .build()
+                    );
+                },
+                field -> field.getType().isEnum() && field.isAnnotationPresent(ConfigEntry.Gui.EnumHandler.class) && field.getAnnotation(ConfigEntry.Gui.EnumHandler.class).option() == ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON
+        );
+        
+        //noinspection unchecked
+        registry.registerPredicateProvider(
+                (i13n, field, config, defaults, guiProvider) -> {
+                    List<Enum<?>> enums = Arrays.asList(((Class<? extends Enum<?>>) field.getType()).getEnumConstants());
+                    return Collections.singletonList(
+                            ENTRY_BUILDER.startDropdownMenu(
+                                    new TranslatableComponent(i13n),
+                                    DropdownMenuBuilder.TopCellElementBuilder.of(
+                                            getUnsafely(field, config, getUnsafely(field, defaults)),
+                                            str -> {
+                                                String s = new TextComponent(str).getString();
+                                                for (Enum<?> constant : enums) {
+                                                    if (DEFAULT_NAME_PROVIDER.apply(constant).getString().equals(s)) {
+                                                        return constant;
+                                                    }
+                                                }
+                                                return null;
+                                            },
+                                            DEFAULT_NAME_PROVIDER
+                                    ),
+                                    DropdownMenuBuilder.CellCreatorBuilder.of(DEFAULT_NAME_PROVIDER)
+                            )
+                                    .setSelections(enums)
+                                    .setDefaultValue(() -> getUnsafely(field, defaults))
+                                    .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                    .build()
+                    );
+                },
+                field -> field.getType().isEnum()
+        );
+        
+        registry.registerPredicateProvider((i13n, field, config, defaults, registry1) -> Collections.singletonList(
+                ENTRY_BUILDER.startIntList(new TranslatableComponent(i13n), getUnsafely(field, config))
+                        .setDefaultValue(() -> getUnsafely(field, defaults))
+                        .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                        .build()
+        ), isListOfType(Integer.class));
+        
+        registry.registerPredicateProvider((i13n, field, config, defaults, registry1) -> Collections.singletonList(
+                ENTRY_BUILDER.startLongList(new TranslatableComponent(i13n), getUnsafely(field, config))
+                        .setDefaultValue(() -> getUnsafely(field, defaults))
+                        .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                        .build()
+        ), isListOfType(Long.class));
+        
+        registry.registerPredicateProvider((i13n, field, config, defaults, registry1) -> Collections.singletonList(
+                ENTRY_BUILDER.startFloatList(new TranslatableComponent(i13n), getUnsafely(field, config))
+                        .setDefaultValue(() -> getUnsafely(field, defaults))
+                        .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                        .build()
+        ), isListOfType(Float.class));
+        
+        registry.registerPredicateProvider((i13n, field, config, defaults, registry1) -> Collections.singletonList(
+                ENTRY_BUILDER.startDoubleList(new TranslatableComponent(i13n), getUnsafely(field, config))
+                        .setDefaultValue(() -> getUnsafely(field, defaults))
+                        .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                        .build()
+        ), isListOfType(Double.class));
+        
+        registry.registerPredicateProvider((i13n, field, config, defaults, registry1) -> Collections.singletonList(
+                ENTRY_BUILDER.startStrList(new TranslatableComponent(i13n), getUnsafely(field, config))
+                        .setDefaultValue(() -> getUnsafely(field, defaults))
+                        .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                        .build()
+        ), isListOfType(String.class));
+        
+        registry.registerPredicateProvider((i13n, field, config, defaults, registry1) -> {
+            List<Object> configValue = getUnsafely(field, config);
+            
+            Class<?> fieldTypeParam = (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
+            
+            Object defaultElemValue = Utils.constructUnsafely(fieldTypeParam);
+            
+            String remainingI13n = i13n.substring(0, i13n.indexOf(".option") + ".option".length());
+            String classI13n = String.format("%s.%s", remainingI13n, fieldTypeParam.getSimpleName());
+            
+            return Collections.singletonList(
+                    new NestedListListEntry<Object, MultiElementListEntry<Object>>(
+                            new TranslatableComponent(i13n),
+                            configValue,
+                            false,
+                            null,
+                            abstractConfigListEntries -> {
+                            },
+                            () -> getUnsafely(field, defaults),
+                            ENTRY_BUILDER.getResetButtonKey(),
+                            true,
+                            true,
+                            (elem, nestedListListEntry) -> {
+                                if (elem == null) {
+                                    Object newDefaultElemValue = Utils.constructUnsafely(fieldTypeParam);
+                                    return new MultiElementListEntry<>(new TranslatableComponent(classI13n), newDefaultElemValue, (List) getChildren(classI13n, fieldTypeParam, newDefaultElemValue, defaultElemValue, registry1), true);
+                                } else
+                                    return new MultiElementListEntry<>(new TranslatableComponent(classI13n), elem, (List) getChildren(classI13n, fieldTypeParam, elem, defaultElemValue, registry1), true);
+                            }
+                    )
+            );
+        }, isNotListOfType(Integer.class, Long.class, Float.class, Double.class, String.class));
+        
+        registry.registerTypeProvider(
+                (i13n, field, config, defaults, guiProvider) -> Collections.singletonList(
+                        ENTRY_BUILDER.startBooleanToggle(
+                                new TranslatableComponent(i13n),
+                                getUnsafely(field, config, false)
+                        )
+                                .setDefaultValue(() -> getUnsafely(field, defaults))
+                                .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                .setYesNoTextSupplier(bool -> {
+                                    String key = i13n + ".boolean." + bool;
+                                    String translate = I18n.get(key);
+                                    if (translate.equals(key))
+                                        return new TranslatableComponent("text.cloth-config.boolean.value." + bool);
+                                    return new TextComponent(translate);
+                                })
+                                .build()
+                ),
+                boolean.class, Boolean.class
+        );
+        
+        registry.registerTypeProvider(
+                (i13n, field, config, defaults, guiProvider) -> Collections.singletonList(
+                        ENTRY_BUILDER.startIntField(
+                                new TranslatableComponent(i13n),
+                                getUnsafely(field, config, 0)
+                        )
+                                .setDefaultValue(() -> getUnsafely(field, defaults))
+                                .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                .build()
+                ),
+                int.class, Integer.class
+        );
+        
+        registry.registerTypeProvider(
+                (i13n, field, config, defaults, guiProvider) -> Collections.singletonList(
+                        ENTRY_BUILDER.startIntList(
+                                new TranslatableComponent(i13n),
+                                Lists.newArrayList(getUnsafely(field, config, new Integer[0]))
+                        )
+                                .setDefaultValue(() -> getUnsafely(field, defaults))
+                                .setSaveConsumer(newValue -> setUnsafely(field, config, newValue.toArray(new Integer[0])))
+                                .build()
+                ),
+                Integer[].class
+        );
+        
+        registry.registerTypeProvider(
+                (i13n, field, config, defaults, guiProvider) -> Collections.singletonList(
+                        ENTRY_BUILDER.startLongField(
+                                new TranslatableComponent(i13n),
+                                getUnsafely(field, config, 0L)
+                        )
+                                .setDefaultValue(() -> getUnsafely(field, defaults))
+                                .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                .build()
+                ),
+                long.class, Long.class
+        );
+        
+        registry.registerTypeProvider(
+                (i13n, field, config, defaults, guiProvider) -> Collections.singletonList(
+                        ENTRY_BUILDER.startFloatField(
+                                new TranslatableComponent(i13n),
+                                getUnsafely(field, config, 0f)
+                        )
+                                .setDefaultValue(() -> getUnsafely(field, defaults))
+                                .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                .build()
+                ),
+                float.class, Float.class
+        );
+        
+        registry.registerTypeProvider(
+                (i13n, field, config, defaults, guiProvider) -> Collections.singletonList(
+                        ENTRY_BUILDER.startDoubleField(
+                                new TranslatableComponent(i13n),
+                                getUnsafely(field, config, 0.0)
+                        )
+                                .setDefaultValue(() -> getUnsafely(field, defaults))
+                                .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                .build()
+                ),
+                double.class, Double.class
+        );
+        
+        registry.registerTypeProvider(
+                (i13n, field, config, defaults, guiProvider) -> Collections.singletonList(
+                        ENTRY_BUILDER.startStrField(
+                                new TranslatableComponent(i13n),
+                                getUnsafely(field, config, "")
+                        )
+                                .setDefaultValue(() -> getUnsafely(field, defaults))
+                                .setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
+                                .build()
+                ),
+                String.class
+        );
+        
+        return registry;
+    }
+    
+    private static List<AbstractConfigListEntry> getChildren(String i13n, Field field, Object config, Object defaults, GuiRegistryAccess guiProvider) {
+        return getChildren(i13n, field.getType(), getUnsafely(field, config), getUnsafely(field, defaults), guiProvider);
+    }
+    
+    private static List<AbstractConfigListEntry> getChildren(String i13n, Class<?> fieldType, Object iConfig, Object iDefaults, GuiRegistryAccess guiProvider) {
+        return Arrays.stream(fieldType.getDeclaredFields())
+                .map(
+                        iField -> {
+                            String iI13n = String.format("%s.%s", i13n, iField.getName());
+                            return guiProvider.getAndTransform(iI13n, iField, iConfig, iDefaults, guiProvider);
+                        }
+                )
+                .filter(Objects::nonNull)
+                .flatMap(Collection::stream)
+                .collect(Collectors.toList());
+    }
+    
+    /**
+     * Returns a predicate that tests if the field is a list containing some particular {@link Type}s, i.e. {@code List<Integer>}.
+     *
+     * @param types the types to check for in the list's parameter
+     * @return {@code true} if the field is a list containing the provided type, {@code false} otherwise
+     */
+    private static Predicate<Field> isListOfType(Type... types) {
+        return field -> {
+            if (List.class.isAssignableFrom(field.getType()) && field.getGenericType() instanceof ParameterizedType) {
+                Type[] args = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
+                return args.length == 1 && Stream.of(types).anyMatch(type -> Objects.equals(args[0], type));
+            } else {
+                return false;
+            }
+        };
+    }
+    
+    /**
+     * Returns a predicate that tests if the field is a list <i>not</i> containing any particular {@link Type}s, i.e. anything that isn't a {@code List<Integer>}.
+     *
+     * @param types the types to check for in the list's parameter
+     * @return {@code true} if the field is a list <i>not</i> containing any of the provided types, {@code false} otherwise
+     */
+    private static Predicate<Field> isNotListOfType(Type... types) {
+        return field -> {
+            if (List.class.isAssignableFrom(field.getType()) && field.getGenericType() instanceof ParameterizedType) {
+                Type[] args = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
+                return args.length == 1 && Stream.of(types).noneMatch(type -> Objects.equals(args[0], type));
+            } else {
+                return false;
+            }
+        };
+    }
+}

+ 140 - 0
common/src/main/java/me/shedaniel/autoconfig/gui/DefaultGuiTransformers.java

@@ -0,0 +1,140 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.gui;
+
+import blue.endless.jankson.Comment;
+import me.shedaniel.autoconfig.annotation.ConfigEntry;
+import me.shedaniel.autoconfig.gui.registry.GuiRegistry;
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
+import me.shedaniel.clothconfig2.gui.entries.TextListEntry;
+import me.shedaniel.clothconfig2.gui.entries.TooltipListEntry;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.TextComponent;
+import net.minecraft.network.chat.TranslatableComponent;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+@Environment(EnvType.CLIENT)
+public class DefaultGuiTransformers {
+    
+    private static final ConfigEntryBuilder ENTRY_BUILDER = ConfigEntryBuilder.create();
+    
+    private DefaultGuiTransformers() {
+    }
+    
+    public static GuiRegistry apply(GuiRegistry registry) {
+        
+        registry.registerAnnotationTransformer(
+                (guis, i13n, field, config, defaults, guiProvider) -> guis.stream()
+                        .peek(gui -> {
+                            if (!(gui instanceof TextListEntry)) {
+                                ConfigEntry.Gui.Tooltip tooltip = field.getAnnotation(ConfigEntry.Gui.Tooltip.class);
+                                if (tooltip.count() == 0) {
+                                    tryRemoveTooltip(gui);
+                                } else if (tooltip.count() == 1) {
+                                    tryApplyTooltip(
+                                            gui,
+                                            new Component[]{
+                                                    new TranslatableComponent(String.format("%s.%s", i13n, "@Tooltip"))
+                                            }
+                                    );
+                                } else {
+                                    tryApplyTooltip(
+                                            gui, IntStream.range(0, tooltip.count()).boxed()
+                                                    .map(i -> String.format("%s.%s[%d]", i13n, "@Tooltip", i))
+                                                    .map(TranslatableComponent::new)
+                                                    .toArray(Component[]::new)
+                                    );
+                                }
+                            }
+                        })
+                        .collect(Collectors.toList()),
+                ConfigEntry.Gui.Tooltip.class
+        );
+        
+        registry.registerAnnotationTransformer(
+                (guis, i13n, field, config, defaults, guiProvider) -> guis.stream()
+                        .peek(gui -> {
+                            if (!(gui instanceof TextListEntry)) {
+                                Comment tooltip = field.getAnnotation(Comment.class);
+                                Component[] text = new Component[]{new TextComponent(tooltip.value())};
+                                tryApplyTooltip(gui, text);
+                            }
+                        })
+                        .collect(Collectors.toList()),
+                field -> !field.isAnnotationPresent(ConfigEntry.Gui.Tooltip.class),
+                Comment.class
+        );
+        
+        registry.registerAnnotationTransformer(
+                (guis, i13n, field, config, defaults, guiProvider) -> guis.stream()
+                        .peek(gui -> {
+                            if (!(gui instanceof TextListEntry)) {
+                                tryRemoveTooltip(gui);
+                            }
+                        })
+                        .collect(Collectors.toList()),
+                ConfigEntry.Gui.NoTooltip.class
+        );
+        
+        registry.registerAnnotationTransformer(
+                (guis, i13n, field, config, defaults, guiProvider) -> {
+                    ArrayList<AbstractConfigListEntry> ret = new ArrayList<>(guis);
+                    String text = String.format("%s.%s", i13n, "@PrefixText");
+                    ret.add(0, ENTRY_BUILDER.startTextDescription(new TranslatableComponent(text)).build());
+                    return Collections.unmodifiableList(ret);
+                },
+                ConfigEntry.Gui.PrefixText.class
+        );
+        
+        registry.registerAnnotationTransformer(
+                (guis, i13n, field, config, defaults, guiProvider) -> {
+                    for (AbstractConfigListEntry gui : guis) {
+                        gui.setRequiresRestart(field.getAnnotation(ConfigEntry.Gui.RequiresRestart.class).value());
+                    }
+                    return guis;
+                },
+                ConfigEntry.Gui.RequiresRestart.class
+        );
+        
+        return registry;
+    }
+    
+    private static void tryApplyTooltip(AbstractConfigListEntry gui, Component[] text) {
+        if (gui instanceof TooltipListEntry) {
+            TooltipListEntry tooltipGui = (TooltipListEntry) gui;
+            tooltipGui.setTooltipSupplier(() -> Optional.of(text));
+        }
+    }
+    
+    private static void tryRemoveTooltip(AbstractConfigListEntry gui) {
+        if (gui instanceof TooltipListEntry) {
+            TooltipListEntry tooltipGui = (TooltipListEntry) gui;
+            tooltipGui.setTooltipSupplier(() -> Optional.empty());
+        }
+    }
+}

+ 69 - 0
common/src/main/java/me/shedaniel/autoconfig/gui/registry/ComposedGuiRegistryAccess.java

@@ -0,0 +1,69 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.gui.registry;
+
+import me.shedaniel.autoconfig.gui.registry.api.GuiRegistryAccess;
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+@Environment(EnvType.CLIENT)
+public class ComposedGuiRegistryAccess implements GuiRegistryAccess {
+    
+    private List<GuiRegistryAccess> children;
+    
+    public ComposedGuiRegistryAccess(GuiRegistryAccess... children) {
+        this.children = Arrays.asList(children);
+    }
+    
+    @Override
+    public List<AbstractConfigListEntry> get(
+            String i13n,
+            Field field,
+            Object config,
+            Object defaults,
+            GuiRegistryAccess registry) {
+        return children.stream()
+                .map(child -> child.get(i13n, field, config, defaults, registry))
+                .filter(Objects::nonNull)
+                .findFirst()
+                .orElseThrow(() -> new RuntimeException("No ConfigGuiProvider match!"));
+    }
+    
+    @Override
+    public List<AbstractConfigListEntry> transform(
+            List<AbstractConfigListEntry> guis,
+            String i13n,
+            Field field,
+            Object config,
+            Object defaults,
+            GuiRegistryAccess registry
+    ) {
+        for (GuiRegistryAccess child : children) {
+            guis = child.transform(guis, i13n, field, config, defaults, registry);
+        }
+        return guis;
+    }
+}

+ 54 - 0
common/src/main/java/me/shedaniel/autoconfig/gui/registry/DefaultGuiRegistryAccess.java

@@ -0,0 +1,54 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.gui.registry;
+
+import me.shedaniel.autoconfig.gui.registry.api.GuiRegistryAccess;
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import org.apache.logging.log4j.LogManager;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.List;
+
+public class DefaultGuiRegistryAccess implements GuiRegistryAccess {
+    @Override
+    public List<AbstractConfigListEntry> get(
+            String i13n,
+            Field field,
+            Object config,
+            Object defaults,
+            GuiRegistryAccess registry
+    ) {
+        LogManager.getLogger().error("No GUI provider registered for field '{}'!", field);
+        return Collections.emptyList();
+    }
+    
+    @Override
+    public List<AbstractConfigListEntry> transform(
+            List<AbstractConfigListEntry> guis,
+            String i13n,
+            Field field,
+            Object config,
+            Object defaults,
+            GuiRegistryAccess registry
+    ) {
+        return guis;
+    }
+}

+ 174 - 0
common/src/main/java/me/shedaniel/autoconfig/gui/registry/GuiRegistry.java

@@ -0,0 +1,174 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.gui.registry;
+
+import me.shedaniel.autoconfig.gui.registry.api.GuiProvider;
+import me.shedaniel.autoconfig.gui.registry.api.GuiRegistryAccess;
+import me.shedaniel.autoconfig.gui.registry.api.GuiTransformer;
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Environment(EnvType.CLIENT)
+public final class GuiRegistry implements GuiRegistryAccess {
+    
+    private Map<Priority, List<ProviderEntry>> providers = new HashMap<>();
+    private List<TransformerEntry> transformers = new ArrayList<>();
+    
+    public GuiRegistry() {
+        for (Priority priority : Priority.values()) {
+            providers.put(priority, new ArrayList<>());
+        }
+    }
+    
+    private static <T> Optional<T> firstPresent(Stream<Supplier<Optional<T>>> optionals) {
+        return optionals
+                .map(Supplier::get)
+                .filter(Optional::isPresent)
+                .findFirst()
+                .orElse(Optional.empty());
+    }
+    
+    @Override
+    public List<AbstractConfigListEntry> get(
+            String i13n,
+            Field field,
+            Object config,
+            Object defaults,
+            GuiRegistryAccess registry
+    ) {
+        return firstPresent(
+                Arrays.stream(Priority.values())
+                        .map(priority ->
+                                (Supplier<Optional<ProviderEntry>>) () ->
+                                        providers.get(priority).stream()
+                                                .filter(entry -> entry.predicate.test(field))
+                                                .findFirst()
+                        )
+        )
+                .map(entry -> entry.provider.get(i13n, field, config, defaults, registry))
+                .orElse(null);
+    }
+    
+    @Override
+    public List<AbstractConfigListEntry> transform(
+            List<AbstractConfigListEntry> guis,
+            String i13n,
+            Field field,
+            Object config,
+            Object defaults,
+            GuiRegistryAccess registry
+    ) {
+        List<GuiTransformer> matchedTransformers = this.transformers.stream()
+                .filter(entry -> entry.predicate.test(field))
+                .map(entry -> entry.transformer)
+                .collect(Collectors.toList());
+        
+        for (GuiTransformer transformer : matchedTransformers) {
+            guis = transformer.transform(guis, i13n, field, config, defaults, registry);
+        }
+        
+        return guis;
+    }
+    
+    private void registerProvider(Priority priority, GuiProvider provider, Predicate<Field> predicate) {
+        providers.computeIfAbsent(priority, p -> new ArrayList<>()).add(new ProviderEntry(predicate, provider));
+    }
+    
+    public final void registerTypeProvider(GuiProvider provider, Class... types) {
+        for (Class type : types) {
+            registerProvider(Priority.LAST, provider, field -> type == field.getType());
+        }
+    }
+    
+    public final void registerPredicateProvider(GuiProvider provider, Predicate<Field> predicate) {
+        registerProvider(Priority.NORMAL, provider, predicate);
+    }
+    
+    @SafeVarargs
+    public final void registerAnnotationProvider(GuiProvider provider, Class<? extends Annotation>... types) {
+        for (Class<? extends Annotation> type : types) {
+            registerProvider(Priority.FIRST, provider, field -> field.isAnnotationPresent(type));
+        }
+    }
+    
+    @SafeVarargs
+    public final void registerAnnotationProvider(GuiProvider provider, Predicate<Field> predicate, Class<? extends Annotation>... types) {
+        for (Class<? extends Annotation> type : types) {
+            registerProvider(
+                    Priority.FIRST,
+                    provider,
+                    field -> predicate.test(field) && field.isAnnotationPresent(type)
+            );
+        }
+    }
+    
+    @SuppressWarnings("WeakerAccess")
+    public void registerPredicateTransformer(GuiTransformer transformer, Predicate<Field> predicate) {
+        transformers.add(new TransformerEntry(predicate, transformer));
+    }
+    
+    @SafeVarargs
+    public final void registerAnnotationTransformer(GuiTransformer transformer, Class<? extends Annotation>... types) {
+        registerAnnotationTransformer(transformer, field -> true, types);
+    }
+    
+    @SuppressWarnings("WeakerAccess")
+    @SafeVarargs
+    public final void registerAnnotationTransformer(GuiTransformer transformer, Predicate<Field> predicate, Class<? extends Annotation>... types) {
+        for (Class<? extends Annotation> type : types) {
+            registerPredicateTransformer(transformer, field -> predicate.test(field) && field.isAnnotationPresent(type));
+        }
+    }
+    
+    private enum Priority {
+        FIRST,
+        NORMAL,
+        LAST
+    }
+    
+    private static class ProviderEntry {
+        final Predicate<Field> predicate;
+        final GuiProvider provider;
+        
+        ProviderEntry(Predicate<Field> predicate, GuiProvider provider) {
+            this.predicate = predicate;
+            this.provider = provider;
+        }
+    }
+    
+    private static class TransformerEntry {
+        final Predicate<Field> predicate;
+        final GuiTransformer transformer;
+        
+        TransformerEntry(Predicate<Field> predicate, GuiTransformer transformer) {
+            this.predicate = predicate;
+            this.transformer = transformer;
+        }
+    }
+}

+ 39 - 0
common/src/main/java/me/shedaniel/autoconfig/gui/registry/api/GuiProvider.java

@@ -0,0 +1,39 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.gui.registry.api;
+
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+@FunctionalInterface
+@Environment(EnvType.CLIENT)
+public interface GuiProvider {
+    List<AbstractConfigListEntry> get(
+            String i13n,
+            Field field,
+            Object config,
+            Object defaults,
+            GuiRegistryAccess registry
+    );
+}

+ 40 - 0
common/src/main/java/me/shedaniel/autoconfig/gui/registry/api/GuiRegistryAccess.java

@@ -0,0 +1,40 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.gui.registry.api;
+
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+@Environment(EnvType.CLIENT)
+public interface GuiRegistryAccess extends GuiProvider, GuiTransformer {
+    default List<AbstractConfigListEntry> getAndTransform(
+            String i13n,
+            Field field,
+            Object config,
+            Object defaults,
+            GuiRegistryAccess registry
+    ) {
+        return transform(get(i13n, field, config, defaults, registry), i13n, field, config, defaults, registry);
+    }
+}

+ 40 - 0
common/src/main/java/me/shedaniel/autoconfig/gui/registry/api/GuiTransformer.java

@@ -0,0 +1,40 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.gui.registry.api;
+
+import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+@FunctionalInterface
+@Environment(EnvType.CLIENT)
+public interface GuiTransformer {
+    List<AbstractConfigListEntry> transform(
+            List<AbstractConfigListEntry> guis,
+            String i13n,
+            Field field,
+            Object config,
+            Object defaults,
+            GuiRegistryAccess registry
+    );
+}

+ 44 - 0
common/src/main/java/me/shedaniel/autoconfig/serializer/ConfigSerializer.java

@@ -0,0 +1,44 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.serializer;
+
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.annotation.Config;
+
+public interface ConfigSerializer<T extends ConfigData> {
+    
+    void serialize(T config) throws SerializationException;
+    
+    T deserialize() throws SerializationException;
+    
+    T createDefault();
+    
+    @FunctionalInterface
+    interface Factory<T extends ConfigData> {
+        ConfigSerializer<T> create(Config definition, Class<T> configClass);
+    }
+    
+    class SerializationException extends Exception {
+        public SerializationException(Throwable cause) {
+            super(cause);
+        }
+    }
+}
+

+ 50 - 0
common/src/main/java/me/shedaniel/autoconfig/serializer/DummyConfigSerializer.java

@@ -0,0 +1,50 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.serializer;
+
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.util.Utils;
+
+/**
+ * This serializer doesn't serialize anything. Why would you ever use this?
+ */
+public class DummyConfigSerializer<T extends ConfigData> implements ConfigSerializer<T> {
+    
+    private final Class<T> configClass;
+    
+    public DummyConfigSerializer(@SuppressWarnings("unused") Config definition, Class<T> configClass) {
+        this.configClass = configClass;
+    }
+    
+    @Override
+    public void serialize(T config) {
+    }
+    
+    @Override
+    public T deserialize() {
+        return createDefault();
+    }
+    
+    @Override
+    public T createDefault() {
+        return Utils.constructUnsafely(configClass);
+    }
+}

+ 94 - 0
common/src/main/java/me/shedaniel/autoconfig/serializer/GsonConfigSerializer.java

@@ -0,0 +1,94 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.serializer;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonParseException;
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.util.Utils;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * This serializer serializes configs into Json files using Gson.
+ */
+@SuppressWarnings({"unused", "FieldMayBeFinal"})
+public class GsonConfigSerializer<T extends ConfigData> implements ConfigSerializer<T> {
+    
+    private Config definition;
+    private Class<T> configClass;
+    private Gson gson;
+    
+    @SuppressWarnings("WeakerAccess")
+    public GsonConfigSerializer(Config definition, Class<T> configClass, Gson gson) {
+        this.definition = definition;
+        this.configClass = configClass;
+        this.gson = gson;
+    }
+    
+    public GsonConfigSerializer(Config definition, Class<T> configClass) {
+        this(definition, configClass, new GsonBuilder().setPrettyPrinting().create());
+    }
+    
+    private Path getConfigPath() {
+        return Utils.getConfigFolder().resolve(definition.name() + ".json");
+    }
+    
+    @Override
+    public void serialize(T config) throws SerializationException {
+        Path configPath = getConfigPath();
+        try {
+            Files.createDirectories(configPath.getParent());
+            BufferedWriter writer = Files.newBufferedWriter(configPath);
+            gson.toJson(config, writer);
+            writer.close();
+        } catch (IOException e) {
+            throw new SerializationException(e);
+        }
+    }
+    
+    @Override
+    public T deserialize() throws SerializationException {
+        Path configPath = getConfigPath();
+        if (Files.exists(configPath)) {
+            try {
+                BufferedReader reader = Files.newBufferedReader(configPath);
+                T ret = gson.fromJson(reader, configClass);
+                reader.close();
+                return ret;
+            } catch (IOException | JsonParseException e) {
+                throw new SerializationException(e);
+            }
+        } else {
+            return createDefault();
+        }
+    }
+    
+    @Override
+    public T createDefault() {
+        return Utils.constructUnsafely(configClass);
+    }
+}

+ 87 - 0
common/src/main/java/me/shedaniel/autoconfig/serializer/JanksonConfigSerializer.java

@@ -0,0 +1,87 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.serializer;
+
+import blue.endless.jankson.Jankson;
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.util.Utils;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * This serializer serializes configs into Json5 files using Jankson.
+ */
+@SuppressWarnings("unused")
+public class JanksonConfigSerializer<T extends ConfigData> implements ConfigSerializer<T> {
+    
+    private Config definition;
+    private Class<T> configClass;
+    private Jankson jankson;
+    
+    public JanksonConfigSerializer(Config definition, Class<T> configClass, Jankson jankson) {
+        this.definition = definition;
+        this.configClass = configClass;
+        this.jankson = jankson;
+    }
+    
+    public JanksonConfigSerializer(Config definition, Class<T> configClass) {
+        this(definition, configClass, Jankson.builder().build());
+    }
+    
+    private Path getConfigPath() {
+        return Utils.getConfigFolder().resolve(definition.name() + ".json5");
+    }
+    
+    @Override
+    public void serialize(T config) throws SerializationException {
+        Path configPath = getConfigPath();
+        try {
+            Files.createDirectories(configPath.getParent());
+            BufferedWriter writer = Files.newBufferedWriter(configPath);
+            writer.write(jankson.toJson(config).toJson(true, true));
+            writer.close();
+        } catch (IOException e) {
+            throw new SerializationException(e);
+        }
+    }
+    
+    @Override
+    public T deserialize() throws SerializationException {
+        Path configPath = getConfigPath();
+        if (Files.exists(configPath)) {
+            try {
+                return jankson.fromJson(jankson.load(getConfigPath().toFile()), configClass);
+            } catch (Throwable e) {
+                throw new SerializationException(e);
+            }
+        } else {
+            return createDefault();
+        }
+    }
+    
+    @Override
+    public T createDefault() {
+        return Utils.constructUnsafely(configClass);
+    }
+}

+ 146 - 0
common/src/main/java/me/shedaniel/autoconfig/serializer/PartitioningSerializer.java

@@ -0,0 +1,146 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.serializer;
+
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.util.Utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * This serializer wraps another serializer and produces a folder with each field of the config
+ * corresponding to a single config file.
+ * The top level config must inherit from GlobalData.
+ * Each field of the top level config must be of a type inheriting from ConfigData.
+ */
+public final class PartitioningSerializer<T extends PartitioningSerializer.GlobalData, M extends ConfigData> implements ConfigSerializer<T> {
+    
+    private Class<T> configClass;
+    private Map<Field, ConfigSerializer<M>> serializers;
+    
+    private PartitioningSerializer(Config definition, Class<T> configClass, ConfigSerializer.Factory<M> factory) {
+        this.configClass = configClass;
+        
+        //noinspection unchecked
+        serializers = getModuleFields(configClass).stream()
+                .collect(
+                        Utils.toLinkedMap(
+                                Function.identity(),
+                                field -> factory.create(
+                                        createDefinition(
+                                                String.format(
+                                                        "%s/%s",
+                                                        definition.name(),
+                                                        field.getType().getAnnotation(Config.class).name()
+                                                )
+                                        ),
+                                        (Class<M>) field.getType()
+                                )
+                        )
+                );
+    }
+    
+    public static <T extends PartitioningSerializer.GlobalData, M extends ConfigData>
+    ConfigSerializer.Factory<T> wrap(ConfigSerializer.Factory<M> inner) {
+        return (definition, configClass) -> new PartitioningSerializer<>(definition, configClass, inner);
+    }
+    
+    private static Config createDefinition(String name) {
+        return new Config() {
+            
+            @Override
+            public Class<? extends Annotation> annotationType() {
+                return Config.class;
+            }
+            
+            @Override
+            public String name() {
+                return name;
+            }
+            
+            @Override
+            public int hashCode() {
+                return ("name".hashCode() * 127) ^ name().hashCode();
+            }
+            
+            @Override
+            public boolean equals(Object obj) {
+                return obj instanceof Config && ((Config) obj).name().equals(name());
+            }
+        };
+    }
+    
+    private static boolean isValidModule(Field field) {
+        return ConfigData.class.isAssignableFrom(field.getType())
+               && field.getType().isAnnotationPresent(Config.class);
+    }
+    
+    private static List<Field> getModuleFields(Class<?> configClass) {
+        return Arrays.stream(configClass.getDeclaredFields())
+                .filter(PartitioningSerializer::isValidModule)
+                .collect(Collectors.toList());
+    }
+    
+    @Override
+    public void serialize(T config) throws SerializationException {
+        for (Map.Entry<Field, ConfigSerializer<M>> entry : serializers.entrySet()) {
+            entry.getValue().serialize(Utils.getUnsafely(entry.getKey(), config));
+        }
+    }
+    
+    @Override
+    public T deserialize() throws SerializationException {
+        T ret = createDefault();
+        for (Map.Entry<Field, ConfigSerializer<M>> entry : serializers.entrySet()) {
+            Utils.setUnsafely(entry.getKey(), ret, entry.getValue().deserialize());
+        }
+        return ret;
+    }
+    
+    @Override
+    public T createDefault() {
+        return Utils.constructUnsafely(configClass);
+    }
+    
+    public static abstract class GlobalData implements ConfigData {
+        
+        public GlobalData() {
+            Arrays.stream(getClass().getDeclaredFields())
+                    .filter(field -> !isValidModule(field))
+                    .forEach(field -> {
+                        throw new RuntimeException(String.format("Invalid module: %s", field));
+                    });
+        }
+        
+        @Override
+        final public void validatePostLoad() throws ValidationException {
+            for (Field moduleField : getModuleFields(getClass())) {
+                ((ConfigData) Utils.getUnsafely(moduleField, this)).validatePostLoad();
+            }
+        }
+    }
+}

+ 86 - 0
common/src/main/java/me/shedaniel/autoconfig/serializer/Toml4jConfigSerializer.java

@@ -0,0 +1,86 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.serializer;
+
+import com.moandjiezana.toml.Toml;
+import com.moandjiezana.toml.TomlWriter;
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.util.Utils;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * This serializer serializes configs into Toml files using Toml4j.
+ */
+@SuppressWarnings("unused")
+public class Toml4jConfigSerializer<T extends ConfigData> implements ConfigSerializer<T> {
+    
+    private Config definition;
+    private Class<T> configClass;
+    private TomlWriter tomlWriter;
+    
+    @SuppressWarnings("WeakerAccess")
+    public Toml4jConfigSerializer(Config definition, Class<T> configClass, TomlWriter tomlWriter) {
+        this.definition = definition;
+        this.configClass = configClass;
+        this.tomlWriter = tomlWriter;
+    }
+    
+    public Toml4jConfigSerializer(Config definition, Class<T> configClass) {
+        this(definition, configClass, new TomlWriter());
+    }
+    
+    private Path getConfigPath() {
+        return Utils.getConfigFolder().resolve(definition.name() + ".toml");
+    }
+    
+    @Override
+    public void serialize(T config) throws SerializationException {
+        Path configPath = getConfigPath();
+        try {
+            Files.createDirectories(configPath.getParent());
+            tomlWriter.write(config, configPath.toFile());
+        } catch (IOException e) {
+            throw new SerializationException(e);
+        }
+    }
+    
+    @Override
+    public T deserialize() throws SerializationException {
+        Path configPath = getConfigPath();
+        if (Files.exists(configPath)) {
+            try {
+                return new Toml().read(configPath.toFile()).to(configClass);
+            } catch (IllegalStateException e) {
+                throw new SerializationException(e);
+            }
+        } else {
+            return createDefault();
+        }
+    }
+    
+    @Override
+    public T createDefault() {
+        return Utils.constructUnsafely(configClass);
+    }
+}

+ 84 - 0
common/src/main/java/me/shedaniel/autoconfig/serializer/YamlConfigSerializer.java

@@ -0,0 +1,84 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.serializer;
+
+import me.shedaniel.autoconfig.ConfigData;
+import me.shedaniel.autoconfig.annotation.Config;
+import me.shedaniel.autoconfig.util.Utils;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+public class YamlConfigSerializer<T extends ConfigData> implements ConfigSerializer<T> {
+    
+    private Config definition;
+    private Class<T> configClass;
+    private Yaml yaml;
+    
+    @SuppressWarnings("WeakerAccess")
+    public YamlConfigSerializer(Config definition, Class<T> configClass, Yaml yaml) {
+        this.definition = definition;
+        this.configClass = configClass;
+        this.yaml = yaml;
+    }
+    
+    public YamlConfigSerializer(Config definition, Class<T> configClass) {
+        this(definition, configClass, new Yaml());
+    }
+    
+    private Path getConfigPath() {
+        return Utils.getConfigFolder().resolve(definition.name() + ".yaml");
+    }
+    
+    @Override
+    public void serialize(T config) throws SerializationException {
+        Path configPath = getConfigPath();
+        try {
+            Files.createDirectories(configPath.getParent());
+            Files.write(configPath, yaml.dump(config).getBytes(StandardCharsets.UTF_8));
+        } catch (IOException e) {
+            throw new SerializationException(e);
+        }
+    }
+    
+    @Override
+    public T deserialize() throws SerializationException {
+        Path configPath = getConfigPath();
+        if (Files.exists(configPath)) {
+            try (InputStream stream = Files.newInputStream(configPath)) {
+                return yaml.load(stream);
+            } catch (IOException e) {
+                throw new SerializationException(e);
+            }
+        } else {
+            return createDefault();
+        }
+    }
+    
+    @Override
+    public T createDefault() {
+        return Utils.constructUnsafely(configClass);
+    }
+}
+

+ 98 - 0
common/src/main/java/me/shedaniel/autoconfig/util/Utils.java

@@ -0,0 +1,98 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.autoconfig.util;
+
+import me.shedaniel.architectury.annotations.ExpectPlatform;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.nio.file.Path;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collector;
+
+import static java.util.stream.Collectors.toMap;
+
+public class Utils {
+    private Utils() {
+    }
+    
+    @ExpectPlatform
+    public static Path getConfigFolder() {
+        throw new AssertionError();
+    }
+    
+    public static <V> V constructUnsafely(Class<V> cls) {
+        try {
+            Constructor<V> constructor = cls.getDeclaredConstructor();
+            constructor.setAccessible(true);
+            return constructor.newInstance();
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    public static <V> V getUnsafely(Field field, Object obj) {
+        if (obj == null)
+            return null;
+        
+        try {
+            field.setAccessible(true);
+            //noinspection unchecked
+            return (V) field.get(obj);
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    public static <V> V getUnsafely(Field field, Object obj, V defaultValue) {
+        V ret = getUnsafely(field, obj);
+        if (ret == null)
+            ret = defaultValue;
+        return ret;
+    }
+    
+    public static void setUnsafely(Field field, Object obj, Object newValue) {
+        if (obj == null)
+            return;
+        
+        try {
+            field.setAccessible(true);
+            field.set(obj, newValue);
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    public static <T, K, U> Collector<T, ?, Map<K, U>> toLinkedMap(
+            Function<? super T, ? extends K> keyMapper,
+            Function<? super T, ? extends U> valueMapper
+    ) {
+        return toMap(
+                keyMapper,
+                valueMapper,
+                (u, v) -> {
+                    throw new IllegalStateException(String.format("Duplicate key %s", u));
+                },
+                LinkedHashMap::new
+        );
+    }
+}

+ 22 - 12
forge/src/main/java/me/shedaniel/clothconfig2/ClothConfigForgeDemo.java → common/src/main/java/me/shedaniel/clothconfig2/ClothConfigDemo.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2;
 package me.shedaniel.clothconfig2;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;
@@ -14,21 +33,12 @@ import net.minecraft.network.chat.TranslatableComponent;
 import net.minecraft.resources.ResourceLocation;
 import net.minecraft.resources.ResourceLocation;
 import net.minecraft.world.item.Item;
 import net.minecraft.world.item.Item;
 import net.minecraft.world.item.Items;
 import net.minecraft.world.item.Items;
-import net.minecraftforge.fml.ExtensionPoint;
-import net.minecraftforge.fml.ModLoadingContext;
 
 
 import java.util.*;
 import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
-public class ClothConfigForgeDemo {
-    
-    public static void registerModsPage() {
-        ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY, () -> (client, parent) -> {
-            return ClothConfigForgeDemo.getConfigBuilderWithDemo(parent).build();
-        });
-    }
-    
-    public static ConfigBuilder getConfigBuilderWithDemo(Screen parent) {
+public class ClothConfigDemo {
+    public static ConfigBuilder getConfigBuilderWithDemo() {
         class Pair<T, R> {
         class Pair<T, R> {
             T t;
             T t;
             R r;
             R r;
@@ -65,7 +75,7 @@ public class ClothConfigForgeDemo {
             }
             }
         }
         }
         
         
-        ConfigBuilder builder = ConfigBuilder.create().setParentScreen(parent).setTitle(new TranslatableComponent("title.cloth-config.config"));
+        ConfigBuilder builder = ConfigBuilder.create().setTitle(new TranslatableComponent("title.cloth-config.config"));
         builder.setDefaultBackgroundTexture(new ResourceLocation("minecraft:textures/block/oak_planks.png"));
         builder.setDefaultBackgroundTexture(new ResourceLocation("minecraft:textures/block/oak_planks.png"));
 //        builder.setGlobalized(true);
 //        builder.setGlobalized(true);
         ConfigEntryBuilder entryBuilder = builder.entryBuilder();
         ConfigEntryBuilder entryBuilder = builder.entryBuilder();

+ 20 - 1
common/src/main/java/me/shedaniel/clothconfig2/ClothConfigInitializer.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2;
 package me.shedaniel.clothconfig2;
 
 
 import me.shedaniel.clothconfig2.api.ScrollingContainer;
 import me.shedaniel.clothconfig2.api.ScrollingContainer;
@@ -13,7 +32,7 @@ import org.jetbrains.annotations.ApiStatus;
 public class ClothConfigInitializer {
 public class ClothConfigInitializer {
     public static final Logger LOGGER = LogManager.getFormatterLogger("ClothConfig");
     public static final Logger LOGGER = LogManager.getFormatterLogger("ClothConfig");
     
     
-    public static final String MOD_ID = "cloth-config2";
+    public static final String MOD_ID = "cloth-config";
     
     
     @Deprecated
     @Deprecated
     @ApiStatus.ScheduledForRemoval
     @ApiStatus.ScheduledForRemoval

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import me.shedaniel.clothconfig2.gui.AbstractConfigScreen;
 import me.shedaniel.clothconfig2.gui.AbstractConfigScreen;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import com.mojang.blaze3d.vertex.PoseStack;
 import com.mojang.blaze3d.vertex.PoseStack;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/ConfigBuilder.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import me.shedaniel.clothconfig2.impl.ConfigBuilderImpl;
 import me.shedaniel.clothconfig2.impl.ConfigBuilderImpl;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/ConfigCategory.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/ConfigEntryBuilder.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import com.mojang.blaze3d.platform.InputConstants;
 import com.mojang.blaze3d.platform.InputConstants;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/ConfigScreen.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.Nullable;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/Expandable.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 public interface Expandable {
 public interface Expandable {

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/LazyResettable.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import java.util.Objects;
 import java.util.Objects;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/Modifier.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/ModifierKeyCode.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import com.mojang.blaze3d.platform.InputConstants;
 import com.mojang.blaze3d.platform.InputConstants;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/QueuedTooltip.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import me.shedaniel.math.Point;
 import me.shedaniel.math.Point;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/ReferenceBuildingConfigScreen.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 public interface ReferenceBuildingConfigScreen extends ConfigScreen {
 public interface ReferenceBuildingConfigScreen extends ConfigScreen {

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/ReferenceProvider.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.NotNull;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/ScissorsHandler.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import me.shedaniel.clothconfig2.impl.ScissorsHandlerImpl;
 import me.shedaniel.clothconfig2.impl.ScissorsHandlerImpl;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/ScissorsScreen.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.math.Rectangle;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/TabbedConfigScreen.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import net.minecraft.network.chat.Component;
 import net.minecraft.network.chat.Component;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/api/Tooltip.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.api;
 package me.shedaniel.clothconfig2.api;
 
 
 import me.shedaniel.math.Point;
 import me.shedaniel.math.Point;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/AbstractConfigScreen.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui;
 package me.shedaniel.clothconfig2.gui;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/AbstractTabbedConfigScreen.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui;
 package me.shedaniel.clothconfig2.gui;
 
 
 import com.google.common.collect.Maps;
 import com.google.common.collect.Maps;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/ClothConfigScreen.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui;
 package me.shedaniel.clothconfig2.gui;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/ClothConfigTabButton.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui;
 package me.shedaniel.clothconfig2.gui;
 
 
 import me.shedaniel.clothconfig2.api.Tooltip;
 import me.shedaniel.clothconfig2.api.Tooltip;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/ClothRequiresRestartScreen.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui;
 package me.shedaniel.clothconfig2.gui;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/GlobalizedClothConfigScreen.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui;
 package me.shedaniel.clothconfig2.gui;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/AbstractListListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/AbstractTextFieldListListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BaseListCell.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BaseListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BooleanListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/ColorEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import me.shedaniel.clothconfig2.gui.widget.ColorDisplayWidget;
 import me.shedaniel.clothconfig2.gui.widget.ColorDisplayWidget;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/DoubleListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/DoubleListListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/DropdownBoxEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/EnumListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/FloatListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/FloatListListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/IntegerListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/IntegerListListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/IntegerSliderEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/KeyCodeEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/LongListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/LongListListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/LongSliderEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/MultiElementListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/NestedListListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/SelectionListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/StringListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/StringListListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/SubCategoryListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TextFieldListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TextListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TooltipListEntry.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.entries;
 package me.shedaniel.clothconfig2.gui.entries;
 
 
 import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
 import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/widget/ColorDisplayWidget.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.widget;
 package me.shedaniel.clothconfig2.gui.widget;
 
 
 import com.mojang.blaze3d.vertex.PoseStack;
 import com.mojang.blaze3d.vertex.PoseStack;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicElementListWidget.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.widget;
 package me.shedaniel.clothconfig2.gui.widget;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicEntryListWidget.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.gui.widget;
 package me.shedaniel.clothconfig2.gui.widget;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 17 - 22
common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicNewSmoothScrollingEntryListWidget.java

@@ -1,27 +1,22 @@
 /*
 /*
- * The smooth scrolling code is partially taken from osu-framework.
- * <p>
- * Copyright (c) 2020 ppy Pty Ltd <contact@ppy.sh>.
- * Copyright (c) 2018, 2019, 2020 shedaniel.
- * <p>
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- * <p>
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * <p>
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
  */
+
 package me.shedaniel.clothconfig2.gui.widget;
 package me.shedaniel.clothconfig2.gui.widget;
 
 
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/ConfigBuilderImpl.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl;
 package me.shedaniel.clothconfig2.impl;
 
 
 import com.google.common.collect.Maps;
 import com.google.common.collect.Maps;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/ConfigCategoryImpl.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl;
 package me.shedaniel.clothconfig2.impl;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/ConfigEntryBuilderImpl.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl;
 package me.shedaniel.clothconfig2.impl;
 
 
 import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
 import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/EasingMethod.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl;
 package me.shedaniel.clothconfig2.impl;
 
 
 import java.util.function.Function;
 import java.util.function.Function;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/EasingMethods.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl;
 package me.shedaniel.clothconfig2.impl;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/GameOptionsHooks.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl;
 package me.shedaniel.clothconfig2.impl;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/KeyBindingHooks.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl;
 package me.shedaniel.clothconfig2.impl;
 
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/ModifierKeyCodeImpl.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl;
 package me.shedaniel.clothconfig2.impl;
 
 
 import com.mojang.blaze3d.platform.InputConstants;
 import com.mojang.blaze3d.platform.InputConstants;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/ScissorsHandlerImpl.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl;
 package me.shedaniel.clothconfig2.impl;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/builders/BooleanToggleBuilder.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl.builders;
 package me.shedaniel.clothconfig2.impl.builders;
 
 
 import me.shedaniel.clothconfig2.gui.entries.BooleanListEntry;
 import me.shedaniel.clothconfig2.gui.entries.BooleanListEntry;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/builders/ColorFieldBuilder.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl.builders;
 package me.shedaniel.clothconfig2.impl.builders;
 
 
 import me.shedaniel.clothconfig2.gui.entries.ColorEntry;
 import me.shedaniel.clothconfig2.gui.entries.ColorEntry;

+ 19 - 0
common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleFieldBuilder.java

@@ -1,3 +1,22 @@
+/*
+ * This file is part of Cloth Config.
+ * Copyright (C) 2020 - 2021 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package me.shedaniel.clothconfig2.impl.builders;
 package me.shedaniel.clothconfig2.impl.builders;
 
 
 import me.shedaniel.clothconfig2.gui.entries.DoubleListEntry;
 import me.shedaniel.clothconfig2.gui.entries.DoubleListEntry;

部分文件因为文件数量过多而无法显示