aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/build.gradle.kts1
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/GsonConfigSerializerBuilder.java2
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/SimpleOptionFactory.java5
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java14
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java109
-rw-r--r--fabric/build.gradle.kts4
-rw-r--r--forge/build.gradle.kts5
-rw-r--r--gradle/libs.versions.toml7
-rw-r--r--test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java9
-rw-r--r--test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java5
-rw-r--r--test-fabric/build.gradle.kts1
-rw-r--r--test-forge/build.gradle.kts2
12 files changed, 110 insertions, 54 deletions
diff --git a/common/build.gradle.kts b/common/build.gradle.kts
index 7d5ece7..ba6dd04 100644
--- a/common/build.gradle.kts
+++ b/common/build.gradle.kts
@@ -28,6 +28,7 @@ dependencies {
modImplementation(libs.fabric.loader)
implementation(libs.bundles.twelvemonkeys.imageio)
+ implementation(libs.bundles.quilt.parsers)
}
java {
diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/GsonConfigSerializerBuilder.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/GsonConfigSerializerBuilder.java
index 8d8d6c7..e871b7c 100644
--- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/GsonConfigSerializerBuilder.java
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/GsonConfigSerializerBuilder.java
@@ -64,5 +64,7 @@ public interface GsonConfigSerializerBuilder<T> {
*/
GsonConfigSerializerBuilder<T> appendGsonBuilder(UnaryOperator<GsonBuilder> gsonBuilder);
+ GsonConfigSerializerBuilder<T> setJson5(boolean json5);
+
ConfigSerializer<T> build();
}
diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/SimpleOptionFactory.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/SimpleOptionFactory.java
index 5c6894e..67b1d87 100644
--- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/SimpleOptionFactory.java
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/SimpleOptionFactory.java
@@ -26,6 +26,7 @@ public abstract class SimpleOptionFactory<A extends Annotation, T> implements Op
.controller(opt -> this.createController(annotation, field, storage, opt))
.available(this.available(annotation, field, storage))
.flags(this.flags(annotation, field, storage))
+ .listener((opt, v) -> this.listener(annotation, field, storage, opt, v))
.build();
postInit(annotation, field, storage, option);
@@ -70,6 +71,10 @@ public abstract class SimpleOptionFactory<A extends Annotation, T> implements Op
return Set.of();
}
+ protected void listener(A annotation, ConfigField<T> field, OptionStorage storage, Option<T> option, T value) {
+
+ }
+
protected void postInit(A annotation, ConfigField<T> field, OptionStorage storage, Option<T> option) {
}
diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java
index 65433a3..fa2b7b5 100644
--- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java
@@ -15,13 +15,11 @@ public class MasterTickBoxImpl extends SimpleOptionFactory<MasterTickBox, Boolea
}
@Override
- protected void postInit(MasterTickBox annotation, ConfigField<Boolean> field, OptionStorage storage, Option<Boolean> option) {
- option.addListener((opt, val) -> {
- for (String child : annotation.value()) {
- storage.scheduleOptionOperation(child, childOpt -> {
- childOpt.setAvailable(annotation.invert() != val);
- });
- }
- });
+ protected void listener(MasterTickBox annotation, ConfigField<Boolean> field, OptionStorage storage, Option<Boolean> option, Boolean value) {
+ for (String child : annotation.value()) {
+ storage.scheduleOptionOperation(child, childOpt -> {
+ childOpt.setAvailable(annotation.invert() != value);
+ });
+ }
}
}
diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java
index 712a459..c59d20b 100644
--- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java
@@ -6,52 +6,71 @@ import dev.isxander.yacl3.impl.utils.YACLConstants;
import dev.isxander.yacl3.platform.YACLPlatform;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
+import org.quiltmc.parsers.json.JsonReader;
+import org.quiltmc.parsers.json.JsonWriter;
+import org.quiltmc.parsers.json.gson.GsonReader;
+import org.quiltmc.parsers.json.gson.GsonWriter;
import java.awt.*;
+import java.io.IOException;
+import java.io.StringWriter;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
public class GsonConfigSerializer<T> extends ConfigSerializer<T> {
private final Gson gson;
private final Path path;
+ private final boolean json5;
- private GsonConfigSerializer(ConfigClassHandler<T> config, Path path, Gson gson) {
+ private GsonConfigSerializer(ConfigClassHandler<T> config, Path path, Gson gson, boolean json5) {
super(config);
this.gson = gson;
this.path = path;
+ this.json5 = json5;
}
@Override
public void serialize() {
- JsonObject root = new JsonObject();
+ YACLConstants.LOGGER.info("Serializing {} to '{}'", config.configClass(), path);
- for (ConfigField<?> field : config.fields()) {
- SerialField serial = field.serial().orElse(null);
- if (serial == null) {
- continue;
- }
+ try (StringWriter stringWriter = new StringWriter()) {
+ JsonWriter jsonWriter = json5 ? JsonWriter.json5(stringWriter) : JsonWriter.json(stringWriter);
+ GsonWriter gsonWriter = new GsonWriter(jsonWriter);
+ jsonWriter.beginObject();
+ for (ConfigField<?> field : config.fields()) {
+ SerialField serial = field.serial().orElse(null);
+ if (serial == null) {
+ continue;
+ }
- if (YACLPlatform.isDevelopmentEnv() && serial.comment().isPresent()) {
- YACLConstants.LOGGER.error("Config field '{}' has a comment, but comments are not supported by Gson. Please remove the comment or switch to a different serializer. This log will not be shown in production.", serial.serialName());
- }
+ if (!json5 && serial.comment().isPresent() && YACLPlatform.isDevelopmentEnv()) {
+ YACLConstants.LOGGER.warn("Found comment in config field '{}', but json5 is not enabled. Enable it with `.setJson5(true)` on the `GsonConfigSerializerBuilder`. Comments will not be serialized. This warning is only visible in development environments.", serial.serialName());
+ }
+ jsonWriter.comment(serial.comment().orElse(null));
- try {
- root.add(serial.serialName(), gson.toJsonTree(field.access().get()));
- } catch (Exception e) {
- YACLConstants.LOGGER.error("Failed to serialize config field '{}'.", serial.serialName(), e);
+ jsonWriter.name(serial.serialName());
+ try {
+ gson.toJson(field.access().get(), field.access().type(), gsonWriter);
+ } catch (Exception e) {
+ YACLConstants.LOGGER.error("Failed to serialize config field '{}'.", serial.serialName(), e);
+ jsonWriter.nullValue();
+ }
}
- }
+ jsonWriter.endObject();
+ jsonWriter.flush();
- YACLConstants.LOGGER.info("Serializing {} to '{}'", config.configClass(), path);
- try {
- Files.writeString(path, gson.toJson(root), StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE);
- } catch (Exception e) {
+ Files.createDirectories(path.getParent());
+ Files.writeString(path, stringWriter.toString(), StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE);
+ } catch (IOException e) {
YACLConstants.LOGGER.error("Failed to serialize config class '{}'.", config.configClass().getSimpleName(), e);
}
}
@@ -66,38 +85,37 @@ public class GsonConfigSerializer<T> extends ConfigSerializer<T> {
YACLConstants.LOGGER.info("Deserializing {} from '{}'", config.configClass().getSimpleName(), path);
- String json;
- try {
- json = Files.readString(path);
- } catch (Exception e) {
- throw new IllegalStateException("Failed to read '%s' for deserialization.".formatted(path), e);
- }
+ try (JsonReader jsonReader = json5 ? JsonReader.json5(path) : JsonReader.json(path)) {
+ GsonReader gsonReader = new GsonReader(jsonReader);
- Map<String, JsonElement> root = gson.fromJson(json, JsonObject.class).asMap();
- List<String> unconsumedKeys = new ArrayList<>(root.keySet());
+ Map<String, ConfigField<?>> fieldMap = Arrays.stream(config.fields())
+ .filter(field -> field.serial().isPresent())
+ .collect(Collectors.toMap(f -> f.serial().orElseThrow().serialName(), Function.identity()));
- for (ConfigField<?> field : config.fields()) {
- SerialField serial = field.serial().orElse(null);
- if (serial == null) {
- continue;
- }
+ jsonReader.beginObject();
+
+ while (jsonReader.hasNext()) {
+ String name = jsonReader.nextName();
+ ConfigField<?> field = fieldMap.get(name);
+ if (field == null) {
+ YACLConstants.LOGGER.warn("Found unknown config field '{}' in '{}'.", name, path);
+ jsonReader.skipValue();
+ continue;
+ }
- if (root.containsKey(serial.serialName())) {
try {
- field.access().set(gson.fromJson(root.get(serial.serialName()), field.access().type()));
+ field.access().set(gson.fromJson(gsonReader, field.access().type()));
} catch (Exception e) {
- YACLConstants.LOGGER.error("Failed to deserialize config field '{}'.", serial.serialName(), e);
+ YACLConstants.LOGGER.error("Failed to deserialize config field '{}'.", name, e);
+ jsonReader.skipValue();
}
- } else {
- YACLConstants.LOGGER.warn("Config field '{}' was not found in the config file. Skipping.", serial.serialName());
}
- unconsumedKeys.remove(serial.serialName());
+ jsonReader.endObject();
+ } catch (IOException e) {
+ YACLConstants.LOGGER.error("Failed to deserialize config class '{}'.", config.configClass().getSimpleName(), e);
}
- if (!unconsumedKeys.isEmpty()) {
- YACLConstants.LOGGER.warn("The following keys were not consumed by the config class: {}", String.join(", ", unconsumedKeys));
- }
}
public static class ColorTypeAdapter implements JsonSerializer<Color>, JsonDeserializer<Color> {
@@ -115,6 +133,7 @@ public class GsonConfigSerializer<T> extends ConfigSerializer<T> {
public static class Builder<T> implements GsonConfigSerializerBuilder<T> {
private final ConfigClassHandler<T> config;
private Path path;
+ private boolean json5;
private UnaryOperator<GsonBuilder> gsonBuilder = builder -> builder
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.serializeNulls()
@@ -152,8 +171,14 @@ public class GsonConfigSerializer<T> extends ConfigSerializer<T> {
}
@Override
+ public Builder<T> setJson5(boolean json5) {
+ this.json5 = json5;
+ return this;
+ }
+
+ @Override
public GsonConfigSerializer<T> build() {
- return new GsonConfigSerializer<>(config, path, gsonBuilder.apply(new GsonBuilder()).create());
+ return new GsonConfigSerializer<>(config, path, gsonBuilder.apply(new GsonBuilder()).create(), json5);
}
}
}
diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts
index bee77d4..de256bd 100644
--- a/fabric/build.gradle.kts
+++ b/fabric/build.gradle.kts
@@ -44,6 +44,10 @@ dependencies {
implementation(it)
include(it)
}
+ libs.bundles.quilt.parsers.let {
+ implementation(it)
+ include(it)
+ }
"common"(project(path = ":common", configuration = "namedElements")) { isTransitive = false }
"shadowCommon"(project(path = ":common", configuration = "transformProductionFabric")) { isTransitive = false }
diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts
index 16cd72d..73e2ccb 100644
--- a/forge/build.gradle.kts
+++ b/forge/build.gradle.kts
@@ -50,6 +50,11 @@ dependencies {
include(it)
forgeRuntimeLibrary(it)
}
+ libs.bundles.quilt.parsers.let {
+ implementation(it)
+ include(it)
+ forgeRuntimeLibrary(it)
+ }
"common"(project(path = ":common", configuration = "namedElements")) { isTransitive = false }
"shadowCommon"(project(path = ":common", configuration = "transformProductionForge")) { isTransitive = false }
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index fdbf9df..77242e8 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -17,6 +17,7 @@ fabric_loader = "0.14.21"
# Common Dependencies
mixin_extras = "0.2.0-beta.8"
twelvemonkeys_imageio = "3.10.0-SNAPSHOT"
+quilt_parsers = "0.2.1"
# Fabric-like Dependencies
fabric_api = "0.86.0+1.20.1"
@@ -37,6 +38,8 @@ twelvemonkeys_imageio_metadata = { module = "com.twelvemonkeys.imageio:imageio-m
twelvemonkeys_common_lang = { module = "com.twelvemonkeys.common:common-lang", version.ref = "twelvemonkeys_imageio" }
twelvemonkeys_common_io = { module = "com.twelvemonkeys.common:common-io", version.ref = "twelvemonkeys_imageio" }
twelvemonkeys_common_image = { module = "com.twelvemonkeys.common:common-image", version.ref = "twelvemonkeys_imageio" }
+quilt_parsers_json = { module = "org.quiltmc.parsers:json", version.ref = "quilt_parsers" }
+quilt_parsers_gson = { module = "org.quiltmc.parsers:gson", version.ref = "quilt_parsers" }
# Fabric-like Dependencies
fabric_api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric_api" }
@@ -54,6 +57,10 @@ twelvemonkeys_imageio = [
"twelvemonkeys_common_io",
"twelvemonkeys_common_image"
]
+quilt_parsers = [
+ "quilt_parsers_json",
+ "quilt_parsers_gson"
+]
[plugins]
architectury_loom = { id = "dev.architectury.loom", version.ref = "architectury_loom" }
diff --git a/test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java b/test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java
index 6084e23..d287604 100644
--- a/test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java
+++ b/test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java
@@ -12,18 +12,21 @@ public class ConfigV2Test {
public static ConfigClassHandler<ConfigV2Test> INSTANCE = ConfigClassHandler.createBuilder(ConfigV2Test.class)
.id(new ResourceLocation("yacl3", "config"))
.serializer(config -> GsonConfigSerializerBuilder.create(config)
- .setPath(YACLPlatform.getConfigDir().resolve("yacl-test-v2.json"))
+ .setPath(YACLPlatform.getConfigDir().resolve("yacl-test-v2.json5"))
+ .setJson5(true)
.build())
.autoGen(true)
.build();
@AutoGen(category = "test", group = "master_test")
@MasterTickBox({ "testTickBox", "testInt" })
- @SerialEntry public boolean masterOption = true;
+ @SerialEntry(comment = "This option does this and that which is cool because this...")
+ public boolean masterOption = true;
@AutoGen(category = "test", group = "master_test")
@TickBox
- @SerialEntry public boolean testTickBox = true;
+ @SerialEntry(comment = "This is a cool comment omg this is amazing")
+ public boolean testTickBox = true;
@AutoGen(category = "test", group = "master_test")
@IntSlider(min = 0, max = 10, step = 2)
diff --git a/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java b/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java
index 2eadb2a..4953d0c 100644
--- a/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java
+++ b/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java
@@ -44,7 +44,10 @@ public class GuiTest {
.build())
.option(ButtonOption.createBuilder()
.name(Component.literal("Auto-gen test"))
- .action((screen, opt) -> Minecraft.getInstance().setScreen(ConfigV2Test.INSTANCE.generateGui().generateScreen(screen)))
+ .action((screen, opt) -> {
+ ConfigV2Test.INSTANCE.serializer().deserialize();
+ Minecraft.getInstance().setScreen(ConfigV2Test.INSTANCE.generateGui().generateScreen(screen));
+ })
.build())
.group(OptionGroup.createBuilder()
.name(Component.literal("Wiki"))
diff --git a/test-fabric/build.gradle.kts b/test-fabric/build.gradle.kts
index 5786b4a..f2145d9 100644
--- a/test-fabric/build.gradle.kts
+++ b/test-fabric/build.gradle.kts
@@ -33,6 +33,7 @@ dependencies {
implementation(libs.twelvemonkeys.imageio.core)
implementation(libs.twelvemonkeys.imageio.webp)
+ implementation(libs.bundles.quilt.parsers)
"common"(project(path = ":test-common", configuration = "namedElements")) { isTransitive = false }
implementation(project(path = ":fabric", configuration = "namedElements"))
diff --git a/test-forge/build.gradle.kts b/test-forge/build.gradle.kts
index 6fd938f..b43c7eb 100644
--- a/test-forge/build.gradle.kts
+++ b/test-forge/build.gradle.kts
@@ -42,6 +42,8 @@ dependencies {
forgeRuntimeLibrary(libs.twelvemonkeys.imageio.core)
implementation(libs.twelvemonkeys.imageio.webp)
forgeRuntimeLibrary(libs.twelvemonkeys.imageio.webp)
+ implementation(libs.bundles.quilt.parsers)
+ forgeRuntimeLibrary(libs.bundles.quilt.parsers)
"common"(project(path = ":test-common", configuration = "namedElements")) { isTransitive = false }
implementation(project(path = ":forge", configuration = "namedElements"))