diff --git a/build.gradle.kts b/build.gradle.kts index 805e443..d79b6d4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,20 +5,11 @@ plugins { allprojects { group = "io.gitlab.jfronny.libjf" } subprojects { version = rootProject.version } -val fabricVersion by extra("0.91.1+1.20.4") -val commonsVersion by extra("1.5-SNAPSHOT") -val gsonCompileVersion by extra("1.4-SNAPSHOT") -val modmenuVersion by extra("9.0.0-pre.1") - -val annotationsVersion by extra("24.0.1") -val javapoetVersion by extra("1.13.0") - -val baseCommonsModules by extra(listOf("http-client", "io", "logging", "logging-slf4j", "serialize", "serialize-gson")) - jfMod { - minecraftVersion = "1.20.4" - yarn("build.1") - loaderVersion = "0.15.0" + minecraftVersion = libs.versions.minecraft + yarn(libs.versions.yarn.get()) + loaderVersion = libs.versions.fabric.loader + fabricApiVersion = libs.versions.fabric.api modrinth { projectId = "libjf" @@ -30,20 +21,21 @@ jfMod { } } +base { + archivesName = "libjf" +} + allprojects { if (!rootProject.jfMod.isMod(this)) return@allprojects - base { - archivesName = "libjf" - } - dependencies { - modLocalRuntime("com.terraformersmc:modmenu:$modmenuVersion") { - exclude("net.fabricmc") // required to work around duplicate fabric loaders - } - modLocalRuntime(fabricApi.module("fabric-command-api-v2", fabricVersion)) - modLocalRuntime(fabricApi.module("fabric-networking-api-v1", fabricVersion)) - compileOnly("io.gitlab.jfronny:commons:$commonsVersion") - baseCommonsModules.forEach { compileOnly("io.gitlab.jfronny:commons-$it:$commonsVersion") } +// modLocalRuntime(libs.modmenu) { +// exclude("net.fabricmc") // required to work around duplicate fabric loaders +// } + modLocalRuntime("net.fabricmc.fabric-api:fabric-command-api-v2") + modLocalRuntime("net.fabricmc.fabric-api:fabric-networking-api-v1") + modLocalRuntime("net.fabricmc.fabric-api:fabric-resource-loader-v0") + modLocalRuntime("net.fabricmc.fabric-api:fabric-lifecycle-events-v1") + compileOnly(libs.bundles.commons) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..22cef1a --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,27 @@ +# jf-scripts version is in settings.gradle.kts +[versions] +minecraft = "1.20.5" +yarn = "build.1" +fabric-loader = "0.15.10" +fabric-api = "0.97.5+1.20.5" +jf-commons = "1.7-SNAPSHOT" +modmenu = "9.2.0-beta.2" +annotations = "24.1.0" +javapoet = "1.13.0" + +[libraries] +commons = { module = "io.gitlab.jfronny:commons", version.ref="jf-commons" } +commons-http-client = { module = "io.gitlab.jfronny:commons-http-client", version.ref="jf-commons" } +commons-io = { module = "io.gitlab.jfronny:commons-io", version.ref="jf-commons" } +commons-logger = { module = "io.gitlab.jfronny:commons-logger", version.ref="jf-commons" } +commons-serialize = { module = "io.gitlab.jfronny:commons-serialize", version.ref="jf-commons" } +commons-serialize-databind = { module = "io.gitlab.jfronny:commons-serialize-databind", version.ref="jf-commons" } +commons-serialize-json = { module = "io.gitlab.jfronny:commons-serialize-json", version.ref="jf-commons" } +commons-serialize-generator-core = { module = "io.gitlab.jfronny:commons-serialize-generator-core", version.ref="jf-commons" } +commons-unsafe = { module = "io.gitlab.jfronny:commons-unsafe", version.ref="jf-commons" } +modmenu = { module = "com.terraformersmc:modmenu", version.ref="modmenu" } +annotations = { module = "org.jetbrains:annotations", version.ref="annotations" } +javapoet = { module = "com.squareup:javapoet", version.ref="javapoet" } + +[bundles] +commons = ["commons", "commons-http-client", "commons-logger", "commons-io", "commons-serialize", "commons-serialize-databind", "commons-serialize-json"] \ No newline at end of file diff --git a/libjf-base/build.gradle.kts b/libjf-base/build.gradle.kts index 7488be1..2505d09 100644 --- a/libjf-base/build.gradle.kts +++ b/libjf-base/build.gradle.kts @@ -1,18 +1,35 @@ +import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer +import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext +import org.codehaus.plexus.util.IOUtil +import java.io.ByteArrayOutputStream + plugins { id("jfmod.module") } base { - archivesName.set("libjf-base") + archivesName = "libjf-base" } dependencies { - val fabricVersion: String by rootProject.extra - val commonsVersion: String by rootProject.extra - val baseCommonsModules: List by rootProject.extra - include(modImplementation(fabricApi.module("fabric-lifecycle-events-v1", fabricVersion))!!) - shadow("io.gitlab.jfronny:commons:$commonsVersion") - baseCommonsModules.forEach { shadow("io.gitlab.jfronny:commons-$it:$commonsVersion") { - if (it == "logging-slf4j") isTransitive = false - } } + include(modImplementation("net.fabricmc.fabric-api:fabric-lifecycle-events-v1")!!) + shadow(libs.bundles.commons) } + +// workaround to ensure our custom System.LoggerFinder is initialized early +// ideally, we would use the configuration API, but that seems to cause a class loading issue with fabric loader +tasks.shadowJar { + val path = "META-INF/services/java.lang.System\$LoggerFinder" + val field = ServiceFileTransformer::class.java.getDeclaredField("serviceEntries").apply { isAccessible = true } + exclude(path) + transform(object: ServiceFileTransformer() { + private val serviceEntries get() = field.get(this) as MutableMap + override fun transform(context: TransformerContext?) { + super.transform(context) + (serviceEntries[path] as ByteArrayOutputStream).run { + reset() + file("src/main/resources/$path").inputStream().use { IOUtil.copy(it, this) } + } + } + }) +} \ No newline at end of file diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java index 615d518..e60a4f8 100644 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java @@ -1,21 +1,25 @@ package io.gitlab.jfronny.libjf; -import io.gitlab.jfronny.commons.logging.Level; -import io.gitlab.jfronny.commons.logging.Logger; -import io.gitlab.jfronny.commons.logging.slf4j.SLF4JLogger; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; -import io.gitlab.jfronny.libjf.gson.HiddenAnnotationExclusionStrategy; -import net.fabricmc.loader.api.FabricLoader; +import io.gitlab.jfronny.commons.Serializer; +import io.gitlab.jfronny.commons.logger.DelegateLogger; +import io.gitlab.jfronny.commons.logger.HotswapLoggerFinder; +import io.gitlab.jfronny.commons.logger.SystemLoggerPlus; +import io.gitlab.jfronny.commons.serialize.databind.DatabindSerializer; +import io.gitlab.jfronny.commons.serialize.databind.ObjectMapper; +import io.gitlab.jfronny.commons.serialize.json.JsonTransport; +import io.gitlab.jfronny.libjf.log.JULBridge; +import io.gitlab.jfronny.libjf.log.SLF4JPlatformLogger; import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; +import org.slf4j.LoggerFactory; public class LibJf implements PreLaunchEntrypoint { public static final String MOD_ID = "libjf"; - public static final Logger LOGGER = Logger.forName(MOD_ID); + public static final SystemLoggerPlus LOGGER = SystemLoggerPlus.forName(MOD_ID); + public static final ObjectMapper MAPPER = new ObjectMapper(); + public static final JsonTransport JSON_TRANSPORT = new JsonTransport(); static { - HiddenAnnotationExclusionStrategy.register(); - GsonHolders.registerSerializer(); - Logger.setMinimumLevel(FabricLoader.getInstance().isDevelopmentEnvironment() ? Level.TRACE : Level.INFO); + Serializer.setInstance(new DatabindSerializer<>(JSON_TRANSPORT, MAPPER)); } @Override @@ -24,10 +28,35 @@ public class LibJf implements PreLaunchEntrypoint { } private static boolean setup = false; + private static boolean bootstrapped = false; public static void setup() { + bootstrap(); if (!setup) { setup = true; - Logger.registerFactory(SLF4JLogger::new); + // Sometimes a mod using LibJF may want to log before game libraries are initialized. + // For that case, an implementation of System.Logger that redirects to Fabric Loader's logger is used at startup. + // After the game is initialized though, that becomes unnecessary, and we can switch to using SLF4J directly. + // The setup method is called after the game is initialized, so this is the perfect place to do this. + HotswapLoggerFinder.updateAllStrategies((name, module, level) -> new SLF4JPlatformLogger(LoggerFactory.getLogger(name))); + } + } + + public static void bootstrap() { + if (!bootstrapped) { + bootstrapped = true; + // I use System.Logger for logging. + // LibJF ships a service loaded in System.LoggerFinder, which delegates to Fabric Loader and (later on) SLF4J (after setup). + if (LOGGER instanceof DelegateLogger) { + // If the ServiceLoader was able to find this service, any Logger generated will be a DelegateLogger since that class is used by the HotswapLoggerFinder. + // This means that redirection to SLF4J is already set up and we don't need to do anything. + LOGGER.debug("HotswapLoggerFinder was loaded successfully. No need to install JULBridge."); + } else { + // If Fabric Loader is run in production, the ServiceLoader may not pick up this implementation quickly enough. + // In that case, the JUL backend is selected and this cannot be changed, so we need to redirect logs from JUL instead. + // The JULBridge does exactly that by redirecting JUL logs to loggers created by its own instance of EarlyLoggerSetup. + JULBridge.install(); + LOGGER.debug("JULBridge was installed. If available in your launcher, please enable the ServiceLoader fix for better performance."); + } } } } diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ClientOnly.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ClientOnly.java deleted file mode 100644 index d09d721..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ClientOnly.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ClientOnly { -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/FabricLoaderGsonGenerator.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/FabricLoaderGsonGenerator.java deleted file mode 100644 index 8838515..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/FabricLoaderGsonGenerator.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import io.gitlab.jfronny.gson.*; -import net.fabricmc.loader.api.metadata.CustomValue; - -import java.util.Map; - -public class FabricLoaderGsonGenerator { - public static JsonElement toGson(CustomValue customValue) { - if (customValue == null) return null; - return switch (customValue.getType()) { - case OBJECT -> { - JsonObject jo = new JsonObject(); - for (Map.Entry value : customValue.getAsObject()) - jo.add(value.getKey(), toGson(value.getValue())); - yield jo; - } - case ARRAY -> { - JsonArray jo = new JsonArray(); - for (CustomValue value : customValue.getAsArray()) - jo.add(toGson(value)); - yield jo; - } - case STRING -> new JsonPrimitive(customValue.getAsString()); - case NUMBER -> new JsonPrimitive(customValue.getAsNumber()); - case BOOLEAN -> new JsonPrimitive(customValue.getAsBoolean()); - case NULL -> JsonNull.INSTANCE; - }; - } -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/GsonAdapter.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/GsonAdapter.java deleted file mode 100644 index ae8179b..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/GsonAdapter.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import io.gitlab.jfronny.gson.GsonBuilder; - -public interface GsonAdapter { - void apply(GsonBuilder builder); -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java deleted file mode 100644 index 41d99ec..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; -import io.gitlab.jfronny.gson.ExclusionStrategy; -import io.gitlab.jfronny.gson.FieldAttributes; -import net.fabricmc.api.EnvType; -import net.fabricmc.loader.api.FabricLoader; - -public class HiddenAnnotationExclusionStrategy implements ExclusionStrategy { - public boolean shouldSkipClass(Class clazz) { - return false; - } - public boolean shouldSkipField(FieldAttributes fieldAttributes) { - return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT - ? fieldAttributes.getAnnotation(ServerOnly.class) != null - : fieldAttributes.getAnnotation(ClientOnly.class) != null; - } - - public static void register() { - GsonHolders.applyTransform(builder -> builder.setExclusionStrategies(new HiddenAnnotationExclusionStrategy())); - } -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ServerOnly.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ServerOnly.java deleted file mode 100644 index 4523b51..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ServerOnly.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ServerOnly { -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/EarlyLoggerSetup.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/EarlyLoggerSetup.java new file mode 100644 index 0000000..f5a94f9 --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/EarlyLoggerSetup.java @@ -0,0 +1,22 @@ +package io.gitlab.jfronny.libjf.log; + +import io.gitlab.jfronny.commons.logger.HotswapLoggerFinder; +import io.gitlab.jfronny.commons.logger.LeveledLoggerFinder; +import io.gitlab.jfronny.commons.logger.SystemLoggerPlus; +import org.jetbrains.annotations.Nullable; + +public class EarlyLoggerSetup extends LeveledLoggerFinder { + static { + // When a logger is used before the game is initialized, SLF4J is not yet available. + // To support that, this implementation which redirects to Fabric Loader's internal logging abstraction is used instead. + // After the game is initialized, something calls LibJF.setup (usually preEntry), which replaces this factory with a SLF4J-based one. + HotswapLoggerFinder.updateAllStrategies((name, module, level) -> new LoaderPlatformLogger(name)); + } + + private final LeveledLoggerFinder delegate = new HotswapLoggerFinder(); + + @Override + public SystemLoggerPlus getLogger(String name, Module module, @Nullable System.Logger.Level level) { + return delegate.getLogger(name, module, level); + } +} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/JULBridge.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/JULBridge.java new file mode 100644 index 0000000..6afeb0c --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/JULBridge.java @@ -0,0 +1,98 @@ +package io.gitlab.jfronny.libjf.log; + +import io.gitlab.jfronny.commons.StringFormatter; + +import java.text.MessageFormat; +import java.util.Objects; +import java.util.ResourceBundle; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; + +/** + * Based on SLF4JBridgeHandler, modified for LibJF. + */ +public class JULBridge extends Handler { + public static void install() { + var rootLogger = getRootLogger(); + rootLogger.addHandler(new JULBridge()); + boolean bridgeFound = false; + for (Handler handler : rootLogger.getHandlers()) { + if (handler instanceof JULBridge) { + bridgeFound = true; + continue; + } + rootLogger.removeHandler(handler); + } + if (!bridgeFound) { + // Someone is wrapping our handlers. No matter, just add it again. + rootLogger.addHandler(new JULBridge()); + } + } + + private static java.util.logging.Logger getRootLogger() { + return LogManager.getLogManager().getLogger(""); + } + + private JULBridge() { + } + + @Override + public void flush() { + // Do nothing + } + + @Override + public void close() { + // Do nothing + } + + private final Module module = JULBridge.class.getClassLoader().getUnnamedModule(); + private final EarlyLoggerSetup loggerFinder = new EarlyLoggerSetup(); + + private System.Logger getLoggerFor(LogRecord record) { + return loggerFinder.getLogger(Objects.requireNonNullElse(record.getLoggerName(), ""), module); + } + + private static System.Logger.Level getLevel(LogRecord record) { + System.Logger.Level level; + if (record.getLevel().equals(Level.OFF)) level = System.Logger.Level.OFF; + else if (record.getLevel().equals(Level.ALL)) level = System.Logger.Level.ALL; + else if (record.getLevel().intValue() >= Level.SEVERE.intValue()) { + level = System.Logger.Level.ERROR; + } else if (record.getLevel().intValue() >= Level.WARNING.intValue()) { + level = System.Logger.Level.WARNING; + } else if (record.getLevel().intValue() >= Level.INFO.intValue()) { + level = System.Logger.Level.INFO; + } else { + level = System.Logger.Level.DEBUG; + } + return level; + } + + @Override + public void publish(LogRecord record) { + if (record == null) return; + System.Logger logger = getLoggerFor(record); + System.Logger.Level level = getLevel(record); + String message = record.getMessage(); + ResourceBundle bundle = null; + if (message == null) message = ""; + else bundle = record.getResourceBundle(); + Object[] params = record.getParameters(); + Throwable thrown = record.getThrown(); + if (thrown == null) { + logger.log(level, bundle, message, params); + } else { + if (params != null && params.length > 0) { + String[] strings = new String[params.length]; + for (int i = 0; i < params.length; i++) { + strings[i] = StringFormatter.toString(params[i]); + } + message = new MessageFormat(message).format(strings); + } + logger.log(level, bundle, message, thrown); + } + } +} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/LoaderPlatformLogger.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/LoaderPlatformLogger.java new file mode 100644 index 0000000..b184d44 --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/LoaderPlatformLogger.java @@ -0,0 +1,57 @@ +package io.gitlab.jfronny.libjf.log; + +import io.gitlab.jfronny.commons.logger.CompactLogger; +import net.fabricmc.loader.impl.util.log.Log; +import net.fabricmc.loader.impl.util.log.LogCategory; +import net.fabricmc.loader.impl.util.log.LogLevel; + +public class LoaderPlatformLogger implements CompactLogger { + private final LogCategory category; + + public LoaderPlatformLogger(String context, String... names) { + this.category = LogCategory.createCustom(context, names); + } + + @Override + public String getName() { + return category.name; + } + + @Override + public Level getLevel() { + for (Level value : Level.values()) { + if (value == Level.ALL || value == Level.OFF) continue; + if (isLoggable(value)) return value; + } + return Level.INFO; // should not happen, but if it does, INFO is a reasonable default + } + + @Override + public void log(Level level, String message) { + Log.log(jplLevelToFabricLevel(level), category, message); + } + + @Override + public void log(Level level, String message, Throwable throwable) { + Log.log(jplLevelToFabricLevel(level), category, message, throwable); + } + + @Override + public boolean isLoggable(Level level) { + if (level == Level.ALL) return true; + if (level == Level.OFF) return false; + return Log.shouldLog(jplLevelToFabricLevel(level), category); + } + + private LogLevel jplLevelToFabricLevel(Level jplLevel) { + return switch (jplLevel) { + case TRACE -> LogLevel.TRACE; + case DEBUG -> LogLevel.DEBUG; + case INFO -> LogLevel.INFO; + case WARNING -> LogLevel.WARN; + case ERROR -> LogLevel.ERROR; + // should not happen, but if it does, INFO is a reasonable default + default -> LogLevel.INFO; + }; + } +} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/SLF4JPlatformLogger.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/SLF4JPlatformLogger.java new file mode 100644 index 0000000..7514040 --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/log/SLF4JPlatformLogger.java @@ -0,0 +1,116 @@ +package io.gitlab.jfronny.libjf.log; + +import io.gitlab.jfronny.commons.StringFormatter; +import io.gitlab.jfronny.commons.logger.CompactLogger; +import org.slf4j.Logger; +import org.slf4j.spi.CallerBoundaryAware; +import org.slf4j.spi.LoggingEventBuilder; + +import java.text.MessageFormat; +import java.util.Objects; +import java.util.ResourceBundle; + +/** + * A {@link System.Logger} implementation that delegates to SLF4J. + * Adapted from slf4j-jdk-platform-logging for use in LibJF. + * + * @author Ceki Gülcü + * @author JFronny + */ +public class SLF4JPlatformLogger implements CompactLogger { + private static final String PRESUMED_CALLER_BOUNDARY = System.Logger.class.getName(); + private final Logger slf4jLogger; + + public SLF4JPlatformLogger(Logger logger) { + slf4jLogger = Objects.requireNonNull(logger); + } + + @Override + public String getName() { + return slf4jLogger.getName(); + } + + @Override + public Level getLevel() { + if (slf4jLogger.isTraceEnabled()) return Level.TRACE; + else if (slf4jLogger.isDebugEnabled()) return Level.DEBUG; + else if (slf4jLogger.isInfoEnabled()) return Level.INFO; + else if (slf4jLogger.isWarnEnabled()) return Level.WARNING; + else if (slf4jLogger.isErrorEnabled()) return Level.ERROR; + else return Level.INFO; // should not happen, but if it does, INFO is a reasonable default + } + + @Override + public boolean isLoggable(Level level) { + if (level == Level.ALL) return true; + if (level == Level.OFF) return false; + return slf4jLogger.isEnabledForLevel(jplLevelToSLF4JLevel(level)); + } + + private org.slf4j.event.Level jplLevelToSLF4JLevel(Level jplLevel) { + return switch (jplLevel) { + case TRACE -> org.slf4j.event.Level.TRACE; + case DEBUG -> org.slf4j.event.Level.DEBUG; + case INFO -> org.slf4j.event.Level.INFO; + case WARNING -> org.slf4j.event.Level.WARN; + case ERROR -> org.slf4j.event.Level.ERROR; + // should not happen, but if it does, INFO is a reasonable default + default -> org.slf4j.event.Level.INFO; + }; + } + + @Override + public void log(Level level, String message) { + log(level, null, message, null, (Object[]) null); + } + + @Override + public void log(Level level, String message, Throwable throwable) { + log(level, null, message, throwable, (Object[]) null); + } + + @Override + public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) { + log(level, bundle, msg, thrown, (Object[]) null); + } + + @Override + public void log(Level level, ResourceBundle bundle, String format, Object... params) { + log(level, bundle, format, null, params); + } + + private void log(Level jplLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) { + if (jplLevel == Level.OFF) return; + if (jplLevel == Level.ALL) { + performLog(org.slf4j.event.Level.TRACE, bundle, msg, thrown, params); + return; + } + + org.slf4j.event.Level slf4jLevel = jplLevelToSLF4JLevel(jplLevel); + if (slf4jLogger.isEnabledForLevel(slf4jLevel)) { + performLog(slf4jLevel, bundle, msg, thrown, params); + } + } + + private void performLog(org.slf4j.event.Level slf4jLevel, ResourceBundle bundle, String msg, Throwable thrown, Object... params) { + String message = CompactLogger.getResourceStringOrMessage(bundle, msg); + LoggingEventBuilder leb = slf4jLogger.makeLoggingEventBuilder(slf4jLevel); + if (thrown != null) { + leb = leb.setCause(thrown); + } + if (params != null && params.length > 0) { + // add the arguments to the logging event for possible processing by the backend + String[] strings = new String[params.length]; + for (int i = 0; i < params.length; i++) { + leb = leb.addArgument(params[i]); + strings[i] = StringFormatter.toString(params[i]); + } + // The JDK uses a different formatting convention. We must invoke it now. + message = new MessageFormat(message).format(strings); + } + if (leb instanceof CallerBoundaryAware cba) { + cba.setCallerBoundary(PRESUMED_CALLER_BOUNDARY); + } + leb.log(message); + } +} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/FabricLoaderDataMapper.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/FabricLoaderDataMapper.java new file mode 100644 index 0000000..8eda0f6 --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/FabricLoaderDataMapper.java @@ -0,0 +1,30 @@ +package io.gitlab.jfronny.libjf.serialize; + +import io.gitlab.jfronny.commons.serialize.emulated.DataElement; +import net.fabricmc.loader.api.metadata.CustomValue; + +import java.util.Map; + +public class FabricLoaderDataMapper { + public static DataElement toGson(CustomValue customValue) { + if (customValue == null) return null; + return switch (customValue.getType()) { + case OBJECT -> { + DataElement.Object jo = new DataElement.Object(); + for (Map.Entry value : customValue.getAsObject()) + jo.members().put(value.getKey(), toGson(value.getValue())); + yield jo; + } + case ARRAY -> { + DataElement.Array jo = new DataElement.Array(); + for (CustomValue value : customValue.getAsArray()) + jo.elements().add(toGson(value)); + yield jo; + } + case STRING -> new DataElement.Primitive.String(customValue.getAsString()); + case NUMBER -> new DataElement.Primitive.Number(customValue.getAsNumber()); + case BOOLEAN -> new DataElement.Primitive.Boolean(customValue.getAsBoolean()); + case NULL -> new DataElement.Null(); + }; + } +} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/SerializationMode.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/SerializationMode.java new file mode 100644 index 0000000..f57f934 --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/SerializationMode.java @@ -0,0 +1,26 @@ +package io.gitlab.jfronny.libjf.serialize; + +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.SerializeWriter; +import io.gitlab.jfronny.commons.serialize.json.JsonWriter; + +public class SerializationMode { + public static > Reader asConfig(Reader reader) { + reader.setLenient(true) + .setSerializeSpecialFloatingPointValues(true); + return reader; + } + + public static > Writer asConfig(Writer writer) { + writer.setLenient(true) + .setSerializeSpecialFloatingPointValues(true) + .setSerializeNulls(true); + if (writer instanceof JsonWriter jw) { + jw.setIndent(" ") + .setNewline("\n") + .setOmitQuotes(true) + .setCommentUnexpectedNames(true); + } + return writer; + } +} diff --git a/libjf-base/src/main/resources/META-INF/services/java.lang.System$LoggerFinder b/libjf-base/src/main/resources/META-INF/services/java.lang.System$LoggerFinder new file mode 100644 index 0000000..32d3705 --- /dev/null +++ b/libjf-base/src/main/resources/META-INF/services/java.lang.System$LoggerFinder @@ -0,0 +1 @@ +io.gitlab.jfronny.libjf.log.EarlyLoggerSetup \ No newline at end of file diff --git a/libjf-config-commands/build.gradle.kts b/libjf-config-commands/build.gradle.kts index 695d0e8..170eaad 100644 --- a/libjf-config-commands/build.gradle.kts +++ b/libjf-config-commands/build.gradle.kts @@ -5,12 +5,11 @@ plugins { } base { - archivesName.set("libjf-config-commands") + archivesName = "libjf-config-commands" } dependencies { - val fabricVersion: String by rootProject.extra api(devProject(":libjf-base")) api(devProject(":libjf-config-core-v2")) - include(modImplementation(fabricApi.module("fabric-command-api-v2", fabricVersion))!!) + include(modImplementation("net.fabricmc.fabric-api:fabric-command-api-v2")!!) } diff --git a/libjf-config-compiler-plugin-v2/build.gradle.kts b/libjf-config-compiler-plugin-v2/build.gradle.kts index 3ce4e18..e0a2de9 100644 --- a/libjf-config-compiler-plugin-v2/build.gradle.kts +++ b/libjf-config-compiler-plugin-v2/build.gradle.kts @@ -14,16 +14,13 @@ repositories { } dependencies { - val commonsVersion: String by rootProject.extra - val gsonCompileVersion: String by rootProject.extra - val annotationsVersion: String by rootProject.extra - val javapoetVersion: String by rootProject.extra - implementation("io.gitlab.jfronny.gson:gson-compile-processor-core:$gsonCompileVersion") + implementation(libs.commons.serialize.generator.core) implementation(devProject(":libjf-config-core-v2")) - implementation("org.jetbrains:annotations:$annotationsVersion") - implementation("io.gitlab.jfronny:commons:$commonsVersion") - implementation("io.gitlab.jfronny:commons-serialize-gson:$commonsVersion") - implementation("com.squareup:javapoet:$javapoetVersion") + implementation(libs.annotations) + implementation(libs.commons) + implementation(libs.commons.serialize.databind) + implementation(libs.commons.serialize.json) + implementation(libs.javapoet) testAnnotationProcessor(sourceSets.main.get().output) configurations.testAnnotationProcessor.get().extendsFrom(configurations.implementation.get()) } diff --git a/libjf-config-compiler-plugin-v2/src/main/java/io/gitlab/jfronny/libjf/config/plugin/ConfigProcessor.java b/libjf-config-compiler-plugin-v2/src/main/java/io/gitlab/jfronny/libjf/config/plugin/ConfigProcessor.java index e2568b1..9bdc876 100644 --- a/libjf-config-compiler-plugin-v2/src/main/java/io/gitlab/jfronny/libjf/config/plugin/ConfigProcessor.java +++ b/libjf-config-compiler-plugin-v2/src/main/java/io/gitlab/jfronny/libjf/config/plugin/ConfigProcessor.java @@ -2,8 +2,8 @@ package io.gitlab.jfronny.libjf.config.plugin; import com.squareup.javapoet.*; import io.gitlab.jfronny.commons.StringFormatter; -import io.gitlab.jfronny.gson.compile.processor.core.*; -import io.gitlab.jfronny.gson.reflect.TypeToken; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken; +import io.gitlab.jfronny.commons.serialize.generator.core.*; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v2.dsl.DSL; import io.gitlab.jfronny.libjf.config.api.v2.type.Type; diff --git a/libjf-config-core-v2/build.gradle.kts b/libjf-config-core-v2/build.gradle.kts index 794dfb7..63ee27f 100644 --- a/libjf-config-core-v2/build.gradle.kts +++ b/libjf-config-core-v2/build.gradle.kts @@ -5,11 +5,10 @@ plugins { } base { - archivesName.set("libjf-config-core-v2") + archivesName = "libjf-config-core-v2" } dependencies { - val modmenuVersion: String by rootProject.extra api(devProject(":libjf-base")) - modCompileOnly("com.terraformersmc:modmenu:$modmenuVersion") + modCompileOnly(libs.modmenu) } diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigHolder.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigHolder.java index 2d43a2e..1ff42bd 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigHolder.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigHolder.java @@ -1,6 +1,5 @@ package io.gitlab.jfronny.libjf.config.api.v2; -import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.impl.ConfigHolderImpl; import java.nio.file.Path; @@ -15,7 +14,6 @@ public interface ConfigHolder { * @return The config holder */ static ConfigHolder getInstance() { - LibJf.setup(); return ConfigHolderImpl.INSTANCE; } diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java index a6c880a..e60eea1 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java @@ -1,6 +1,7 @@ package io.gitlab.jfronny.libjf.config.api.v2; -import io.gitlab.jfronny.gson.stream.*; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.SerializeWriter; import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.dsl.DslEntryInfo; import org.jetbrains.annotations.ApiStatus; @@ -68,13 +69,13 @@ public interface EntryInfo { * Set this entry's value to that of the element * @param reader The reader to read from */ - void loadFromJson(JsonReader reader) throws IOException, IllegalAccessException; + > void loadFromJson(Reader reader) throws TEx, IllegalAccessException; /** * Write the currently cached value to the writer * @param writer The writer to write to */ - void writeTo(JsonWriter writer, String translationPrefix) throws IOException, IllegalAccessException; + > void writeTo(Writer writer, String translationPrefix) throws TEx, IllegalAccessException; /** * @return Get the width for this entry diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java index 31c752c..2791840 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java @@ -1,10 +1,10 @@ package io.gitlab.jfronny.libjf.config.api.v2.dsl; -import io.gitlab.jfronny.gson.stream.JsonReader; +import io.gitlab.jfronny.commons.serialize.SerializeReader; import java.io.IOException; @FunctionalInterface public interface Migration { - void apply(JsonReader reader) throws IOException; + > void apply(Reader reader) throws IOException; } diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java index e6b8a0a..75223df 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java @@ -1,16 +1,17 @@ package io.gitlab.jfronny.libjf.config.impl; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; +import io.gitlab.jfronny.commons.serialize.emulated.DataElement; import io.gitlab.jfronny.libjf.config.api.v2.Category; import io.gitlab.jfronny.libjf.config.api.v2.JfConfig; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; -import io.gitlab.jfronny.libjf.gson.FabricLoaderGsonGenerator; +import io.gitlab.jfronny.libjf.serialize.FabricLoaderDataMapper; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.metadata.CustomValue; import org.jetbrains.annotations.Nullable; import java.util.LinkedList; import java.util.List; +import java.util.Map; import static io.gitlab.jfronny.libjf.config.impl.ConfigCore.MODULE_ID; @@ -43,11 +44,30 @@ public class AuxiliaryMetadata { cv = cv.getAsObject().get("config"); } } - if (cv != null) metaRef.meta = GsonHolders.API.getGson().fromJson(FabricLoaderGsonGenerator.toGson(cv), AuxiliaryMetadata.class); + if (cv != null) metaRef.meta = read(FabricLoaderDataMapper.toGson(cv)); }); return metaRef.meta; } + public static AuxiliaryMetadata read(DataElement data) { + if (!(data instanceof DataElement.Object obj)) throw new IllegalArgumentException("AuxiliaryMetadata must be an object"); + AuxiliaryMetadata meta = new AuxiliaryMetadata(); + for (Map.Entry entry : obj.members().entrySet()) { + switch (entry.getKey()) { + case "referencedConfigs" -> { + if (!(entry.getValue() instanceof DataElement.Array arr)) throw new IllegalArgumentException("referencedConfigs must be an array"); + meta.referencedConfigs = new LinkedList<>(); + arr.elements().forEach(element -> { + if (!(element instanceof DataElement.Primitive.String str)) throw new IllegalArgumentException("referencedConfigs must be an array of strings"); + meta.referencedConfigs.add(str.value()); + }); + } + default -> throw new IllegalArgumentException("Unknown key in AuxiliaryMetadata: " + entry.getKey()); + } + } + return meta; + } + public List referencedConfigs; public void applyTo(CategoryBuilder builder) { diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java index 4babb6e..1c7f816 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; +import io.gitlab.jfronny.commons.serialize.SerializeReader; import io.gitlab.jfronny.commons.throwable.Coerce; -import io.gitlab.jfronny.gson.stream.JsonReader; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; @@ -21,7 +21,8 @@ public class CategoryBuilderImpl> i public final Map> presets = new LinkedHashMap<>(); public final List>> referencedConfigs = new LinkedList<>(); public final List> verifiers = new LinkedList<>(); - public final Map> migrations = new LinkedHashMap<>(); + @SuppressWarnings("rawtypes") // recursive types aren't really needed here + public final Map> migrations = new LinkedHashMap<>(); private boolean built = false; public CategoryBuilderImpl(String id, String categoryPath) { @@ -174,7 +175,7 @@ public class CategoryBuilderImpl> i public Builder addMigration(String element, Migration migration) { checkBuilt(); if (migrations.containsKey(element)) LibJf.LOGGER.warn("Duplicate migration registered for " + categoryPath + id + ": " + element + ", overriding"); - migrations.put(element, Coerce.consumer(migration::apply).addHandler(e -> LibJf.LOGGER.error("Could not apply migration for " + element, e))); + migrations.put(element, Coerce.consumer(migration::apply).addHandler(e -> LibJf.LOGGER.error("Could not apply migration for " + element, e))); return asBuilder(); } diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java index 26c9389..98ec729 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java @@ -1,12 +1,14 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; -import io.gitlab.jfronny.gson.*; -import io.gitlab.jfronny.gson.stream.*; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.Token; +import io.gitlab.jfronny.commons.serialize.json.JsonReader; +import io.gitlab.jfronny.commons.serialize.json.JsonWriter; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.impl.entrypoint.JfConfigSafe; import io.gitlab.jfronny.libjf.config.impl.watch.JfConfigWatchService; +import io.gitlab.jfronny.libjf.serialize.SerializationMode; import java.io.*; import java.nio.file.Files; @@ -19,7 +21,8 @@ public class DefaultConfigIO { // Actions cannot be cached since entries can change if (Files.exists(path)) { try (BufferedReader br = Files.newBufferedReader(path); - JsonReader jr = GsonHolders.CONFIG.getGson().newJsonReader(br)) { + JsonReader jr = new JsonReader(br)) { + SerializationMode.asConfig(jr); runActions(id, createActions(c), jr); } catch (Exception e) { LibJf.LOGGER.error("Could not read config for " + id, e); @@ -29,21 +32,21 @@ public class DefaultConfigIO { }); } - record Action(Consumer task, boolean required) { - public Action(Consumer task) { + record Action(Consumer task, boolean required) { + public Action(Consumer task) { this(task, true); } } - private static void runActions(String id, Map actions, JsonReader reader) { + private static > void runActions(String id, Map actions, Reader reader) { try { - if (reader.peek() != JsonToken.BEGIN_OBJECT) { + if (reader.peek() != Token.BEGIN_OBJECT) { LibJf.LOGGER.error("Invalid config: Not a JSON object for " + id); return; } Set appeared = new HashSet<>(); reader.beginObject(); - while (reader.peek() != JsonToken.END_OBJECT) { + while (reader.peek() != Token.END_OBJECT) { String name = reader.nextName(); if (!actions.containsKey(name)) { LibJf.LOGGER.warn("Unrecognized key in config for " + id + ": " + name); @@ -61,8 +64,8 @@ public class DefaultConfigIO { LibJf.LOGGER.error("Missing entry in config for " + id + ": " + name); } }); - } catch (IOException e) { - throw new JsonParseException("Could not read config", e); + } catch (Exception e) { + throw new IllegalStateException("Could not read config", e); } } @@ -71,7 +74,7 @@ public class DefaultConfigIO { category.getEntries().forEach(entry -> actions.putIfAbsent(entry.getName(), new Action(reader -> { try { entry.loadFromJson(reader); - } catch (IllegalAccessException | IOException e) { + } catch (Exception e) { LibJf.LOGGER.error("Could not set config entry value of " + entry.getName(), e); } }))); @@ -91,7 +94,8 @@ public class DefaultConfigIO { public static Consumer writer(String id) { return c -> c.getFilePath().ifPresent(path -> JfConfigWatchService.lock(path, () -> { try (BufferedWriter bw = Files.newBufferedWriter(path); - JsonWriter jw = GsonHolders.CONFIG.getGson().newJsonWriter(bw)) { + JsonWriter jw = new JsonWriter(bw)) { + SerializationMode.asConfig(jw); writeTo(jw, c); } catch (Exception e) { LibJf.LOGGER.error("Could not write config for " + id, e); diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java index 9eb471e..64b8255 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.gson.stream.JsonReader; +import io.gitlab.jfronny.commons.serialize.SerializeReader; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; import org.jetbrains.annotations.ApiStatus; @@ -17,7 +17,7 @@ public class DslConfigCategory implements ConfigCategory { private final List> entries; private final Map presets; private final List>> referencedConfigs; - @ApiStatus.Internal public final Map> migrations; + @ApiStatus.Internal public final Map> migrations; private final Map categories; private final Supplier root; private final List> verifiers; @@ -31,7 +31,7 @@ public class DslConfigCategory implements ConfigCategory { List> categories, Supplier root, List> verifiers, - Map> migrations) { + Map> migrations) { this.id = id; this.categoryPath = categoryPath; this.translationPrefix = translationPrefix; diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java index 6e7a294..1e7990d 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.gson.stream.JsonReader; +import io.gitlab.jfronny.commons.serialize.SerializeReader; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; import org.jetbrains.annotations.Nullable; @@ -23,7 +23,7 @@ public class DslConfigInstance extends DslConfigCategory implements ConfigInstan List> categories, Supplier root, List> verifiers, - Map> migrations, + Map> migrations, Consumer load, Consumer write, @Nullable Path path) { diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java index 81c4f43..7a2454d 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java @@ -1,16 +1,19 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; +import io.gitlab.jfronny.commons.Serializer; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.SerializeWriter; +import io.gitlab.jfronny.commons.serialize.Token; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken; import io.gitlab.jfronny.commons.throwable.ThrowingConsumer; import io.gitlab.jfronny.commons.throwable.ThrowingSupplier; -import io.gitlab.jfronny.gson.stream.*; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.Entry; import io.gitlab.jfronny.libjf.config.api.v2.EntryInfo; import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.entrypoint.JfConfigSafe; -import java.io.IOException; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Objects; @@ -127,38 +130,42 @@ public class DslEntryInfo implements EntryInfo { } @Override - public void loadFromJson(JsonReader reader) throws IOException, IllegalAccessException { + public > void loadFromJson(Reader reader) throws TEx, IllegalAccessException { var next = reader.peek(); if (type.isBool()) { - if (next == JsonToken.BOOLEAN) setUnchecked(reader.nextBoolean()); + if (next == Token.BOOLEAN) setUnchecked(reader.nextBoolean()); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected boolean but got " + next); } else if (type.isString()) { - if (next == JsonToken.STRING || next == JsonToken.NUMBER) setUnchecked(reader.nextString()); - else if (next == JsonToken.BOOLEAN) setUnchecked(Boolean.toString(reader.nextBoolean())); - else if (next == JsonToken.NULL) { + if (next == Token.STRING || next == Token.NUMBER) setUnchecked(reader.nextString()); + else if (next == Token.BOOLEAN) setUnchecked(Boolean.toString(reader.nextBoolean())); + else if (next == Token.NULL) { reader.nextNull(); setUnchecked(null); } else LibJf.LOGGER.error("Unexpected value for " + name + ": expected string but got " + next); } else if (type.isInt()) { - if (next == JsonToken.NUMBER) setUnchecked(reader.nextInt()); + if (next == Token.NUMBER) setUnchecked(reader.nextInt()); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isLong()) { - if (next == JsonToken.NUMBER) setUnchecked(reader.nextLong()); + if (next == Token.NUMBER) setUnchecked(reader.nextLong()); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isDouble()) { - if (next == JsonToken.NUMBER) { + if (next == Token.NUMBER) { setUnchecked(reader.nextDouble()); } else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isFloat()) { - if (next == JsonToken.NUMBER) setUnchecked((float) reader.nextDouble()); + if (next == Token.NUMBER) setUnchecked((float) reader.nextDouble()); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isEnum()) { Type.TEnum e = (Type.TEnum) type; - if (next == JsonToken.STRING) setUnchecked(e.optionForString(reader.nextString())); + if (next == Token.STRING) setUnchecked(e.optionForString(reader.nextString())); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected string but got " + next); } else { - setValue(GsonHolders.CONFIG.getGson().fromJson(reader, type.asClass())); + try { + setValue((T) LibJf.MAPPER.getAdapter(TypeToken.get(type.asClass())).deserialize(reader)); + } catch (MalformedDataException e) { + LibJf.LOGGER.error("Could not read " + name, e); + } } } @@ -169,7 +176,7 @@ public class DslEntryInfo implements EntryInfo { } @Override - public void writeTo(JsonWriter writer, String translationPrefix) throws IOException, IllegalAccessException { + public > void writeTo(Writer writer, String translationPrefix) throws TEx, IllegalAccessException { T value = getValue(); String commentText; if ((commentText = JfConfigSafe.TRANSLATION_SUPPLIER.apply(translationPrefix + getName() + ".tooltip")) != null) { @@ -179,7 +186,11 @@ public class DslEntryInfo implements EntryInfo { writer.comment("Valid: [" + Arrays.stream(((Type.TEnum)type).options()).map(Objects::toString).collect(Collectors.joining(", ")) + "]"); } writer.name(name); - GsonHolders.CONFIG.getGson().toJson(value, Objects.requireNonNullElse(type.asClass(), String.class), writer); + try { + LibJf.MAPPER.getAdapter((TypeToken) TypeToken.get(Objects.requireNonNullElse(type.asClass(), String.class))).serialize(value, writer); + } catch (MalformedDataException e) { + LibJf.LOGGER.error("Could not write " + name, e); + } } @Override diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/entrypoint/JfConfigSafe.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/entrypoint/JfConfigSafe.java index 948dffe..6fcd3bb 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/entrypoint/JfConfigSafe.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/entrypoint/JfConfigSafe.java @@ -26,7 +26,13 @@ public class JfConfigSafe implements PreLaunchEntrypoint { } } TRANSLATION_SUPPLIER = s -> { - String translated = Language.getInstance().get(s); + String translated; + try { + translated = Language.getInstance().get(s); + } catch (Throwable t) { + LibJf.LOGGER.debug("Failed to translate key " + s, t); + return null; + } return translated.equals(s) ? null : translated; }; } diff --git a/libjf-config-network-v0/build.gradle.kts b/libjf-config-network-v0/build.gradle.kts index 710c308..c96e879 100644 --- a/libjf-config-network-v0/build.gradle.kts +++ b/libjf-config-network-v0/build.gradle.kts @@ -5,15 +5,13 @@ plugins { } base { - archivesName.set("libjf-config-network-v0") + archivesName = "libjf-config-network-v0" } dependencies { - val fabricVersion: String by rootProject.extra - val modmenuVersion: String by rootProject.extra api(devProject(":libjf-base")) api(devProject(":libjf-config-core-v2")) - modCompileOnly("com.terraformersmc:modmenu:$modmenuVersion") - include(modImplementation(fabricApi.module("fabric-networking-api-v1", fabricVersion))!!) - include(modImplementation(fabricApi.module("fabric-command-api-v2", fabricVersion))!!) + modCompileOnly(libs.modmenu) + include(modImplementation("net.fabricmc.fabric-api:fabric-networking-api-v1")!!) + include(modImplementation("net.fabricmc.fabric-api:fabric-command-api-v2")!!) } diff --git a/libjf-config-network-v0/src/client/java/io/gitlab/jfronny/libjf/config/impl/network/client/JfConfigNetworkClient.java b/libjf-config-network-v0/src/client/java/io/gitlab/jfronny/libjf/config/impl/network/client/JfConfigNetworkClient.java index 5b27ffe..4033549 100644 --- a/libjf-config-network-v0/src/client/java/io/gitlab/jfronny/libjf/config/impl/network/client/JfConfigNetworkClient.java +++ b/libjf-config-network-v0/src/client/java/io/gitlab/jfronny/libjf/config/impl/network/client/JfConfigNetworkClient.java @@ -3,21 +3,24 @@ package io.gitlab.jfronny.libjf.config.impl.network.client; import io.gitlab.jfronny.libjf.config.impl.network.packet.ConfigurationCompletePacket; import io.gitlab.jfronny.libjf.config.impl.network.packet.ConfigurationPacket; import io.gitlab.jfronny.libjf.config.impl.network.RequestRouter; +import io.gitlab.jfronny.libjf.config.impl.network.packet.RequestPacket; +import io.gitlab.jfronny.libjf.config.impl.network.packet.ResponsePacket; import net.fabricmc.fabric.api.client.networking.v1.*; public class JfConfigNetworkClient { public static boolean isAvailable = false; public static void initialize() { + RequestRouter.initialize(); JfConfigNetworkCommands.initialize(); - ClientPlayNetworking.registerGlobalReceiver(RequestRouter.RESPONSE_ID, (client, handler, buf, responseSender) -> { - RequestRouter.acceptResponse(buf, responseSender); + ClientPlayNetworking.registerGlobalReceiver(ResponsePacket.ID, (payload, context) -> { + RequestRouter.acceptResponse(payload, context.responseSender()); }); - ClientPlayNetworking.registerGlobalReceiver(RequestRouter.REQUEST_ID, (client, handler, buf, responseSender) -> { - RequestRouter.acceptRequest(buf, responseSender); + ClientPlayNetworking.registerGlobalReceiver(RequestPacket.ID, (payload, context) -> { + RequestRouter.acceptRequest(payload, context.responseSender()); }); - ClientConfigurationNetworking.registerGlobalReceiver(ConfigurationPacket.PACKET_TYPE, (packet, responseSender) -> { - isAvailable = packet.version() == RequestRouter.PROTOCOL_VERSION; // Handshake possible? - responseSender.sendPacket(new ConfigurationCompletePacket()); + ClientConfigurationNetworking.registerGlobalReceiver(ConfigurationPacket.ID, (payload, context) -> { + isAvailable = payload.version() == RequestRouter.PROTOCOL_VERSION; // Handshake possible? + context.responseSender().sendPacket(new ConfigurationCompletePacket()); }); ClientConfigurationConnectionEvents.INIT.register((handler, client) -> { isAvailable = false; // Reset for new server connection diff --git a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/RequestRouter.java b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/RequestRouter.java index a3e9347..f3faecb 100644 --- a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/RequestRouter.java +++ b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/RequestRouter.java @@ -1,84 +1,93 @@ package io.gitlab.jfronny.libjf.config.impl.network; import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.config.impl.network.packet.ConfigurationCompletePacket; +import io.gitlab.jfronny.libjf.config.impl.network.packet.ConfigurationPacket; +import io.gitlab.jfronny.libjf.config.impl.network.packet.RequestPacket; +import io.gitlab.jfronny.libjf.config.impl.network.packet.ResponsePacket; +import io.netty.buffer.ByteBuf; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; import java.util.*; public class RequestRouter { public static final String MOD_ID = "libjf-config-network-v0"; - public static final Identifier RESPONSE_ID = new Identifier(MOD_ID, "response"); - public static final Identifier REQUEST_ID = new Identifier(MOD_ID, "request"); public static int PROTOCOL_VERSION = 1; private static final Map persistendHandlers = new HashMap<>(); private static final Map currentRequests = new HashMap<>(); //TODO implement timeout and prune old requests private static final Random random = new Random(); - public static void acceptResponse(PacketByteBuf buf, PacketSender responseSender) { - Request request = currentRequests.remove(buf.readLong()); + public static void initialize() { + PayloadTypeRegistry.playC2S().register(RequestPacket.ID, RequestPacket.CODEC); + PayloadTypeRegistry.playS2C().register(RequestPacket.ID, RequestPacket.CODEC); + PayloadTypeRegistry.playC2S().register(ResponsePacket.ID, ResponsePacket.CODEC); + PayloadTypeRegistry.playS2C().register(ResponsePacket.ID, ResponsePacket.CODEC); + PayloadTypeRegistry.configurationS2C().register(ConfigurationPacket.ID, ConfigurationPacket.CODEC); + PayloadTypeRegistry.configurationC2S().register(ConfigurationCompletePacket.ID, ConfigurationCompletePacket.CODEC); + } + + public static void acceptResponse(ResponsePacket response, PacketSender responseSender) { + Request request = currentRequests.remove(response.request()); if (request != null) { - switch (buf.readInt()) { - case 0 -> request.responseHandler.onSuccess(buf); + switch (response.status()) { + case 0 -> request.responseHandler.onSuccess(response.aux()); case 1 -> request.responseHandler.onNotFound(); case 2 -> request.responseHandler.onDeny(); - case 3 -> request.responseHandler.onFailure(buf.readString()); + case 3 -> request.responseHandler.onFailure(response.aux().readString()); default -> request.responseHandler.onFailure("Unrecognized error received"); } } } - public static void acceptRequest(PacketByteBuf buf, PacketSender responseSender) { - PacketByteBuf resp = PacketByteBufs.create(); - long id = buf.readLong(); - resp.writeLong(id); + public static void acceptRequest(RequestPacket request, PacketSender responseSender) { + long id = request.request(); + int mode = 3; + PacketByteBuf aux = PacketByteBufs.create(); try { - if (buf.readBoolean()) { + if (request.parent() == null) { // persistent - handleRequest(resp, id, buf, persistendHandlers.get(buf.readString())); + mode = handleRequest(aux, id, request.aux(), persistendHandlers.get(request.name())); } else { // followup - Request parent = currentRequests.get(buf.readLong()); + Request parent = currentRequests.get(request.parent()); if (parent == null) { - resp.writeInt(1); + mode = 1; } else { - String key = buf.readString(); + String key = request.name(); RequestHandler handler = parent.temporaryHandlers.get(key); if (handler == null) handler = persistendHandlers.get(key); - handleRequest(resp, id, buf, handler); + mode = handleRequest(aux, id, request.aux(), handler); } } } catch (Throwable t) { LibJf.LOGGER.error("Cannot complete request", t); - resp.writeInt(3); - resp.writeString(t.getMessage() == null ? "null" : t.getMessage()); + aux.clear(); + aux.writeString(t.getMessage() == null ? "null" : t.getMessage()); } finally { - responseSender.sendPacket(RESPONSE_ID, resp); + responseSender.sendPacket(new ResponsePacket(id, mode, aux)); } } - private static void handleRequest(PacketByteBuf resp, long id, PacketByteBuf buf, RequestHandler handler) throws Throwable { + private static int handleRequest(ByteBuf aux, long id, PacketByteBuf buf, RequestHandler handler) throws Throwable { if (handler == null) { - resp.writeInt(1); + return 1; } else { PacketByteBuf response = handler.handle( buf, (responseSender, name, body, responseHandler, temporaryHandlers) -> RequestRouter.sendRequest(responseSender, id, name, body, responseHandler, temporaryHandlers) ); - resp.writeInt(0); - if (response != null) resp.writeBytes(response.copy()); + if (response != null) aux.writeBytes(response.copy()); + return 0; } } - public static void deny(PacketByteBuf buf, PacketSender responseSender) { - PacketByteBuf resp = PacketByteBufs.create(); - resp.writeLong(buf.readLong()); - resp.writeInt(2); - responseSender.sendPacket(RESPONSE_ID, resp); + public static void deny(long id, PacketSender responseSender) { + responseSender.sendPacket(new ResponsePacket(id, 2, PacketByteBufs.empty())); } public static void registerHandler(String name, RequestHandler handler) { @@ -98,15 +107,7 @@ public class RequestRouter { } while (keys.contains(id)); currentRequests.put(id, new Request(temporaryHandlers, responseHandler)); } - PacketByteBuf req = PacketByteBufs.create(); - req.writeLong(id); - req.writeBoolean(parent == null); - if (parent != null) req.writeLong(parent); - req.writeString(name); - if (body != null) { - req.writeBytes(body.copy()); - } - responseSender.sendPacket(REQUEST_ID, req); + responseSender.sendPacket(new RequestPacket(id, parent, name, PacketByteBufs.copy(body))); } private record Request(Map temporaryHandlers, ResponseHandler responseHandler) {} diff --git a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ConfigurationCompletePacket.java b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ConfigurationCompletePacket.java index 19a15d6..1e00ba5 100644 --- a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ConfigurationCompletePacket.java +++ b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ConfigurationCompletePacket.java @@ -1,25 +1,25 @@ package io.gitlab.jfronny.libjf.config.impl.network.packet; import io.gitlab.jfronny.libjf.config.impl.network.RequestRouter; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; -import net.fabricmc.fabric.api.networking.v1.PacketType; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; -public record ConfigurationCompletePacket() implements FabricPacket { - public static final Identifier ID = new Identifier(RequestRouter.MOD_ID, "handshake_complete"); - public static final PacketType PACKET_TYPE = PacketType.create(ID, ConfigurationCompletePacket::new); +public record ConfigurationCompletePacket() implements CustomPayload { + public static final CustomPayload.Id ID = CustomPayload.id(RequestRouter.MOD_ID + ":handshake_complete"); + public static final PacketCodec CODEC = new PacketCodec<>() { + @Override + public ConfigurationCompletePacket decode(ByteBuf buf) { + return new ConfigurationCompletePacket(); + } - public ConfigurationCompletePacket(PacketByteBuf buf) { - this(); - } + @Override + public void encode(ByteBuf buf, ConfigurationCompletePacket value) { + } + }; @Override - public void write(PacketByteBuf buf) { - } - - @Override - public PacketType getType() { - return PACKET_TYPE; + public Id getId() { + return ID; } } diff --git a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ConfigurationPacket.java b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ConfigurationPacket.java index 01baff5..2b22032 100644 --- a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ConfigurationPacket.java +++ b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ConfigurationPacket.java @@ -1,26 +1,17 @@ package io.gitlab.jfronny.libjf.config.impl.network.packet; import io.gitlab.jfronny.libjf.config.impl.network.RequestRouter; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; -import net.fabricmc.fabric.api.networking.v1.PacketType; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; -public record ConfigurationPacket(int version) implements FabricPacket { - public static final Identifier ID = new Identifier(RequestRouter.MOD_ID, "handshake"); - public static final PacketType PACKET_TYPE = PacketType.create(ID, ConfigurationPacket::new); - - public ConfigurationPacket(PacketByteBuf buf) { - this(buf.readInt()); - } +public record ConfigurationPacket(int version) implements CustomPayload { + public static final CustomPayload.Id ID = CustomPayload.id(RequestRouter.MOD_ID + ":handshake"); + public static final PacketCodec CODEC = PacketCodecs.INTEGER.xmap(ConfigurationPacket::new, ConfigurationPacket::version); @Override - public void write(PacketByteBuf buf) { - buf.writeInt(version); - } - - @Override - public PacketType getType() { - return PACKET_TYPE; + public Id getId() { + return ID; } } diff --git a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/RequestPacket.java b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/RequestPacket.java new file mode 100644 index 0000000..50ecbb8 --- /dev/null +++ b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/RequestPacket.java @@ -0,0 +1,33 @@ +package io.gitlab.jfronny.libjf.config.impl.network.packet; + +import io.gitlab.jfronny.libjf.config.impl.network.RequestRouter; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; +import org.jetbrains.annotations.Nullable; + +public record RequestPacket(long request, @Nullable Long parent, String name, PacketByteBuf aux) implements CustomPayload { + public static final Id ID = CustomPayload.id(RequestRouter.MOD_ID + ":request"); + public static final PacketCodec CODEC = PacketCodec.of( + (value, buf) -> { + buf.writeLong(value.request); + buf.writeBoolean(value.parent != null); + if (value.parent != null) buf.writeLong(value.parent); + buf.writeString(value.name); + buf.writeBytes(value.aux); + }, + buf -> { + long request = buf.readLong(); + Long parent = buf.readBoolean() ? buf.readLong() : null; + String name = buf.readString(); + PacketByteBuf aux = PacketByteBufs.copy(buf); + return new RequestPacket(request, parent, name, aux); + } + ); + + @Override + public Id getId() { + return ID; + } +} diff --git a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ResponsePacket.java b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ResponsePacket.java new file mode 100644 index 0000000..5d88123 --- /dev/null +++ b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/packet/ResponsePacket.java @@ -0,0 +1,28 @@ +package io.gitlab.jfronny.libjf.config.impl.network.packet; + +import io.gitlab.jfronny.libjf.config.impl.network.RequestRouter; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; + +public record ResponsePacket(long request, int status, PacketByteBuf aux) implements CustomPayload { + public static final CustomPayload.Id ID = CustomPayload.id(RequestRouter.MOD_ID + ":response"); + public static final PacketCodec CODEC = PacketCodec.of( + (value, buf) -> { + buf.writeLong(value.request()); + buf.writeInt(value.status()); + buf.writeBytes(value.aux()); + }, + buf -> { + long request = buf.readLong(); + int status = buf.readInt(); + return new ResponsePacket(request, status, PacketByteBufs.copy(buf)); + } + ); + + @Override + public Id getId() { + return ID; + } +} diff --git a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/rci/entry/MirrorEntryInfoBase.java b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/rci/entry/MirrorEntryInfoBase.java index 7082a48..84f70d4 100644 --- a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/rci/entry/MirrorEntryInfoBase.java +++ b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/rci/entry/MirrorEntryInfoBase.java @@ -1,18 +1,14 @@ package io.gitlab.jfronny.libjf.config.impl.network.rci.entry; -import io.gitlab.jfronny.gson.stream.JsonReader; -import io.gitlab.jfronny.gson.stream.JsonWriter; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.SerializeWriter; import io.gitlab.jfronny.libjf.config.api.v2.EntryInfo; -import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.network.rci.MirrorConfigCategory; import io.gitlab.jfronny.libjf.config.impl.network.rci.MirrorObject; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.minecraft.network.PacketByteBuf; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - public abstract class MirrorEntryInfoBase extends MirrorObject implements EntryInfo { protected final MirrorConfigCategory category; protected final String entryName; @@ -34,13 +30,13 @@ public abstract class MirrorEntryInfoBase extends MirrorObject implements Ent } @Override - public void loadFromJson(JsonReader reader) throws IOException, IllegalAccessException { - throw new UnsupportedEncodingException(); + public > void loadFromJson(Reader reader) { + throw new UnsupportedOperationException(); } @Override - public void writeTo(JsonWriter writer, String translationPrefix) throws IOException, IllegalAccessException { - throw new UnsupportedEncodingException(); + public > void writeTo(Writer writer, String translationPrefix) { + throw new UnsupportedOperationException(); } @Override @@ -51,7 +47,7 @@ public abstract class MirrorEntryInfoBase extends MirrorObject implements Ent } @Override - public void reset() throws IllegalAccessException { + public void reset() { PacketByteBuf buf = PacketByteBufs.create(); writePath(buf); sendRequest("resetEntry", buf); diff --git a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/server/JfConfigNetworkServer.java b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/server/JfConfigNetworkServer.java index 877a158..2307ab7 100644 --- a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/server/JfConfigNetworkServer.java +++ b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/server/JfConfigNetworkServer.java @@ -5,6 +5,8 @@ import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.network.packet.ConfigurationCompletePacket; import io.gitlab.jfronny.libjf.config.impl.network.packet.ConfigurationPacket; import io.gitlab.jfronny.libjf.config.impl.network.RequestRouter; +import io.gitlab.jfronny.libjf.config.impl.network.packet.RequestPacket; +import io.gitlab.jfronny.libjf.config.impl.network.packet.ResponsePacket; import io.gitlab.jfronny.libjf.config.impl.network.rci.entry.Datatype; import io.gitlab.jfronny.libjf.config.impl.network.rci.entry.MirrorEntryInfo; import net.fabricmc.fabric.api.networking.v1.*; @@ -18,19 +20,20 @@ import java.util.function.Consumer; public class JfConfigNetworkServer { public static void initialize() { - ServerPlayNetworking.registerGlobalReceiver(RequestRouter.REQUEST_ID, (server, player, handler, buf, responseSender) -> { - if (authenticate(player)) RequestRouter.acceptRequest(buf, responseSender); - else RequestRouter.deny(buf, responseSender); + RequestRouter.initialize(); + ServerPlayNetworking.registerGlobalReceiver(RequestPacket.ID, (payload, context) -> { + if (authenticate(context.player())) RequestRouter.acceptRequest(payload, context.responseSender()); + else RequestRouter.deny(payload.request(), context.responseSender()); }); - ServerPlayNetworking.registerGlobalReceiver(RequestRouter.RESPONSE_ID, (server, player, handler, buf, responseSender) -> { - if (authenticate(player)) RequestRouter.acceptResponse(buf, responseSender); - else RequestRouter.deny(buf, responseSender); + ServerPlayNetworking.registerGlobalReceiver(ResponsePacket.ID, (payload, context) -> { + if (authenticate(context.player())) RequestRouter.acceptResponse(payload, context.responseSender()); + else RequestRouter.deny(payload.request(), context.responseSender()); }); - ServerConfigurationNetworking.registerGlobalReceiver(ConfigurationCompletePacket.PACKET_TYPE, (packet, networkHandler, responseSender) -> { - networkHandler.completeTask(JfConfigNetworkConfigurationTask.KEY); + ServerConfigurationNetworking.registerGlobalReceiver(ConfigurationCompletePacket.ID, (payload, context) -> { + context.networkHandler().completeTask(JfConfigNetworkConfigurationTask.KEY); }); ServerConfigurationConnectionEvents.CONFIGURE.register((handler, server) -> { - if (ServerConfigurationNetworking.canSend(handler, ConfigurationPacket.PACKET_TYPE)) { + if (ServerConfigurationNetworking.canSend(handler, ConfigurationPacket.ID)) { handler.addTask(new JfConfigNetworkConfigurationTask()); } }); diff --git a/libjf-config-ui-tiny/build.gradle.kts b/libjf-config-ui-tiny/build.gradle.kts index 4cfa50c..e7eed7f 100644 --- a/libjf-config-ui-tiny/build.gradle.kts +++ b/libjf-config-ui-tiny/build.gradle.kts @@ -5,12 +5,11 @@ plugins { } base { - archivesName.set("libjf-config-ui-tiny") + archivesName = "libjf-config-ui-tiny" } dependencies { - val fabricVersion: String by rootProject.extra api(devProject(":libjf-base")) api(devProject(":libjf-config-core-v2")) - include(fabricApi.module("fabric-resource-loader-v0", fabricVersion)) + include("net.fabricmc.fabric-api:fabric-resource-loader-v0") } diff --git a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/EditorScreen.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/EditorScreen.java index a935af8..40ad229 100644 --- a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/EditorScreen.java +++ b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/EditorScreen.java @@ -1,11 +1,8 @@ package io.gitlab.jfronny.libjf.config.impl.ui.tiny; import com.google.common.collect.Lists; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; import io.gitlab.jfronny.commons.ref.R; import it.unimi.dsi.fastutil.ints.IntArrayList; -import net.minecraft.SharedConstants; import net.minecraft.client.font.TextHandler; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -18,6 +15,7 @@ import net.minecraft.client.util.math.Rect2i; import net.minecraft.screen.ScreenTexts; import net.minecraft.text.*; import net.minecraft.util.Formatting; +import net.minecraft.util.StringHelper; import net.minecraft.util.Util; import net.minecraft.util.math.MathHelper; import org.apache.commons.lang3.StringUtils; @@ -161,7 +159,7 @@ public class EditorScreen extends ScreenWithSaveHook { if (super.charTyped(chr, modifiers)) { return true; } - if (SharedConstants.isValidChar(chr)) { + if (StringHelper.isValidChar(chr)) { this.currentPageSelectionManager.insert(Character.toString(chr)); this.invalidatePageContent(); return true; @@ -296,12 +294,6 @@ public class EditorScreen extends ScreenWithSaveHook { final int maxScroll = this.getMaxScroll(); final boolean showScrollbar = maxScroll > 0; - if (client.world == null) { - RenderSystem.setShaderColor(0.125f, 0.125f, 0.125f, 1.0f); - context.drawTexture(Screen.OPTIONS_BACKGROUND_TEXTURE, 0, HEADER_SIZE, showScrollbar ? width - SCROLLBAR_SIZE : width, height - FOOTER_SIZE + (int)scrollAmount, width - SCROLLBAR_SIZE, height - HEADER_SIZE - FOOTER_SIZE, 32, 32); - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); - } - context.enableScissor(0, HEADER_SIZE, width - SCROLLBAR_SIZE, height - FOOTER_SIZE); PageContent pageContent = this.getPageContent(); for (Line line : pageContent.lines) { diff --git a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java index 8cfeb05..1a0b480 100644 --- a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java +++ b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java @@ -1,18 +1,24 @@ package io.gitlab.jfronny.libjf.config.impl.ui.tiny; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; +import io.gitlab.jfronny.commons.Serializer; +import io.gitlab.jfronny.commons.serialize.Transport; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken; +import io.gitlab.jfronny.commons.serialize.json.JsonReader; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; import io.gitlab.jfronny.libjf.config.api.v2.EntryInfo; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory; +import io.gitlab.jfronny.libjf.serialize.SerializationMode; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.resource.language.I18n; import net.minecraft.client.toast.SystemToast; import net.minecraft.text.Text; +import java.io.IOException; + // IDEA doesn't like this, but it does work in practice public class TinyConfigScreenFactory implements ConfigScreenFactory { @Override @@ -26,8 +32,9 @@ public class TinyConfigScreenFactory implements ConfigScreenFactory LibJf.MAPPER.serialize(value, SerializationMode.asConfig(writer))); + } catch (IllegalAccessException | IOException e) { throw new RuntimeException(e); } String key = config.getTranslationPrefix() + entry.getName(); @@ -38,7 +45,12 @@ public class TinyConfigScreenFactory implements ConfigScreenFactory { try { - entry.setValue(GsonHolders.CONFIG.getGson().fromJson(json, type.asClass())); + entry.setValue(LibJf.JSON_TRANSPORT.read( + json, + (Transport.Returnable) reader -> LibJf.MAPPER + .getAdapter(TypeToken.get(type.asClass())) + .deserialize(SerializationMode.asConfig(reader)))); + entry.setValue(Serializer.getInstance().deserialize(json, type.asClass())); config.write(); } catch (Throwable e) { LibJf.LOGGER.error("Could not write element", e); diff --git a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java index 842add5..575b4c5 100644 --- a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java +++ b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java @@ -1,14 +1,19 @@ package io.gitlab.jfronny.libjf.config.impl.ui.tiny.entry; +import io.gitlab.jfronny.commons.Serializer; import io.gitlab.jfronny.commons.ref.R; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; +import io.gitlab.jfronny.commons.serialize.Transport; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken; +import io.gitlab.jfronny.commons.serialize.json.JsonReader; import io.gitlab.jfronny.commons.throwable.Try; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.ConfigCategory; import io.gitlab.jfronny.libjf.config.api.v2.EntryInfo; +import io.gitlab.jfronny.libjf.config.api.v2.JfConfig; import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.ConfigCore; import io.gitlab.jfronny.libjf.config.impl.ui.tiny.EditorScreen; +import io.gitlab.jfronny.libjf.serialize.SerializationMode; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.gui.widget.ButtonWidget; @@ -19,6 +24,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Language; +import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.function.Function; @@ -171,7 +177,7 @@ public class EntryInfoWidgetBuilder { final String jsonified; if (state.tempValue == null) { try { - jsonified = GsonHolders.CONFIG.getGson().toJson(state.cachedValue); + jsonified = LibJf.JSON_TRANSPORT.write(writer -> LibJf.MAPPER.serialize(state.cachedValue, SerializationMode.asConfig(writer))); } catch (Throwable e) { LibJf.LOGGER.error("Could not stringify element", e); SystemToast.add( @@ -193,7 +199,11 @@ public class EntryInfoWidgetBuilder { jsonified, json -> { try { - state.updateCache(GsonHolders.CONFIG.getGson().fromJson(json, info.getValueType().asClass())); + state.updateCache(LibJf.JSON_TRANSPORT.read( + json, + (Transport.Returnable) reader -> LibJf.MAPPER + .getAdapter((TypeToken) TypeToken.get(info.getValueType().asClass())) + .deserialize(SerializationMode.asConfig(reader)))); state.tempValue = null; } catch (Throwable e) { LibJf.LOGGER.error("Could not write element", e); diff --git a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryListWidget.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryListWidget.java index 52d4ce0..7dddd2c 100644 --- a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryListWidget.java +++ b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryListWidget.java @@ -19,18 +19,15 @@ import java.util.function.Supplier; @Environment(EnvType.CLIENT) public class EntryListWidget extends ElementListWidget { private final TextRenderer textRenderer; - private final boolean background; public EntryListWidget(MinecraftClient client, TextRenderer tr, int width, int height, int top) { super(client, width, height, top, 25); this.centerListVertically = false; textRenderer = tr; - background = client.world == null; - setRenderBackground(background); } @Override - public int getScrollbarPositionX() { + public int getScrollbarX() { return this.width -7; } @@ -82,12 +79,6 @@ public class EntryListWidget extends ElementListWidget { public PresetListWidget(MinecraftClient client, int width, int height, int top, int itemHeight) { super(client, width, height, top, itemHeight); - setRenderBackground(client.world == null); } public void addButton(ClickableWidget button) { @@ -19,8 +18,8 @@ public class PresetListWidget extends ElementListWidget { adder.add( createButton(Text.translatable(key + ".jfconfig.title"), () -> ConfigScreenFactory.getInstance() diff --git a/libjf-data-manipulation-v0/build.gradle.kts b/libjf-data-manipulation-v0/build.gradle.kts index fce7e55..16c2f14 100644 --- a/libjf-data-manipulation-v0/build.gradle.kts +++ b/libjf-data-manipulation-v0/build.gradle.kts @@ -5,12 +5,11 @@ plugins { } base { - archivesName.set("libjf-data-manipulation-v0") + archivesName = "libjf-data-manipulation-v0" } dependencies { - val fabricVersion: String by rootProject.extra api(devProject(":libjf-base")) api(devProject(":libjf-unsafe-v0")) - modApi(fabricApi.module("fabric-api-base", fabricVersion)) + modApi("net.fabricmc.fabric-api:fabric-api-base") } diff --git a/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/api/UserResourceEvents.java b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/api/UserResourceEvents.java index 308ea49..41faa6b 100644 --- a/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/api/UserResourceEvents.java +++ b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/api/UserResourceEvents.java @@ -1,6 +1,8 @@ package io.gitlab.jfronny.libjf.data.manipulation.api; import io.gitlab.jfronny.commons.LazySupplier; +import io.gitlab.jfronny.commons.concurrent.ScopedValue; +import io.gitlab.jfronny.commons.throwable.ExceptionWrapper; import io.gitlab.jfronny.commons.throwable.ThrowingRunnable; import io.gitlab.jfronny.commons.throwable.ThrowingSupplier; import io.gitlab.jfronny.libjf.LibJf; @@ -19,20 +21,17 @@ import java.util.function.Supplier; public class UserResourceEvents { public static TVal disable(ThrowingSupplier then) throws TEx { try { - ResourcePackHook.setDisabled(true); - return then.get(); - } - finally { - ResourcePackHook.setDisabled(false); + return ScopedValue.getWhere(ResourcePackHook.DISABLED, true, then.orThrow()); + } catch (ExceptionWrapper ew) { + throw (TEx) ExceptionWrapper.unwrap(ew); } } public static void disable(ThrowingRunnable then) throws TEx { try { - ResourcePackHook.setDisabled(true); - then.run(); - } finally { - ResourcePackHook.setDisabled(false); + ScopedValue.runWhere(ResourcePackHook.DISABLED, true, then.orThrow()); + } catch (ExceptionWrapper ew) { + throw (TEx) ExceptionWrapper.unwrap(ew); } } diff --git a/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHook.java b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHook.java index b90ac9f..6007a3a 100644 --- a/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHook.java +++ b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHook.java @@ -1,6 +1,7 @@ package io.gitlab.jfronny.libjf.data.manipulation.impl; import io.gitlab.jfronny.commons.LazySupplier; +import io.gitlab.jfronny.commons.concurrent.ScopedValue; import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents; import net.minecraft.resource.*; import net.minecraft.resource.metadata.ResourceMetadataReader; @@ -9,22 +10,15 @@ import org.jetbrains.annotations.ApiStatus; import java.io.IOException; import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; @SuppressWarnings("unused") @ApiStatus.Internal public class ResourcePackHook { - private static final Map disabled = new HashMap<>(); - @ApiStatus.Internal - public static void setDisabled(boolean disabled) { - ResourcePackHook.disabled.put(Thread.currentThread().getId(), disabled); - } + public static final ScopedValue DISABLED = new ScopedValue<>(); - @ApiStatus.Internal - public static boolean isDisabled() { - return disabled.getOrDefault(Thread.currentThread().getId(), false); + private static boolean isDisabled() { + return DISABLED.orElse(false); } public static InputSupplier hookOpenRoot(InputSupplier value, ResourcePack pack, String[] fileName) { diff --git a/libjf-data-manipulation-v0/src/testmod/java/io/gitlab/jfronny/libjf/data/manipulation/test/TestEntrypoint.java b/libjf-data-manipulation-v0/src/testmod/java/io/gitlab/jfronny/libjf/data/manipulation/test/TestEntrypoint.java index 317a16b..2cd479f 100644 --- a/libjf-data-manipulation-v0/src/testmod/java/io/gitlab/jfronny/libjf/data/manipulation/test/TestEntrypoint.java +++ b/libjf-data-manipulation-v0/src/testmod/java/io/gitlab/jfronny/libjf/data/manipulation/test/TestEntrypoint.java @@ -11,7 +11,7 @@ public class TestEntrypoint implements ModInitializer { // This should prevent resource packs from doing anything if my hooks are working and UserResourceEvents.OPEN.register((type, id, previous, pack) -> { if (pack instanceof DirectoryResourcePack) { - LibJf.LOGGER.info(pack.getName() + " opened " + type.name() + "/" + id.toString()); + LibJf.LOGGER.info(pack.getInfo().title() + " opened " + type.name() + "/" + id.toString()); return null; } return previous; diff --git a/libjf-data-v0/build.gradle.kts b/libjf-data-v0/build.gradle.kts index 5477ff8..db562e0 100644 --- a/libjf-data-v0/build.gradle.kts +++ b/libjf-data-v0/build.gradle.kts @@ -5,11 +5,10 @@ plugins { } base { - archivesName.set("libjf-data-v0") + archivesName = "libjf-data-v0" } dependencies { - val fabricVersion: String by rootProject.extra api(devProject(":libjf-base")) - include(fabricApi.module("fabric-resource-loader-v0", fabricVersion)) + include("net.fabricmc.fabric-api:fabric-resource-loader-v0") } diff --git a/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/EntityMixin.java b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/EntityMixin.java index 9803a99..0870843 100644 --- a/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/EntityMixin.java +++ b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/EntityMixin.java @@ -2,7 +2,9 @@ package io.gitlab.jfronny.libjf.data.mixin; import io.gitlab.jfronny.libjf.data.Tags; import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -37,8 +39,9 @@ public class EntityMixin { private boolean libjf$opArmor() { Entity entity = (Entity) (Object) this; + if (!(entity instanceof LivingEntity le)) return false; AtomicInteger armorCount = new AtomicInteger(); - for (ItemStack s : entity.getArmorItems()) { + for (ItemStack s : le.getArmorItems()) { if (s.isIn(Tags.OVERPOWERED)) armorCount.getAndIncrement(); } diff --git a/libjf-mainhttp-v0/build.gradle.kts b/libjf-mainhttp-v0/build.gradle.kts index fd0c61f..75327da 100644 --- a/libjf-mainhttp-v0/build.gradle.kts +++ b/libjf-mainhttp-v0/build.gradle.kts @@ -3,10 +3,9 @@ plugins { } base { - archivesName.set("libjf-mainhttp-v0") + archivesName = "libjf-mainhttp-v0" } dependencies { - val fabricVersion: String by rootProject.extra - implementation(fabricApi.module("fabric-api-base", fabricVersion)) + modImplementation("net.fabricmc.fabric-api:fabric-api-base") } diff --git a/libjf-translate-v1/build.gradle.kts b/libjf-translate-v1/build.gradle.kts index 3e400d0..41b5ebb 100644 --- a/libjf-translate-v1/build.gradle.kts +++ b/libjf-translate-v1/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } base { - archivesName.set("libjf-translate-v1") + archivesName = "libjf-translate-v1" } dependencies { diff --git a/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/libretranslate/LibreTranslateService.java b/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/libretranslate/LibreTranslateService.java index a6aae00..628dc1d 100644 --- a/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/libretranslate/LibreTranslateService.java +++ b/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/libretranslate/LibreTranslateService.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.libjf.translate.impl.libretranslate; import io.gitlab.jfronny.commons.http.client.HttpClient; -import io.gitlab.jfronny.gson.reflect.TypeToken; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken; import io.gitlab.jfronny.libjf.translate.api.TranslateException; import io.gitlab.jfronny.libjf.translate.impl.AbstractTranslateService; import io.gitlab.jfronny.libjf.translate.impl.libretranslate.model.*; diff --git a/libjf-unsafe-v0/build.gradle.kts b/libjf-unsafe-v0/build.gradle.kts index cd64115..45e68ee 100644 --- a/libjf-unsafe-v0/build.gradle.kts +++ b/libjf-unsafe-v0/build.gradle.kts @@ -5,12 +5,11 @@ plugins { } base { - archivesName.set("libjf-unsafe-v0") + archivesName = "libjf-unsafe-v0" } dependencies { - val commonsVersion: String by rootProject.extra api(devProject(":libjf-base")) - compileOnly("io.gitlab.jfronny:commons-unsafe:$commonsVersion") { isTransitive = false } - shadow("io.gitlab.jfronny:commons-unsafe:$commonsVersion") { isTransitive = false } + compileOnly(libs.commons.unsafe) { isTransitive = false } + shadow(libs.commons.unsafe) { isTransitive = false } } diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/FLLogger.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/FLLogger.java deleted file mode 100644 index 0667a8c..0000000 --- a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/FLLogger.java +++ /dev/null @@ -1,118 +0,0 @@ -package io.gitlab.jfronny.libjf.unsafe; - -import io.gitlab.jfronny.commons.logging.Logger; -import net.fabricmc.loader.impl.util.log.Log; -import net.fabricmc.loader.impl.util.log.LogCategory; - -public class FLLogger implements Logger { - private final LogCategory category; - - public FLLogger(String context, String... names) { - this.category = LogCategory.createCustom(context, names); - } - - @Override - public String getName() { - return category.name; - } - - @Override - public void trace(String msg) { - Log.trace(category, msg); - } - - @Override - public void trace(String format, Object arg) { - Log.trace(category, format, arg); - } - - @Override - public void trace(String format, Object... args) { - Log.trace(category, format, args); - } - - @Override - public void trace(String msg, Throwable t) { - Log.trace(category, msg, t); - } - - @Override - public void debug(String msg) { - Log.debug(category, msg); - } - - @Override - public void debug(String format, Object arg) { - Log.debug(category, format, arg); - } - - @Override - public void debug(String format, Object... args) { - Log.debug(category, format, args); - } - - @Override - public void debug(String msg, Throwable t) { - Log.debug(category, msg, t); - } - - @Override - public void info(String msg) { - Log.info(category, msg); - } - - @Override - public void info(String format, Object arg) { - Log.info(category, format, arg); - } - - @Override - public void info(String format, Object... args) { - Log.info(category, format, args); - } - - @Override - public void info(String msg, Throwable t) { - Log.info(category, msg, t); - } - - @Override - public void warn(String msg) { - Log.warn(category, msg); - } - - @Override - public void warn(String format, Object arg) { - Log.warn(category, format, arg); - } - - @Override - public void warn(String format, Object... args) { - Log.warn(category, format, args); - } - - @Override - public void warn(String msg, Throwable t) { - Log.warn(category, msg, t); - } - - @Override - public void error(String msg) { - Log.error(category, msg); - } - - @Override - public void error(String format, Object arg) { - Log.error(category, format, arg); - } - - @Override - public void error(String format, Object... args) { - Log.error(category, format, args); - } - - @Override - public void error(String msg, Throwable t) { - Log.error(category, msg, t); - } -} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/JfLanguageAdapter.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/JfLanguageAdapter.java index 85d6c93..eea7e43 100644 --- a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/JfLanguageAdapter.java +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/JfLanguageAdapter.java @@ -1,9 +1,6 @@ package io.gitlab.jfronny.libjf.unsafe; -import io.gitlab.jfronny.commons.logging.Level; -import io.gitlab.jfronny.commons.logging.Logger; import io.gitlab.jfronny.libjf.LibJf; -import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.LanguageAdapter; public class JfLanguageAdapter implements LanguageAdapter { @@ -11,8 +8,6 @@ public class JfLanguageAdapter implements LanguageAdapter { public native T create(net.fabricmc.loader.api.ModContainer mod, String value, Class type); static { - Logger.registerFactory(FLLogger::new); // Reset in LibJf entrypoint - Logger.setMinimumLevel(FabricLoader.getInstance().isDevelopmentEnvironment() ? Level.TRACE : Level.INFO); LibJf.LOGGER.info("Starting unsafe init"); // Also ensures LibJF. is called and Gson is initialized DynamicEntry.execute("libjf:preEarly", UltraEarlyInit.class, s -> s.instance().init()); DynamicEntry.execute("libjf:early", UltraEarlyInit.class, s -> s.instance().init()); diff --git a/libjf-web-v1/build.gradle.kts b/libjf-web-v1/build.gradle.kts index 9b27cd7..676d112 100644 --- a/libjf-web-v1/build.gradle.kts +++ b/libjf-web-v1/build.gradle.kts @@ -5,15 +5,14 @@ plugins { } base { - archivesName.set("libjf-web-v1") + archivesName = "libjf-web-v1" } dependencies { - val fabricVersion: String by rootProject.extra api(devProject(":libjf-base")) api(devProject(":libjf-config-core-v2")) api(devProject(":libjf-mainhttp-v0")) - include(modImplementation(fabricApi.module("fabric-command-api-v2", fabricVersion))!!) + include(modImplementation("net.fabricmc.fabric-api:fabric-command-api-v2")!!) annotationProcessor(project(":libjf-config-compiler-plugin-v2")) } diff --git a/settings.gradle.kts b/settings.gradle.kts index be25856..7f3d405 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,11 +1,13 @@ pluginManagement { repositories { maven("https://maven.fabricmc.net/") // FabricMC + maven("https://maven.architectury.dev/") // Architectury + maven("https://files.minecraftforge.net/maven/") // Forge maven("https://maven.frohnmeyer-wds.de/artifacts") // scripts gradlePluginPortal() } plugins { - id("jfmod") version("1.5-SNAPSHOT") + id("jfmod") version("1.6-SNAPSHOT") id("jfmod.module") } }