diff --git a/build.gradle.kts b/build.gradle.kts index d9b8c27..9e94fa2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,8 +6,8 @@ allprojects { group = "io.gitlab.jfronny.libjf" } -val fabricVersion by extra("0.86.1+1.20.1") -val commonsVersion by extra("1.3-SNAPSHOT") +val fabricVersion by extra("0.87.1+1.20.2") +val commonsVersion by extra("1.4-SNAPSHOT") val gsonCompileVersion by extra("1.3-SNAPSHOT") val modmenuVersion by extra("7.2.1") @@ -15,8 +15,8 @@ val annotationsVersion by extra("24.0.1") val javapoetVersion by extra("1.13.0") jfMod { - minecraftVersion = "1.20.1" - yarn("build.10") + minecraftVersion = "23w33a" + yarn("build.7") loaderVersion = "0.14.22" modrinth { @@ -37,11 +37,18 @@ allprojects { } dependencies { - modLocalRuntime("com.terraformersmc:modmenu:$modmenuVersion") { - exclude("net.fabricmc") // required to work around duplicate fabric loaders - } + // Temporarily disabled since modmenu doesn't support snapshots +// modLocalRuntime("com.terraformersmc:modmenu:$modmenuVersion") { +// exclude("net.fabricmc") // required to work around duplicate fabric loaders +// } modLocalRuntime(fabricApi.module("fabric-command-api-v2", fabricVersion)) compileOnly("io.gitlab.jfronny:commons:$commonsVersion") compileOnly("io.gitlab.jfronny:commons-gson:$commonsVersion") + + // temporary workaround for snapshot versions since these were previously provided by modmenu. Remove once out of use! + modLocalRuntime(fabricApi.module("fabric-resource-loader-v0", fabricVersion)) + modLocalRuntime(fabricApi.module("fabric-lifecycle-events-v1", fabricVersion)) + modLocalRuntime(fabricApi.module("fabric-screen-api-v1", fabricVersion)) + modLocalRuntime(fabricApi.module("fabric-key-binding-api-v1", fabricVersion)) } } diff --git a/docs/README.md b/docs/README.md index 806746c..9550e8c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,8 +20,8 @@ repositories { and include LibJF modules like this: ```groovy dependencies { - include modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v1:${project.libjf_version}") - include modRuntimeOnly("io.gitlab.jfronny.libjf:libjf-config-ui-tiny-v1:${project.libjf_version}") + include modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v2:${project.libjf_version}") + include modRuntimeOnly("io.gitlab.jfronny.libjf:libjf-config-ui-tiny:${project.libjf_version}") include("io.gitlab.jfronny.libjf:libjf-base:${project.libjf_version}") modLocalRuntime("io.gitlab.jfronny.libjf:libjf-config-reflect-v1:${project.libjf_version}") diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 9ed830a..6a73656 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -6,14 +6,13 @@ - [libjf-base](./libjf-base.md) - [Config](./config/README.md) - - [libjf-config-core-v1](./config/libjf-config-core-v1.md) - - [libjf-config-reflect-v1](./config/libjf-config-reflect-v1.md) - - [libjf-config-compiler-plugin](./config/libjf-config-compiler-plugin.md) - - [libjf-config-commands-v1](./config/libjf-config-commands-v1.md) - - [libjf-config-ui-tiny-v1](./config/libjf-config-ui-tiny-v1.md) + - [libjf-config-core-v2](./config/libjf-config-core-v2.md) + - [libjf-config-compiler-plugin-v2](./config/libjf-config-compiler-plugin-v2.md) + - [libjf-config-commands](./config/libjf-config-commands.md) + - [libjf-config-ui-tiny](./config/libjf-config-ui-tiny.md) - [libjf-devutil](./libjf-devutil.md) - [libjf-data-v0](./libjf-data-v0.md) - [libjf-data-manipulation-v0](./libjf-data-manipulation-v0.md) - [libjf-translate-v1](./libjf-translate-v1.md) - [libjf-unsafe-v0](./libjf-unsafe-v0.md) -- [libjf-web-v0](./libjf-web-v0.md) \ No newline at end of file +- [libjf-web-v1](./libjf-web-v1.md) \ No newline at end of file diff --git a/docs/config/README.md b/docs/config/README.md index d438c94..3654f66 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -11,8 +11,8 @@ repositories { } dependencies { - include modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v1:${project.libjf_version}") - include modRuntimeOnly("io.gitlab.jfronny.libjf:libjf-config-ui-tiny-v1:${project.libjf_version}") + include modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v2:${project.libjf_version}") + include modRuntimeOnly("io.gitlab.jfronny.libjf:libjf-config-ui-tiny:${project.libjf_version}") include("io.gitlab.jfronny.libjf:libjf-base:${project.libjf_version}") annotationProcessor("io.gitlab.jfronny.libjf:libjf-config-compiler-plugin-v2:${project.libjf_version}") diff --git a/docs/config/libjf-config-commands-v1.md b/docs/config/libjf-config-commands.md similarity index 90% rename from docs/config/libjf-config-commands-v1.md rename to docs/config/libjf-config-commands.md index 4f0983f..7b5fc03 100644 --- a/docs/config/libjf-config-commands-v1.md +++ b/docs/config/libjf-config-commands.md @@ -1,4 +1,4 @@ -# libjf-config-commands-v1 +# libjf-config-commands This serverside module provides commands for modifying configs using this library. If you are developing a serverside mod, you may wish to include it to enable easier configuration. The commands are available under `/libjf config`, using auto-complete is recommended. \ No newline at end of file diff --git a/docs/config/libjf-config-core-v1.md b/docs/config/libjf-config-core-v2.md similarity index 99% rename from docs/config/libjf-config-core-v1.md rename to docs/config/libjf-config-core-v2.md index 0dfdd91..6eabb3b 100644 --- a/docs/config/libjf-config-core-v1.md +++ b/docs/config/libjf-config-core-v2.md @@ -1,4 +1,4 @@ -# libjf-config-core-v1 +# libjf-config-core-v2 The core module contains the abstractions and annotations used by other modules to interact with configs. It also contains the code for registering configs to mods, serialization and automatic reloads on change. diff --git a/docs/config/libjf-config-reflect-v1.md b/docs/config/libjf-config-reflect-v1.md deleted file mode 100644 index ed0d08b..0000000 --- a/docs/config/libjf-config-reflect-v1.md +++ /dev/null @@ -1,8 +0,0 @@ -# libjf-config-reflect-v1 -This module uses reflection to register configs from files using the annotations as presented [here](./libjf-config-core-v1.md) -In order to register a config, simply add the class annotated as `@JfConfig` to the `libjf:config` entrypoint. -Please be aware that this module may load your config class before the game classes are available. -Using them there WILL result in problems! - -Instead of using this implementation, you should use the [compiler plugin](./libjf-config-compiler-plugin-v2.md), -which removes the runtime overhead of this implementation. \ No newline at end of file diff --git a/docs/config/libjf-config-ui-tiny-v1.md b/docs/config/libjf-config-ui-tiny-v1.md deleted file mode 100644 index 6cd3f47..0000000 --- a/docs/config/libjf-config-ui-tiny-v1.md +++ /dev/null @@ -1,4 +0,0 @@ -# libjf-config-ui-tiny-v1 -This module provides an automatically registered, TinyConfig-based UI for all mods using libjf-config. -Embedding this is recommended when developing client-side mods. -Manually generating config screens is also possible through `ConfigScreen.create(config, parent)` \ No newline at end of file diff --git a/docs/config/libjf-config-ui-tiny.md b/docs/config/libjf-config-ui-tiny.md new file mode 100644 index 0000000..6aab4c6 --- /dev/null +++ b/docs/config/libjf-config-ui-tiny.md @@ -0,0 +1,4 @@ +# libjf-config-ui-tiny +This module provides an automatically registered, TinyConfig-based UI for all mods using libjf-config. +Embedding this is recommended when developing client-side mods. +libjf-config-ui-tiny implements the config-core-provided `ConfigScreenFactory`, so you can `ConfigScreenFactory.getInstance().create(config, parent).get()` to obtain a screen for your config. \ No newline at end of file diff --git a/docs/libjf-web-v0.md b/docs/libjf-web-v1.md similarity index 74% rename from docs/libjf-web-v0.md rename to docs/libjf-web-v1.md index 6928e3b..5a9e1b3 100644 --- a/docs/libjf-web-v0.md +++ b/docs/libjf-web-v1.md @@ -1,7 +1,7 @@ -# libjf-web-v0 -libjf-web-v0 provides an HTTP web server you can use in your serverside (and technically also clientside) mods +# libjf-web-v1 +libjf-web-v1 provides an HTTP web server you can use in your serverside (and technically also clientside) mods to serve web content through a unified port. -libjf-web-v0 depends on libjf-config-v1 to provide its config, libjf-base, fabric-lifecycle-events-v1 and fabric-command-api-v1 +libjf-web-v1 depends on libjf-config-core-v2 to provide its config, libjf-base, fabric-lifecycle-events-v1 and fabric-command-api-v1 ### Getting started Implement WebInit and register it as a libjf:web entrypoint. To enable the server, also add the following to your fabric.mod.json: diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/coprocess/CoProcessManager.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/coprocess/CoProcessManager.java index 06127c0..7023655 100644 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/coprocess/CoProcessManager.java +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/coprocess/CoProcessManager.java @@ -27,9 +27,8 @@ public class CoProcessManager implements ModInitializer { } private void stop() { - Iterator procs = coProcesses.iterator(); - while (procs.hasNext()) { - CoProcess coProcess = procs.next(); + for (Iterator iter = coProcesses.iterator(); iter.hasNext(); ) { + CoProcess coProcess = iter.next(); coProcess.stop(); if (coProcess instanceof Closeable cl) { try { @@ -38,7 +37,7 @@ public class CoProcessManager implements ModInitializer { LibJf.LOGGER.error("Could not close co-process", e); } } - procs.remove(); + iter.remove(); } } } diff --git a/libjf-config-commands-v1/build.gradle.kts b/libjf-config-commands/build.gradle.kts similarity index 74% rename from libjf-config-commands-v1/build.gradle.kts rename to libjf-config-commands/build.gradle.kts index 923c36f..695d0e8 100644 --- a/libjf-config-commands-v1/build.gradle.kts +++ b/libjf-config-commands/build.gradle.kts @@ -5,12 +5,12 @@ plugins { } base { - archivesName.set("libjf-config-commands-v1") + archivesName.set("libjf-config-commands") } dependencies { val fabricVersion: String by rootProject.extra api(devProject(":libjf-base")) - api(devProject(":libjf-config-core-v1")) + api(devProject(":libjf-config-core-v2")) include(modImplementation(fabricApi.module("fabric-command-api-v2", fabricVersion))!!) } diff --git a/libjf-config-commands-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java similarity index 80% rename from libjf-config-commands-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java rename to libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java index 597d027..3edd15a 100644 --- a/libjf-config-commands-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java +++ b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java @@ -8,11 +8,12 @@ import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import io.gitlab.jfronny.commons.throwable.ThrowingRunnable; import io.gitlab.jfronny.commons.throwable.ThrowingSupplier; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.*; -import io.gitlab.jfronny.libjf.config.api.v1.type.Type; +import io.gitlab.jfronny.libjf.config.api.v2.*; +import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.MutableText; import net.minecraft.text.Text; import java.util.function.Consumer; @@ -22,6 +23,12 @@ import static net.minecraft.server.command.CommandManager.argument; import static net.minecraft.server.command.CommandManager.literal; public class JfConfigCommand implements ModInitializer { + private static final String MOD_ID = "libjf-config-commands"; + + private MutableText text(String text) { + return Text.literal("[" + MOD_ID + "] " + text); + } + @Override public void onInitialize() { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { @@ -29,25 +36,24 @@ public class JfConfigCommand implements ModInitializer { LiteralArgumentBuilder c_config = literal("config") .requires((serverCommandSource) -> serverCommandSource.hasPermissionLevel(4)) .executes(context -> { - context.getSource().sendFeedback(() -> Text.literal("[libjf-config-v1] Loaded configs for:"), false); - ConfigHolder.getInstance().getRegistered().forEach((s, config) -> { - context.getSource().sendFeedback(() -> Text.literal("- " + s), false); - }); + MutableText text = text("Loaded configs for:"); + ConfigHolder.getInstance().getRegistered().forEach((s, config) -> text.append("\n- " + s)); + context.getSource().sendFeedback(() -> text, false); return Command.SINGLE_SUCCESS; }); LiteralArgumentBuilder c_reload = literal("reload").executes(context -> { ConfigHolder.getInstance().getRegistered().forEach((mod, config) -> config.load()); - context.getSource().sendFeedback(() -> Text.literal("[libjf-config-v1] Reloaded configs"), true); + context.getSource().sendFeedback(() -> text("Reloaded configs"), true); return Command.SINGLE_SUCCESS; }); LiteralArgumentBuilder c_reset = literal("reset").executes(context -> { - context.getSource().sendError(Text.literal("[libjf-config-v1] Please specify a config to reset")); + context.getSource().sendError(text("Please specify a config to reset")); return Command.SINGLE_SUCCESS; }); ConfigHolder.getInstance().getRegistered().forEach((id, config) -> { c_reload.then(literal(id).executes(context -> { config.load(); - context.getSource().sendFeedback(() -> Text.literal("[libjf-config-v1] Reloaded config for " + id), true); + context.getSource().sendFeedback(() -> text("Reloaded config for " + id), true); return Command.SINGLE_SUCCESS; })); registerEntries(config, id, c_config, c_reset, cns -> { @@ -63,7 +69,7 @@ public class JfConfigCommand implements ModInitializer { private void registerEntries(ConfigCategory config, String subpath, LiteralArgumentBuilder c_config, LiteralArgumentBuilder c_reset, Function>, LiteralArgumentBuilder> pathGen) { c_config.then(pathGen.apply(cns -> { cns.executes(context -> { - context.getSource().sendFeedback(() -> Text.literal("[libjf-config-v1] " + subpath + " is a category"), false); + context.getSource().sendFeedback(() -> text(subpath + " is a category"), false); return Command.SINGLE_SUCCESS; }); for (EntryInfo entry : config.getEntries()) { @@ -73,13 +79,13 @@ public class JfConfigCommand implements ModInitializer { c_reset.then(pathGen.apply(cns -> { cns.executes(context -> { config.reset(); - context.getSource().sendFeedback(() -> Text.literal("[libjf-config-v1] Reset config for " + subpath), true); + context.getSource().sendFeedback(() -> text("Reset config for " + subpath), true); return Command.SINGLE_SUCCESS; }); config.getPresets().forEach((id2, preset) -> { cns.then(literal(id2).executes(context -> { preset.run(); - context.getSource().sendFeedback(() -> Text.literal("[libjf-config-v1] Loaded preset " + id2 + " for " + subpath), true); + context.getSource().sendFeedback(() -> text("Loaded preset " + id2 + " for " + subpath), true); return Command.SINGLE_SUCCESS; })); }); @@ -103,8 +109,8 @@ public class JfConfigCommand implements ModInitializer { private void registerEntry(ConfigCategory config, String subpath, LiteralArgumentBuilder cns, EntryInfo entry) { LiteralArgumentBuilder c_entry = literal(entry.getName()).executes(context -> { - String msg = "[libjf-config-v1] The value of " + subpath + "." + entry.getName() + " is " + tryRun(entry::getValue); - context.getSource().sendFeedback(() -> Text.literal(msg), false); + String msg = "The value of " + subpath + "." + entry.getName() + " is " + tryRun(entry::getValue); + context.getSource().sendFeedback(() -> text(msg), false); return Command.SINGLE_SUCCESS; }); ArgumentType type = getType(entry); @@ -115,7 +121,7 @@ public class JfConfigCommand implements ModInitializer { entry.setValue(value); config.getRoot().write(); }); - context.getSource().sendFeedback(() -> Text.literal("[libjf-config-v1] Set " + subpath + "." + entry.getName() + " to " + value), true); + context.getSource().sendFeedback(() -> text("Set " + subpath + "." + entry.getName() + " to " + value), true); return Command.SINGLE_SUCCESS; })); } @@ -126,7 +132,7 @@ public class JfConfigCommand implements ModInitializer { entry.setValue(enumConstant); config.getRoot().write(); }); - context.getSource().sendFeedback(() -> Text.literal("[libjf-config-v1] Set " + subpath + "." + entry.getName() + " to " + enumConstant), true); + context.getSource().sendFeedback(() -> text("Set " + subpath + "." + entry.getName() + " to " + enumConstant), true); return Command.SINGLE_SUCCESS; })); } diff --git a/libjf-config-commands-v1/src/main/resources/fabric.mod.json b/libjf-config-commands/src/main/resources/fabric.mod.json similarity index 90% rename from libjf-config-commands-v1/src/main/resources/fabric.mod.json rename to libjf-config-commands/src/main/resources/fabric.mod.json index eba5d9b..e5a8dff 100644 --- a/libjf-config-commands-v1/src/main/resources/fabric.mod.json +++ b/libjf-config-commands/src/main/resources/fabric.mod.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "id": "libjf-config-commands-v1", + "id": "libjf-config-commands", "name": "LibJF Config Commands", "version": "${version}", "authors": ["JFronny"], @@ -20,7 +20,7 @@ "minecraft": "*", "fabric-command-api-v2": "*", "libjf-base": ">=${version}", - "libjf-config-core-v1": ">=${version}" + "libjf-config-core-v2": ">=${version}" }, "custom": { "modmenu": { diff --git a/libjf-config-compiler-plugin-v2/build.gradle.kts b/libjf-config-compiler-plugin-v2/build.gradle.kts index 2e791ee..338e9a8 100644 --- a/libjf-config-compiler-plugin-v2/build.gradle.kts +++ b/libjf-config-compiler-plugin-v2/build.gradle.kts @@ -22,7 +22,7 @@ dependencies { val annotationsVersion: String by rootProject.extra val javapoetVersion: String by rootProject.extra implementation("io.gitlab.jfronny.gson:gson-compile-processor-core:$gsonCompileVersion") - implementation(devProject(":libjf-config-core-v1")) + implementation(devProject(":libjf-config-core-v2")) implementation("org.jetbrains:annotations:$annotationsVersion") implementation("io.gitlab.jfronny:commons:$commonsVersion") implementation("io.gitlab.jfronny:commons-gson:$commonsVersion") 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 5c96300..e2568b1 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 @@ -4,9 +4,9 @@ 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.libjf.config.api.v1.*; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL; -import io.gitlab.jfronny.libjf.config.api.v1.type.Type; +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; import javax.annotation.processing.*; import javax.lang.model.SourceVersion; diff --git a/libjf-config-compiler-plugin-v2/src/test/java/io/gitlab/jfronny/libjf/config/plugin/test/PluginTest.java b/libjf-config-compiler-plugin-v2/src/test/java/io/gitlab/jfronny/libjf/config/plugin/test/PluginTest.java index abfa073..2307750 100644 --- a/libjf-config-compiler-plugin-v2/src/test/java/io/gitlab/jfronny/libjf/config/plugin/test/PluginTest.java +++ b/libjf-config-compiler-plugin-v2/src/test/java/io/gitlab/jfronny/libjf/config/plugin/test/PluginTest.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.libjf.config.plugin.test; -import io.gitlab.jfronny.libjf.config.api.v1.*; +import io.gitlab.jfronny.libjf.config.api.v2.*; import java.util.Map; diff --git a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/api/v1/ui/ConfigScreenFactory.java b/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/api/v1/ui/ConfigScreenFactory.java deleted file mode 100644 index e97fcd8..0000000 --- a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/api/v1/ui/ConfigScreenFactory.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.gitlab.jfronny.libjf.config.api.v1.ui; - -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; -import io.gitlab.jfronny.libjf.config.impl.ui.ConfigScreenFactoryDiscovery; -import net.minecraft.client.gui.screen.Screen; - -@Deprecated -public interface ConfigScreenFactory { - static ConfigScreenFactory getInstance() { - return ConfigScreenFactoryDiscovery.getConfigured(); - } - - S create(ConfigInstance config, Screen parent); - - int getPriority(); -} diff --git a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactory1To2.java b/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactory1To2.java deleted file mode 100644 index 1643f82..0000000 --- a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactory1To2.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.gitlab.jfronny.libjf.config.impl.ui; - -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; -import io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory; -import net.minecraft.client.gui.screen.Screen; - -public record ConfigScreenFactory1To2(io.gitlab.jfronny.libjf.config.api.v1.ui.ConfigScreenFactory impl) implements ConfigScreenFactory> { - @Override - public Built create(ConfigInstance config, Screen parent) { - return new Built<>(impl.create(config, parent)); - } - - @Override - public int getPriority() { - return impl.getPriority(); - } - - public record Built(S screen) implements ConfigScreenFactory.Built { - @Override - public S get() { - return null; - } - - @Override - public void onSave(Runnable action) { - throw new UnsupportedOperationException(); - } - } -} diff --git a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactory2To1.java b/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactory2To1.java deleted file mode 100644 index 3e45b29..0000000 --- a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactory2To1.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.gitlab.jfronny.libjf.config.impl.ui; - -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; -import io.gitlab.jfronny.libjf.config.api.v1.ui.ConfigScreenFactory; -import net.minecraft.client.gui.screen.Screen; - -public record ConfigScreenFactory2To1>(io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory impl) implements ConfigScreenFactory { - @Override - public S create(ConfigInstance config, Screen parent) { - return impl.create(config, parent).get(); - } - - @Override - public int getPriority() { - return impl.getPriority(); - } -} diff --git a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactoryDiscovery.java b/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactoryDiscovery.java deleted file mode 100644 index 48214e7..0000000 --- a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactoryDiscovery.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.gitlab.jfronny.libjf.config.impl.ui; - -import io.gitlab.jfronny.libjf.config.api.v1.ui.ConfigScreenFactory; -import net.fabricmc.loader.api.FabricLoader; - -import java.util.Comparator; -import java.util.List; - -public class ConfigScreenFactoryDiscovery { - private static ConfigScreenFactory discovered1 = null; - private static io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory discovered2 = null; - - @Deprecated - public static ConfigScreenFactory getConfigured() { - if (discovered1 == null) { - List entrypoints = getEntrypoints(); - discovered1 = entrypoints - .stream() - .filter(it -> it instanceof io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory) - .map(it -> (io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory) it) - .max(Comparator.comparing(io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory::getPriority)) - .map(ConfigScreenFactory2To1::new) - .orElseGet(() -> entrypoints - .stream() - .filter(it -> it instanceof ConfigScreenFactory) - .map(it -> (ConfigScreenFactory) it) - .max(Comparator.comparing(ConfigScreenFactory::getPriority)) - .orElseGet(() -> new ConfigScreenFactory2To1(new PlaceholderScreenFactory()))); - } - return discovered1; - } - - public static io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory getConfigured2() { - if (discovered2 == null) { - List entrypoints = getEntrypoints(); - discovered2 = entrypoints - .stream() - .filter(it -> it instanceof io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory) - .map(it -> (io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory) it) - .max(Comparator.comparing(io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory::getPriority)) - .orElseGet(() -> entrypoints - .stream() - .filter(it -> it instanceof ConfigScreenFactory) - .map(it -> (ConfigScreenFactory) it) - .map(ConfigScreenFactory1To2::new) - .max(Comparator.comparing(io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory::getPriority)) - .orElseGet(PlaceholderScreenFactory::new)); - } - return discovered2; - } - - private static List getEntrypoints() { - return FabricLoader.getInstance().getEntrypoints("libjf:config_screen", Object.class); - } -} diff --git a/libjf-config-core-v1/src/client/resources/assets/libjf-config-ui-tiny-v1/lang/en_us.json b/libjf-config-core-v1/src/client/resources/assets/libjf-config-ui-tiny-v1/lang/en_us.json deleted file mode 100644 index c30f9b2..0000000 --- a/libjf-config-core-v1/src/client/resources/assets/libjf-config-ui-tiny-v1/lang/en_us.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "libjf-config-v1.presets": "Presets", - "libjf-config-v1.default": "Default", - "libjf-config-v1.see-also": "See also: %s", - "libjf-config-v1.reset": "Reset", - "libjf-config-core-v1.no-screen": "No screen", - "libjf-config-core-v1.no-screen.description": "No mod for rendering config UIs was discovered. Install LibJF to add one.", - "libjf-config-core-v1.edit": "Edit" -} \ No newline at end of file diff --git a/libjf-config-core-v1/src/main/resources/assets/libjf-config-core-v1/lang/en_us.json b/libjf-config-core-v1/src/main/resources/assets/libjf-config-core-v1/lang/en_us.json deleted file mode 100644 index 91b2da2..0000000 --- a/libjf-config-core-v1/src/main/resources/assets/libjf-config-core-v1/lang/en_us.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "libjf-config-core-v1.jfconfig.title": "LibJF Config", - "libjf-config-core-v1.jfconfig.watchForChanges": "Watch for changes", - "libjf-config-core-v1.jfconfig.watchForChanges.tooltip": "Automatically reload configs when they are changed" -} \ No newline at end of file diff --git a/libjf-config-core-v1/build.gradle.kts b/libjf-config-core-v2/build.gradle.kts similarity index 84% rename from libjf-config-core-v1/build.gradle.kts rename to libjf-config-core-v2/build.gradle.kts index 4bcc048..794dfb7 100644 --- a/libjf-config-core-v1/build.gradle.kts +++ b/libjf-config-core-v2/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } base { - archivesName.set("libjf-config-core-v1") + archivesName.set("libjf-config-core-v2") } dependencies { diff --git a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/api/v2/ui/ConfigScreenFactory.java b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/api/v2/ui/ConfigScreenFactory.java similarity index 90% rename from libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/api/v2/ui/ConfigScreenFactory.java rename to libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/api/v2/ui/ConfigScreenFactory.java index e8a65e8..01b9b41 100644 --- a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/api/v2/ui/ConfigScreenFactory.java +++ b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/api/v2/ui/ConfigScreenFactory.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.libjf.config.api.v2.ui; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; import io.gitlab.jfronny.libjf.config.impl.ui.ConfigScreenFactoryDiscovery; import net.minecraft.client.gui.screen.Screen; diff --git a/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactoryDiscovery.java b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactoryDiscovery.java new file mode 100644 index 0000000..ba5e9fe --- /dev/null +++ b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ConfigScreenFactoryDiscovery.java @@ -0,0 +1,27 @@ +package io.gitlab.jfronny.libjf.config.impl.ui; + +import io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory; +import net.fabricmc.loader.api.FabricLoader; + +import java.util.Comparator; +import java.util.List; + +public class ConfigScreenFactoryDiscovery { + private static ConfigScreenFactory discovered2 = null; + + public static io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory getConfigured2() { + if (discovered2 == null) { + discovered2 = getEntrypoints() + .stream() + .filter(it -> it instanceof io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory) + .>map(it -> (ConfigScreenFactory) it) + .max(Comparator.comparing(io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory::getPriority)) + .orElseGet(PlaceholderScreenFactory::new); + } + return discovered2; + } + + private static List getEntrypoints() { + return FabricLoader.getInstance().getEntrypoints("libjf:config_screen", Object.class); + } +} diff --git a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ModMenuAdapter.java b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ModMenuAdapter.java similarity index 90% rename from libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ModMenuAdapter.java rename to libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ModMenuAdapter.java index dd34880..b906054 100644 --- a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ModMenuAdapter.java +++ b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/ModMenuAdapter.java @@ -3,8 +3,8 @@ package io.gitlab.jfronny.libjf.config.impl.ui; import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ModMenuApi; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigHolder; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; import io.gitlab.jfronny.libjf.config.impl.ConfigCore; import java.util.HashMap; diff --git a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreen.java b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreen.java similarity index 51% rename from libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreen.java rename to libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreen.java index ffed03b..406c466 100644 --- a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreen.java +++ b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreen.java @@ -1,6 +1,5 @@ package io.gitlab.jfronny.libjf.config.impl.ui; -import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.Text; @@ -8,18 +7,14 @@ import java.util.Objects; public class PlaceholderScreen extends Screen { private final Screen parent; - private final Text description = Text.translatable("libjf-config-core-v1.no-screen.description"); + private final Text description = Text.translatable("libjf-config-core-v2.no-screen.description"); protected PlaceholderScreen(Screen parent) { - super(Text.translatable("libjf-config-core-v1.no-screen")); + super(Text.translatable("libjf-config-core-v2.no-screen")); this.parent = parent; - } - - @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { - renderBackground(context); - context.drawCenteredTextWithShadow(textRenderer, description, width / 2, (height - textRenderer.fontHeight) / 2, 0xFFFFFF); - super.render(context, mouseX, mouseY, delta); + addDrawable((context, mouseX, mouseY, delta) -> { + context.drawCenteredTextWithShadow(textRenderer, description, width / 2, (height - textRenderer.fontHeight) / 2, 0xFFFFFF); + }); } @Override diff --git a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreenFactory.java b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreenFactory.java similarity index 93% rename from libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreenFactory.java rename to libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreenFactory.java index c3d580e..b9300fc 100644 --- a/libjf-config-core-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreenFactory.java +++ b/libjf-config-core-v2/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/PlaceholderScreenFactory.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.libjf.config.impl.ui; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; import io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory; import net.minecraft.client.gui.screen.Screen; diff --git a/libjf-config-core-v2/src/client/resources/assets/libjf-config-core/lang/en_us.json b/libjf-config-core-v2/src/client/resources/assets/libjf-config-core/lang/en_us.json new file mode 100644 index 0000000..bfe56a3 --- /dev/null +++ b/libjf-config-core-v2/src/client/resources/assets/libjf-config-core/lang/en_us.json @@ -0,0 +1,12 @@ +{ + "libjf-config-core-v2.jfconfig.title": "LibJF Config", + "libjf-config-core-v2.jfconfig.watchForChanges": "Watch for changes", + "libjf-config-core-v2.jfconfig.watchForChanges.tooltip": "Automatically reload configs when they are changed", + "libjf-config-core-v2.presets": "Presets", + "libjf-config-core-v2.default": "Default", + "libjf-config-core-v2.see-also": "See also: %s", + "libjf-config-core-v2.reset": "Reset", + "libjf-config-core-v2.no-screen": "No screen", + "libjf-config-core-v2.no-screen.description": "No mod for rendering config UIs was discovered. Install LibJF to add one.", + "libjf-config-core-v2.edit": "Edit" +} \ No newline at end of file diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Category.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Category.java similarity index 92% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Category.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Category.java index b24fd31..816260b 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Category.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Category.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; import java.lang.annotation.*; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/ConfigCategory.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigCategory.java similarity index 95% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/ConfigCategory.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigCategory.java index 4d35dc1..f4f0c02 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/ConfigCategory.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigCategory.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; import io.gitlab.jfronny.libjf.LibJf; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/ConfigHolder.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigHolder.java similarity index 97% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/ConfigHolder.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigHolder.java index c18fe67..2d43a2e 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/ConfigHolder.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigHolder.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.impl.ConfigHolderImpl; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/ConfigInstance.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigInstance.java similarity index 90% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/ConfigInstance.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigInstance.java index 38fd34e..e3173a4 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/ConfigInstance.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/ConfigInstance.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; import java.nio.file.Path; import java.util.Optional; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Entry.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Entry.java similarity index 87% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Entry.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Entry.java index 6c6b18c..1a1ce01 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Entry.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Entry.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; import java.lang.annotation.*; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/EntryInfo.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java similarity index 78% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/EntryInfo.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java index cc2cfbb..c3e6290 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/EntryInfo.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java @@ -1,9 +1,7 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; -import io.gitlab.jfronny.gson.JsonElement; -import io.gitlab.jfronny.gson.JsonParseException; import io.gitlab.jfronny.gson.stream.*; -import io.gitlab.jfronny.libjf.config.api.v1.type.Type; +import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.dsl.DslEntryInfo; import org.jetbrains.annotations.ApiStatus; @@ -58,19 +56,6 @@ public interface EntryInfo { */ void fix(); - /** - * Set this entry's value to that of the element - * @param element The element to read from - */ - @Deprecated - default void loadFromJson(JsonElement element) throws IllegalAccessException { - try { - loadFromJson(new JsonTreeReader(element)); - } catch (IOException e) { - throw new JsonParseException("Could not read Json", e); - } - } - /** * Set this entry's value to that of the element * @param reader The reader to read from diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/JfConfig.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/JfConfig.java similarity index 91% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/JfConfig.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/JfConfig.java index 983c646..bee1994 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/JfConfig.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/JfConfig.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; import java.lang.annotation.*; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/JfCustomConfig.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/JfCustomConfig.java similarity index 60% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/JfCustomConfig.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/JfCustomConfig.java index f4b8d1f..d43b7fd 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/JfCustomConfig.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/JfCustomConfig.java @@ -1,6 +1,6 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.DSL; /** * The interface for entrypoints performing custom config registrations diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Preset.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Preset.java similarity index 83% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Preset.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Preset.java index ed45ae6..7f7ddf4 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Preset.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Preset.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; import java.lang.annotation.*; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Verifier.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Verifier.java similarity index 86% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Verifier.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Verifier.java index e23d6a8..c659494 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/Verifier.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/Verifier.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1; +package io.gitlab.jfronny.libjf.config.api.v2; import java.lang.annotation.*; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/CategoryBuilder.java similarity index 89% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/CategoryBuilder.java index 45378fa..af74762 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/CategoryBuilder.java @@ -1,8 +1,9 @@ -package io.gitlab.jfronny.libjf.config.api.v1.dsl; +package io.gitlab.jfronny.libjf.config.api.v2.dsl; import io.gitlab.jfronny.commons.SamWithReceiver; -import io.gitlab.jfronny.libjf.config.api.v1.*; -import io.gitlab.jfronny.libjf.config.api.v1.type.Type; +import io.gitlab.jfronny.libjf.config.api.v2.*; +import io.gitlab.jfronny.libjf.config.api.v2.type.Type; +import io.gitlab.jfronny.libjf.config.impl.ConfigCore; import org.jetbrains.annotations.ApiStatus; import java.util.List; @@ -14,7 +15,7 @@ import java.util.function.Supplier; * @param The class implementing this builder */ public interface CategoryBuilder> { - String CONFIG_PRESET_DEFAULT = "libjf-config-v1.default"; + String CONFIG_PRESET_DEFAULT = ConfigCore.MOD_ID + ".default"; Builder setTranslationPrefix(String translationPrefix); String getTranslationPrefix(); diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/ConfigBuilder.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/ConfigBuilder.java similarity index 87% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/ConfigBuilder.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/ConfigBuilder.java index f7755ff..4266c9f 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/ConfigBuilder.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/ConfigBuilder.java @@ -1,7 +1,7 @@ -package io.gitlab.jfronny.libjf.config.api.v1.dsl; +package io.gitlab.jfronny.libjf.config.api.v2.dsl; import io.gitlab.jfronny.commons.SamWithReceiver; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; import java.nio.file.Path; import java.util.function.Consumer; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/DSL.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/DSL.java similarity index 86% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/DSL.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/DSL.java index b43bd0e..55e7e64 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/DSL.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/DSL.java @@ -1,7 +1,7 @@ -package io.gitlab.jfronny.libjf.config.api.v1.dsl; +package io.gitlab.jfronny.libjf.config.api.v2.dsl; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigHolder; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; import io.gitlab.jfronny.libjf.config.impl.dsl.DSLImpl; /** diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/Migration.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java similarity index 78% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/Migration.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java index 01973d8..31c752c 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/Migration.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1.dsl; +package io.gitlab.jfronny.libjf.config.api.v2.dsl; import io.gitlab.jfronny.gson.stream.JsonReader; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/type/Type.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/type/Type.java similarity index 99% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/type/Type.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/type/Type.java index bdf3cae..c92ca32 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/type/Type.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/type/Type.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.api.v1.type; +package io.gitlab.jfronny.libjf.config.api.v2.type; import org.jetbrains.annotations.Nullable; diff --git a/libjf-config-core-v1/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 similarity index 93% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java index fb5d2ab..53e5637 100644 --- a/libjf-config-core-v1/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,9 +1,9 @@ package io.gitlab.jfronny.libjf.config.impl; import io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolders; -import io.gitlab.jfronny.libjf.config.api.v1.Category; -import io.gitlab.jfronny.libjf.config.api.v1.JfConfig; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder; +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 net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.metadata.CustomValue; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigCore.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigCore.java similarity index 60% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigCore.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigCore.java index bff80d2..75112d0 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigCore.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigCore.java @@ -1,15 +1,17 @@ package io.gitlab.jfronny.libjf.config.impl; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.DSL; public class ConfigCore { - public static final String MOD_ID = "libjf-config-core-v1"; + public static final String MOD_ID = "libjf-config-core-v2"; public static final String MODULE_ID = "libjf:config"; public static boolean watchForChanges = true; public static final ConfigInstance CONFIG_INSTANCE; static { + ConfigHolder.getInstance().migrateFiles(MOD_ID); CONFIG_INSTANCE = DSL.create(MOD_ID).register(builder -> builder .value("watchForChanges", watchForChanges, () -> watchForChanges, b -> watchForChanges = b) ); diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigHolderImpl.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigHolderImpl.java similarity index 95% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigHolderImpl.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigHolderImpl.java index f5c7b04..6bf2d22 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigHolderImpl.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigHolderImpl.java @@ -2,8 +2,8 @@ package io.gitlab.jfronny.libjf.config.impl; import com.google.common.collect.ImmutableMap; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigHolder; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; import net.fabricmc.loader.api.FabricLoader; import org.jetbrains.annotations.ApiStatus; diff --git a/libjf-config-core-v1/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 similarity index 97% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java index eb5bb9a..4babb6e 100644 --- a/libjf-config-core-v1/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 @@ -3,10 +3,10 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; 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.v1.*; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.Migration; -import io.gitlab.jfronny.libjf.config.api.v1.type.Type; +import io.gitlab.jfronny.libjf.config.api.v2.*; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.Migration; +import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import java.util.*; import java.util.function.Consumer; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/ConfigBuilderImpl.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/ConfigBuilderImpl.java similarity index 93% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/ConfigBuilderImpl.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/ConfigBuilderImpl.java index b395e19..625bb2a 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/ConfigBuilderImpl.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/ConfigBuilderImpl.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.ConfigBuilder; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.ConfigBuilder; import net.fabricmc.loader.api.FabricLoader; import java.nio.file.Path; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DSLImpl.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DSLImpl.java similarity index 86% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DSLImpl.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DSLImpl.java index 369f7a0..9a4587f 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DSLImpl.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DSLImpl.java @@ -1,9 +1,9 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigHolder; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.ConfigBuilder; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.ConfigBuilder; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.DSL; public class DSLImpl implements DSL { @Override diff --git a/libjf-config-core-v1/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 similarity index 99% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java index 8369290..8db48d2 100644 --- a/libjf-config-core-v1/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 @@ -4,7 +4,7 @@ import io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolders; import io.gitlab.jfronny.gson.*; import io.gitlab.jfronny.gson.stream.*; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.*; +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; diff --git a/libjf-config-core-v1/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 similarity index 96% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java index b5e3d85..9eb471e 100644 --- a/libjf-config-core-v1/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,8 +1,8 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; import io.gitlab.jfronny.gson.stream.JsonReader; -import io.gitlab.jfronny.libjf.config.api.v1.*; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder; +import io.gitlab.jfronny.libjf.config.api.v2.*; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; import org.jetbrains.annotations.ApiStatus; import java.util.*; diff --git a/libjf-config-core-v1/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 similarity index 93% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java index d997e68..6e7a294 100644 --- a/libjf-config-core-v1/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,8 +1,8 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; import io.gitlab.jfronny.gson.stream.JsonReader; -import io.gitlab.jfronny.libjf.config.api.v1.*; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder; +import io.gitlab.jfronny.libjf.config.api.v2.*; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; import org.jetbrains.annotations.Nullable; import java.nio.file.Path; diff --git a/libjf-config-core-v1/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 similarity index 97% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java index 18498ab..efa7ab1 100644 --- a/libjf-config-core-v1/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 @@ -5,9 +5,9 @@ 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.v1.Entry; -import io.gitlab.jfronny.libjf.config.api.v1.EntryInfo; -import io.gitlab.jfronny.libjf.config.api.v1.type.Type; +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; diff --git a/libjf-config-core-v1/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 similarity index 91% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/entrypoint/JfConfigSafe.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/entrypoint/JfConfigSafe.java index 636a934..948dffe 100644 --- a/libjf-config-core-v1/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 @@ -1,8 +1,8 @@ package io.gitlab.jfronny.libjf.config.impl.entrypoint; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.JfCustomConfig; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL; +import io.gitlab.jfronny.libjf.config.api.v2.JfCustomConfig; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.DSL; import io.gitlab.jfronny.libjf.config.impl.ConfigCore; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.entrypoint.EntrypointContainer; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchService.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchService.java similarity index 100% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchService.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchService.java diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchServiceImpl.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchServiceImpl.java similarity index 98% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchServiceImpl.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchServiceImpl.java index 58e4ed0..05475e7 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchServiceImpl.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/JfConfigWatchServiceImpl.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.libjf.config.impl.watch; import io.gitlab.jfronny.commons.throwable.ThrowingRunnable; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigHolder; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder; import net.fabricmc.loader.api.FabricLoader; import java.io.IOException; diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/ToggleableConfigWatchService.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/ToggleableConfigWatchService.java similarity index 100% rename from libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/ToggleableConfigWatchService.java rename to libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/watch/ToggleableConfigWatchService.java diff --git a/libjf-config-core-v1/src/main/resources/fabric.mod.json b/libjf-config-core-v2/src/main/resources/fabric.mod.json similarity index 93% rename from libjf-config-core-v1/src/main/resources/fabric.mod.json rename to libjf-config-core-v2/src/main/resources/fabric.mod.json index 7c378cb..3a54a89 100644 --- a/libjf-config-core-v1/src/main/resources/fabric.mod.json +++ b/libjf-config-core-v2/src/main/resources/fabric.mod.json @@ -1,6 +1,7 @@ { "schemaVersion": 1, - "id": "libjf-config-core-v1", + "id": "libjf-config-core-v2", + "provides": ["libjf-config-core-v1"], "name": "LibJF Config", "version": "${version}", "authors": ["JFronny"], diff --git a/libjf-config-reflect-v1/build.gradle.kts b/libjf-config-reflect-v1/build.gradle.kts deleted file mode 100644 index 745747a..0000000 --- a/libjf-config-reflect-v1/build.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -import io.gitlab.jfronny.scripts.* - -plugins { - id("jfmod.module") -} - -base { - archivesName.set("libjf-config-reflect-v1") -} - -dependencies { - api(devProject(":libjf-base")) - api(devProject(":libjf-unsafe-v0")) - api(devProject(":libjf-config-core-v1")) -} diff --git a/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/reflect/ReflectiveConfigBuilder.java b/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/reflect/ReflectiveConfigBuilder.java deleted file mode 100644 index c0ac31a..0000000 --- a/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/reflect/ReflectiveConfigBuilder.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.gitlab.jfronny.libjf.config.api.v1.reflect; - -import io.gitlab.jfronny.libjf.config.api.v1.dsl.ConfigBuilder; -import io.gitlab.jfronny.libjf.config.impl.reflect.ReflectiveConfigBuilderImpl; - -public interface ReflectiveConfigBuilder extends ConfigBuilder.ConfigBuilderFunction { - static ReflectiveConfigBuilder of(String id, Class klazz) { - return new ReflectiveConfigBuilderImpl(id, klazz); - } -} diff --git a/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/reflect/ReflectiveConfigBuilderImpl.java b/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/reflect/ReflectiveConfigBuilderImpl.java deleted file mode 100644 index 9639cd9..0000000 --- a/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/reflect/ReflectiveConfigBuilderImpl.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.gitlab.jfronny.libjf.config.impl.reflect; - -import io.gitlab.jfronny.commons.reflect.Reflect; -import io.gitlab.jfronny.commons.throwable.ThrowingConsumer; -import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.*; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.ConfigBuilder; -import io.gitlab.jfronny.libjf.config.api.v1.reflect.ReflectiveConfigBuilder; -import io.gitlab.jfronny.libjf.config.impl.AuxiliaryMetadata; -import io.gitlab.jfronny.libjf.config.impl.dsl.DslEntryInfo; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Objects; -import java.util.function.Function; - -public class ReflectiveConfigBuilderImpl implements ReflectiveConfigBuilder { - private final AuxiliaryMetadata rootMeta; - private final Class rootClass; - private final Class rootTweaker; - private final String id; - - public ReflectiveConfigBuilderImpl(String id, Class klazz) { - this.id = id; - this.rootClass = Objects.requireNonNull(klazz); - JfConfig annotation = klazz.getAnnotation(JfConfig.class); - rootTweaker = annotation.tweaker(); - this.rootMeta = AuxiliaryMetadata.of(annotation).merge(AuxiliaryMetadata.forMod(id)); - } - - @Override - public ConfigBuilder apply(ConfigBuilder builder) { - return applyCategory(builder, rootClass, findTweaker(rootTweaker, ConfigBuilder.class), rootMeta); - } - - private > T applyCategory(T builder, Class configClass, Function tweaker, AuxiliaryMetadata meta) { - meta.applyTo(builder); - for (Field field : configClass.getFields()) { - if (field.isAnnotationPresent(Entry.class)) { - builder.value(DslEntryInfo.ofField(field)); - } - } - for (Method method : configClass.getMethods()) { - try { - if (method.isAnnotationPresent(Preset.class)) { - builder.addPreset(builder.getTranslationPrefix() + method.getName(), ReflectiveConfigBuilderImpl.staticToConsumer(configClass, method).addHandler(e -> LibJf.LOGGER.error("Could not apply preset", e))); - } else if (method.isAnnotationPresent(Verifier.class)) { - builder.addVerifier(ReflectiveConfigBuilderImpl.staticToConsumer(configClass, method).addHandler(e -> LibJf.LOGGER.error("Could not run verifier", e))); - } - } catch (Throwable t) { - LibJf.LOGGER.error("Could not process method " + method.getName() + " of config class " + configClass.getName()); - } - } - - for (Class categoryClass : configClass.getClasses()) { - if (categoryClass.isAnnotationPresent(Category.class)) { - Category annotation = categoryClass.getAnnotation(Category.class); - String name = categoryClass.getSimpleName(); - name = Character.toLowerCase(name.charAt(0)) + name.substring(1); // camelCase - var categoryTweaker = findTweaker(annotation.tweaker(), CategoryBuilder.class); - builder.category(name, builder1 -> applyCategory(builder1, categoryClass, categoryTweaker, AuxiliaryMetadata.of(categoryClass.getAnnotation(Category.class)))); - } - } - - return tweaker.apply(builder); - } - - private Function findTweaker(Class targetClass, Class tweakedClass) { - try { - return Objects.equals(targetClass, void.class) - ? Function.identity() - : Reflect.staticFunction(targetClass, "tweak", tweakedClass, tweakedClass); - } catch (Throwable t) { - LibJf.LOGGER.error("Could not find tweaker " + targetClass + " for mod " + id, t); - return Function.identity(); - } - } - - public static ThrowingConsumer staticToConsumer(Class klazz, Method method) throws Throwable { - Runnable rn = Reflect.staticProcedure(klazz, method.getName()); - return c -> rn.run(); - } -} diff --git a/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/reflect/entrypoint/JfConfigReflectSafe.java b/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/reflect/entrypoint/JfConfigReflectSafe.java deleted file mode 100644 index 36dcb9c..0000000 --- a/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/reflect/entrypoint/JfConfigReflectSafe.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.gitlab.jfronny.libjf.config.impl.reflect.entrypoint; - -import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.*; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL; -import io.gitlab.jfronny.libjf.config.api.v1.reflect.ReflectiveConfigBuilder; -import io.gitlab.jfronny.libjf.config.impl.ConfigCore; -import io.gitlab.jfronny.libjf.config.impl.entrypoint.JfConfigSafe; -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.entrypoint.EntrypointContainer; -import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; - -public class JfConfigReflectSafe implements PreLaunchEntrypoint { - @Override - public void onPreLaunch() { - LibJf.setup(); - for (EntrypointContainer config : FabricLoader.getInstance().getEntrypointContainers(ConfigCore.MODULE_ID, Object.class)) { - registerIfMissing(config.getProvider().getMetadata().getId(), config.getEntrypoint()); - } - } - - public static void registerIfMissing(String modId, Object config) { - if (JfConfigSafe.REGISTERED_MODS.add(modId)) { - ConfigHolder.getInstance().migrateFiles(modId); - if (config instanceof JfCustomConfig cfg) { - cfg.register(DSL.create(modId)); - } else { - Class klazz = config.getClass(); - if (klazz.isAnnotationPresent(JfConfig.class)) { - DSL.create(modId).register(ReflectiveConfigBuilder.of(modId, klazz)); - } else { - LibJf.LOGGER.error("Attempted to register improper config for mod " + modId + " (missing @JfConfig annotation or JfCustomConfig interface)"); - } - } - } - } -} diff --git a/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/reflect/entrypoint/JfConfigUnsafe.java b/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/reflect/entrypoint/JfConfigUnsafe.java deleted file mode 100644 index dce4269..0000000 --- a/libjf-config-reflect-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/reflect/entrypoint/JfConfigUnsafe.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.gitlab.jfronny.libjf.config.impl.reflect.entrypoint; - -import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.impl.ConfigCore; -import io.gitlab.jfronny.libjf.unsafe.DynamicEntry; -import io.gitlab.jfronny.libjf.unsafe.UltraEarlyInit; - -public class JfConfigUnsafe implements UltraEarlyInit { - @Override - public void init() { - DynamicEntry.execute(ConfigCore.MODULE_ID, Object.class, - s -> JfConfigReflectSafe.registerIfMissing(s.modId(), s.instance()) - ); - LibJf.LOGGER.info("Finished LibJF config entrypoint"); - } -} diff --git a/libjf-config-reflect-v1/src/main/resources/fabric.mod.json b/libjf-config-reflect-v1/src/main/resources/fabric.mod.json deleted file mode 100644 index 98c1618..0000000 --- a/libjf-config-reflect-v1/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "schemaVersion": 1, - "id": "libjf-config-reflect-v1", - "name": "LibJF Config Reflect", - "version": "${version}", - "authors": ["JFronny"], - "contact": { - "email": "projects.contact@frohnmeyer-wds.de", - "homepage": "https://jfronny.gitlab.io", - "issues": "https://git.frohnmeyer-wds.de/JfMods/LibJF/issues", - "sources": "https://git.frohnmeyer-wds.de/JfMods/LibJF" - }, - "license": "MIT", - "environment": "*", - "entrypoints": { - "libjf:preEarly": [ - "io.gitlab.jfronny.libjf.config.impl.reflect.entrypoint.JfConfigUnsafe" - ], - "preLaunch": [ - "io.gitlab.jfronny.libjf.config.impl.reflect.entrypoint.JfConfigReflectSafe" - ] - }, - "depends": { - "fabricloader": ">=0.12.0", - "minecraft": "*", - "libjf-base": ">=${version}", - "libjf-unsafe-v0": ">=${version}", - "libjf-config-core-v1": ">=${version}" - }, - "custom": { - "modmenu": { - "badges": ["library"], - "parent": "libjf" - } - } -} diff --git a/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfig.java b/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfig.java deleted file mode 100644 index 091eff2..0000000 --- a/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfig.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.gitlab.jfronny.libjf.config.test.reflect; - -import io.gitlab.jfronny.commons.serialize.gson.api.v1.Ignore; -import io.gitlab.jfronny.libjf.config.api.v1.*; - -import java.util.ArrayList; -import java.util.List; - -@JfConfig(referencedConfigs = {"libjf-web-v0"}, tweaker = TestConfigTweaker.class) -public class TestConfig { - @Entry public static boolean disablePacks = false; - @Entry public static Boolean disablePacks2 = false; - @Entry public static int intTest = 20; - @Entry(min = -5, max = 12) public static int intTestB = 20; - @Entry(min = -6) public static float floatTest = -5; - @Entry(min = 2, max = 21) public static double doubleTest = 20; - @Entry public static String dieStr = "lolz"; - @Entry @Ignore public static String guiOnlyStr = "lolz"; - public static String gsonOnlyStr = "lolz"; - @Entry public static Test enumTest = Test.Test; - @Entry public static List stringList; - - @Preset - public static void moskau() { - disablePacks = true; - disablePacks2 = true; - intTest = -5; - floatTest = -6; - doubleTest = 4; - dieStr = "Moskau"; - } - - @Verifier - public static void setIntTestIfDisable() { - if (disablePacks) intTest = 0; - } - - @Verifier - public static void stringListVerifier() { - if (stringList == null) stringList = new ArrayList<>(List.of("Obama")); - } - - public enum Test { - Test, ER - } - - @Category - public static class Subcategory { - @Entry public static boolean boolInSub = false; - @Entry public static int intIbSub = 15; - - @Category - public static class Inception { - @Entry public static Test yesEnum = Test.ER; - } - } -} diff --git a/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfigTweaker.java b/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfigTweaker.java deleted file mode 100644 index f1c74f3..0000000 --- a/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfigTweaker.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.gitlab.jfronny.libjf.config.test.reflect; - -import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.ConfigBuilder; - -import java.util.Objects; - -public class TestConfigTweaker { - public static ConfigBuilder tweak(ConfigBuilder builder) { - if (!Objects.equals("libjf-config-reflect-v1-testmod", builder.getId())) throw new IllegalStateException("No!"); - LibJf.LOGGER.info("Called config tweaker"); - return builder.addMigration("joe", reader -> { - TestConfig.disablePacks = reader.nextBoolean(); - }); - } -} diff --git a/libjf-config-reflect-v1/src/testmod/resources/assets/libjf-config-v0-testmod/lang/en_us.json b/libjf-config-reflect-v1/src/testmod/resources/assets/libjf-config-v0-testmod/lang/en_us.json deleted file mode 100644 index 464230d..0000000 --- a/libjf-config-reflect-v1/src/testmod/resources/assets/libjf-config-v0-testmod/lang/en_us.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "libjf-config-reflect-v1-testmod.jfconfig.title": "JfConfig example", - "libjf-config-reflect-v1-testmod.jfconfig.disablePacks": "Disable resource packs", - "libjf-config-reflect-v1-testmod.jfconfig.intTest": "Int Test", - "libjf-config-reflect-v1-testmod.jfconfig.decimalTest": "Decimal Test", - "libjf-config-reflect-v1-testmod.jfconfig.dieStr": "String Test", - "libjf-config-reflect-v1-testmod.jfconfig.gsonOnlyStr.tooltip": "George", - "libjf-config-reflect-v1-testmod.jfconfig.enumTest": "Enum Test", - "libjf-config-reflect-v1-testmod.jfconfig.enumTest.tooltip": "Enum Test Tooltip", - "libjf-config-reflect-v1-testmod.jfconfig.enum.Test.Test": "Test", - "libjf-config-reflect-v1-testmod.jfconfig.enum.Test.ER": "ER", - "libjf-config-reflect-v1-testmod.jfconfig.moskau": "Moskau", - "libjf-config-reflect-v1-testmod.jfconfig.stringList": "String list", - "libjf-config-reflect-v1-testmod.jfconfig.stringList.tooltip": "Tooltip of the String list" -} \ No newline at end of file diff --git a/libjf-config-reflect-v1/src/testmod/resources/fabric.mod.json b/libjf-config-reflect-v1/src/testmod/resources/fabric.mod.json deleted file mode 100644 index 9cacc7e..0000000 --- a/libjf-config-reflect-v1/src/testmod/resources/fabric.mod.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "schemaVersion": 1, - "id": "libjf-config-reflect-v1-testmod", - "name": "LibJF Config Reflect", - "version": "1.0", - "environment": "*", - "entrypoints": { - "libjf:config": [ - "io.gitlab.jfronny.libjf.config.test.reflect.TestConfig" - ] - }, - "custom": { - "modmenu": { - "parent": "libjf-testmod" - } - } -} \ No newline at end of file diff --git a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/api/v1/ui/tiny/ConfigScreen.java b/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/api/v1/ui/tiny/ConfigScreen.java deleted file mode 100644 index b18477a..0000000 --- a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/api/v1/ui/tiny/ConfigScreen.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.gitlab.jfronny.libjf.config.api.v1.ui.tiny; - -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; -import io.gitlab.jfronny.libjf.config.impl.ui.tiny.TinyConfigScreenFactory; -import net.minecraft.client.gui.screen.Screen; - -@Deprecated -public interface ConfigScreen { - TinyConfigScreenFactory FACTORY = new TinyConfigScreenFactory(); - static Screen create(ConfigInstance config, Screen parent) { - return FACTORY.create(config, parent).get(); - } -} diff --git a/libjf-config-ui-tiny-v1/src/client/resources/assets/libjf-config-ui-tiny-v1/lang/en_us.json b/libjf-config-ui-tiny-v1/src/client/resources/assets/libjf-config-ui-tiny-v1/lang/en_us.json deleted file mode 100644 index e33841b..0000000 --- a/libjf-config-ui-tiny-v1/src/client/resources/assets/libjf-config-ui-tiny-v1/lang/en_us.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "libjf-config-ui-tiny-v1.entry.json.read.fail.title": "Could not read", - "libjf-config-ui-tiny-v1.entry.json.read.fail.description": "The given entry could not be stringified. Please edit the config manually" -} \ No newline at end of file diff --git a/libjf-config-ui-tiny-v1/src/testmod/resources/assets/libjf-config-ui-tiny-v1-testmod/lang/en_us.json b/libjf-config-ui-tiny-v1/src/testmod/resources/assets/libjf-config-ui-tiny-v1-testmod/lang/en_us.json deleted file mode 100644 index a34336e..0000000 --- a/libjf-config-ui-tiny-v1/src/testmod/resources/assets/libjf-config-ui-tiny-v1-testmod/lang/en_us.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "libjf-config-ui-tiny-v1-testmod.jfconfig.title": "JfConfig Tiny Example", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca1.title": "Category 1", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca1.tooltip": "This is category 1\nIt has an excessively long description to test multiline descriptions and wrapping, which are required for this to look good.\nThis is supported btw.", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca1.value1": "Value 1", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca1.doubleValue": "Double Value", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca2.title": "Category 2", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca2.tooltip": "This is category 2", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca2.value2": "Value 2", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca3.title": "Category 3", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca3.tooltip": "This is category 3", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca3.value3": "Value 3", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca4.title": "Category 4", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca4.tooltip": "This is category 4", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca4.value4": "Value 4", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca5.title": "Category 5", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca5.tooltip": "This is category 5", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca5.value5": "Value 5", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca6.title": "Category 6", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca6.tooltip": "This is category 6", - "libjf-config-ui-tiny-v1-testmod.jfconfig.ca6.value6": "Value 6" -} \ No newline at end of file diff --git a/libjf-config-ui-tiny-v1/build.gradle.kts b/libjf-config-ui-tiny/build.gradle.kts similarity index 73% rename from libjf-config-ui-tiny-v1/build.gradle.kts rename to libjf-config-ui-tiny/build.gradle.kts index a8fd5ce..4cfa50c 100644 --- a/libjf-config-ui-tiny-v1/build.gradle.kts +++ b/libjf-config-ui-tiny/build.gradle.kts @@ -5,12 +5,12 @@ plugins { } base { - archivesName.set("libjf-config-ui-tiny-v1") + archivesName.set("libjf-config-ui-tiny") } dependencies { val fabricVersion: String by rootProject.extra api(devProject(":libjf-base")) - api(devProject(":libjf-config-core-v1")) + api(devProject(":libjf-config-core-v2")) include(fabricApi.module("fabric-resource-loader-v0", fabricVersion)) } diff --git a/libjf-config-ui-tiny-v1/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 similarity index 95% rename from libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/EditorScreen.java rename to libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/EditorScreen.java index ae15b8a..a935af8 100644 --- a/libjf-config-ui-tiny-v1/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 @@ -11,6 +11,7 @@ import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.render.RenderLayer; import net.minecraft.client.util.NarratorManager; import net.minecraft.client.util.SelectionManager; import net.minecraft.client.util.math.Rect2i; @@ -283,7 +284,7 @@ public class EditorScreen extends ScreenWithSaveHook { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { - renderBackground(context); + super.render(context, mouseX, mouseY, delta); if (subtitle == null) { context.drawCenteredTextWithShadow(textRenderer, title, width / 2, (HEADER_SIZE - textRenderer.fontHeight) / 2, 0xFFFFFF); } else { @@ -292,9 +293,12 @@ public class EditorScreen extends ScreenWithSaveHook { } this.setFocused(null); + 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, width - SCROLLBAR_SIZE, height - FOOTER_SIZE + (int)scrollAmount, width - SCROLLBAR_SIZE, height - HEADER_SIZE - FOOTER_SIZE, 32, 32); + 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); } @@ -307,20 +311,17 @@ public class EditorScreen extends ScreenWithSaveHook { this.drawCursor(context, pageContent.position); context.disableScissor(); - int i = this.getScrollbarPositionX(); - int j = i + 6; - int m; - if ((m = this.getMaxScroll()) > 0) { + int scrollbarX = this.getScrollbarPositionX(); + int scrollbarXEnd = scrollbarX + 6; + if (showScrollbar) { int n = (getViewportHeight() * getViewportHeight()) / getMaxPosition(); n = MathHelper.clamp(n, 32, getViewportHeight() - 8); - int o = (int)scrollAmount * (getViewportHeight() - n) / m + HEADER_SIZE; + int o = (int)scrollAmount * (getViewportHeight() - n) / maxScroll + HEADER_SIZE; if (o < HEADER_SIZE) o = HEADER_SIZE; - context.fill(i, HEADER_SIZE, j, height - FOOTER_SIZE, 0xFF000000); - context.fill(i, o, j, o + n, 0xFF808080); - context.fill(i, o, j - 1, o + n - 1, 0xFFC0C0C0); + context.fill(scrollbarX, HEADER_SIZE, scrollbarXEnd, height - FOOTER_SIZE, 0xFF000000); + context.fill(scrollbarX, o, scrollbarXEnd, o + n, 0xFF808080); + context.fill(scrollbarX, o, scrollbarXEnd - 1, o + n - 1, 0xFFC0C0C0); } - - super.render(context, mouseX, mouseY, delta); } private void drawCursor(DrawContext context, Position position) { @@ -331,16 +332,13 @@ public class EditorScreen extends ScreenWithSaveHook { } private void drawSelection(DrawContext context, Rect2i[] selectionRectangles) { - RenderSystem.enableColorLogicOp(); - RenderSystem.logicOp(GlStateManager.LogicOp.OR_REVERSE); for (Rect2i rect2i : selectionRectangles) { int i = rect2i.getX(); int j = rect2i.getY(); int k = i + rect2i.getWidth(); int l = j + rect2i.getHeight(); - context.fill(i, j, k, l, 0xFF0000FF); + context.fill(RenderLayer.getGuiTextHighlight(), i, j, k, l, 0xFF0000FF); } - RenderSystem.disableColorLogicOp(); } private Position screenPositionToAbsolutePosition(Position position) { @@ -409,8 +407,8 @@ public class EditorScreen extends ScreenWithSaveHook { } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - setScrollAmount(scrollAmount - amount * textRenderer.fontHeight * 2); + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + setScrollAmount(scrollAmount - verticalAmount * textRenderer.fontHeight * 2); return true; } diff --git a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/Placeholder.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/Placeholder.java similarity index 95% rename from libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/Placeholder.java rename to libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/Placeholder.java index 27bb6e2..9a39524 100644 --- a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/Placeholder.java +++ b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/Placeholder.java @@ -4,7 +4,6 @@ import net.minecraft.client.gui.*; import net.minecraft.client.gui.navigation.GuiNavigation; import net.minecraft.client.gui.navigation.GuiNavigationPath; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -import net.minecraft.client.util.math.MatrixStack; import org.jetbrains.annotations.Nullable; public final class Placeholder implements Element, Selectable, Drawable { @@ -63,8 +62,8 @@ public final class Placeholder implem } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - return child.mouseScrolled(mouseX, mouseY, amount); + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + return child.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); } @Override diff --git a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/ScreenWithSaveHook.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/ScreenWithSaveHook.java similarity index 100% rename from libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/ScreenWithSaveHook.java rename to libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/ScreenWithSaveHook.java diff --git a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java similarity index 95% rename from libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java rename to libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java index 3bdd33f..cb7d499 100644 --- a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java +++ b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java @@ -2,8 +2,9 @@ package io.gitlab.jfronny.libjf.config.impl.ui.tiny; import io.gitlab.jfronny.commons.throwable.Try; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigCategory; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder; +import io.gitlab.jfronny.libjf.config.api.v2.ConfigCategory; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; +import io.gitlab.jfronny.libjf.config.impl.ConfigCore; import io.gitlab.jfronny.libjf.config.impl.entrypoint.JfConfigSafe; import io.gitlab.jfronny.libjf.config.impl.ui.tiny.entry.EntryListWidget; import io.gitlab.jfronny.libjf.config.impl.ui.tiny.entry.WidgetState; @@ -70,12 +71,6 @@ public class TinyConfigScreen extends ScreenWithSaveHook { && JfConfigSafe.TRANSLATION_SUPPLIER.apply(config.getTranslationPrefix() + "tooltip") == null; } - @Override - public void tick() { - super.tick(); - tabManager.tick(); - } - @Override protected void init() { super.init(); @@ -111,13 +106,13 @@ public class TinyConfigScreen extends ScreenWithSaveHook { this.addDrawableChild(done); if (tabs.size() == 1 && !config.getPresets().isEmpty()) { - this.addDrawableChild(ButtonWidget.builder(Text.translatable("libjf-config-v1.presets"), + this.addDrawableChild(ButtonWidget.builder(Text.translatable(ConfigCore.MOD_ID + ".presets"), button -> Objects.requireNonNull(client).setScreen(new PresetsScreen(this, config, this::afterSelectPreset))) .dimensions(4, 6, 80, 20) .build()); } - this.addSelectableChild(this.placeholder); + this.addDrawableChild(this.placeholder); // Sizing is also done in TinyConfigTab. Keep these in sync! tabManager.setTabArea(new ScreenRect(0, 32, width, height - 68)); @@ -167,8 +162,7 @@ public class TinyConfigScreen extends ScreenWithSaveHook { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { - this.renderBackground(context); - this.placeholder.render(context, mouseX, mouseY, delta); + super.render(context, mouseX, mouseY, delta); if (tabs.size() == 1) context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 16 - textRenderer.fontHeight, 0xFFFFFF); @@ -192,7 +186,6 @@ public class TinyConfigScreen extends ScreenWithSaveHook { } } } - super.render(context, mouseX, mouseY, delta); } @Override diff --git a/libjf-config-ui-tiny-v1/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 similarity index 90% rename from libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java rename to libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java index 9902980..b51421d 100644 --- a/libjf-config-ui-tiny-v1/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 @@ -2,10 +2,10 @@ package io.gitlab.jfronny.libjf.config.impl.ui.tiny; import io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolders; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; -import io.gitlab.jfronny.libjf.config.api.v1.EntryInfo; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder; -import io.gitlab.jfronny.libjf.config.api.v1.type.Type; +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 net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; @@ -45,8 +45,8 @@ public class TinyConfigScreenFactory implements ConfigScreenFactory new PresetsScreen(screen, config, screen::afterSelectPreset)); } @@ -51,7 +52,7 @@ public class TinyConfigTab implements Tab { for (WidgetState info : widgets) { MutableText name = Text.translatable(config.getTranslationPrefix() + info.entry.getName()); WidgetFactory.Widget control = info.factory == null ? null : info.factory.build(screen, textRenderer); - ButtonWidget resetButton = ButtonWidget.builder(Text.translatable("libjf-config-v1.reset"), (button -> info.reset())) + ButtonWidget resetButton = ButtonWidget.builder(Text.translatable(ConfigCore.MOD_ID + ".reset"), (button -> info.reset())) .dimensions(screen.width - 155, 0, 40, 20) .build(); BooleanSupplier resetVisible = () -> { @@ -68,7 +69,7 @@ public class TinyConfigTab implements Tab { } for (ConfigInstance ci : config.getReferencedConfigs()) { if (ci != null) { - this.list.addReference(Text.translatable("libjf-config-v1.see-also", TinyConfigScreen.getTitle(ci.getTranslationPrefix())), + this.list.addReference(Text.translatable(ConfigCore.MOD_ID + ".see-also", TinyConfigScreen.getTitle(ci.getTranslationPrefix())), () -> new TinyConfigScreen(ci, screen)); } } @@ -89,11 +90,6 @@ public class TinyConfigTab implements Tab { list.refreshGrid(tabArea); } - @Override - public void tick() { - Tab.super.tick(); - } - public EntryListWidget getList() { return list; } diff --git a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigTabWrapper.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigTabWrapper.java similarity index 100% rename from libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigTabWrapper.java rename to libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigTabWrapper.java diff --git a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/CustomSlider.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/CustomSlider.java similarity index 100% rename from libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/CustomSlider.java rename to libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/CustomSlider.java diff --git a/libjf-config-ui-tiny-v1/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 similarity index 95% rename from libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java rename to libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java index b437d57..8ce50f4 100644 --- a/libjf-config-ui-tiny-v1/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 @@ -4,10 +4,9 @@ import io.gitlab.jfronny.commons.ref.R; import io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolders; import io.gitlab.jfronny.commons.throwable.Try; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.ConfigCategory; -import io.gitlab.jfronny.libjf.config.api.v1.EntryInfo; -import io.gitlab.jfronny.libjf.config.api.v1.type.Type; -import io.gitlab.jfronny.libjf.config.api.v1.ui.tiny.WidgetFactory; +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.type.Type; import io.gitlab.jfronny.libjf.config.impl.ui.tiny.EditorScreen; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -157,7 +156,7 @@ public class EntryInfoWidgetBuilder { state.managedTemp = false; state.tempValue = null; return (screen, textRenderer) -> { - final ButtonWidget button = ButtonWidget.builder(Text.translatable("libjf-config-core-v1.edit"), $ -> { + final ButtonWidget button = ButtonWidget.builder(Text.translatable("libjf-config-core-v2.edit"), $ -> { final String jsonified; if (state.tempValue == null) { try { @@ -167,8 +166,8 @@ public class EntryInfoWidgetBuilder { SystemToast.add( screen.getClient().getToastManager(), SystemToast.Type.PACK_LOAD_FAILURE, - Text.translatable("libjf-config-ui-tiny-v1.entry.json.read.fail.title"), - Text.translatable("libjf-config-ui-tiny-v1.entry.json.read.fail.description") + Text.translatable("libjf-config-ui-tiny.entry.json.read.fail.title"), + Text.translatable("libjf-config-ui-tiny.entry.json.read.fail.description") ); return; } @@ -190,8 +189,8 @@ public class EntryInfoWidgetBuilder { SystemToast.add( screen.getClient().getToastManager(), SystemToast.Type.PACK_LOAD_FAILURE, - Text.translatable("libjf-config-ui-tiny-v1.entry.json.write.fail.title"), - Text.translatable("libjf-config-ui-tiny-v1.entry.json.write.fail.description") + Text.translatable("libjf-config-ui-tiny.entry.json.write.fail.title"), + Text.translatable("libjf-config-ui-tiny.entry.json.write.fail.description") ); state.tempValue = json; } diff --git a/libjf-config-ui-tiny-v1/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 similarity index 99% rename from libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryListWidget.java rename to libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryListWidget.java index f470c32..cde8610 100644 --- a/libjf-config-ui-tiny-v1/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 @@ -27,7 +27,6 @@ public class EntryListWidget extends ElementListWidget entry : config.getPresets().entrySet()) { - this.list.addButton(ButtonWidget.builder(Text.translatable(entry.getKey()), + list.addButton(ButtonWidget.builder(Text.translatable(entry.getKey()), button -> { LibJf.LOGGER.info("Preset selected: " + entry.getKey()); entry.getValue().run(); @@ -43,7 +42,7 @@ public class PresetsScreen extends Screen { .dimensions(width / 2 - 100, 0, 200, 20) .build()); } - this.addSelectableChild(this.list); + this.addDrawableChild(list); } @Override @@ -53,11 +52,7 @@ public class PresetsScreen extends Screen { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { - this.renderBackground(context); - this.list.render(context, mouseX, mouseY, delta); - - context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 16 - textRenderer.fontHeight / 2, 0xFFFFFF); - super.render(context, mouseX, mouseY, delta); + context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 16 - textRenderer.fontHeight / 2, 0xFFFFFF); } } diff --git a/libjf-config-ui-tiny/src/client/resources/assets/libjf-config-ui-tiny/lang/en_us.json b/libjf-config-ui-tiny/src/client/resources/assets/libjf-config-ui-tiny/lang/en_us.json new file mode 100644 index 0000000..1bd4da7 --- /dev/null +++ b/libjf-config-ui-tiny/src/client/resources/assets/libjf-config-ui-tiny/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "libjf-config-ui-tiny.entry.json.read.fail.title": "Could not read", + "libjf-config-ui-tiny.entry.json.read.fail.description": "The given entry could not be stringified. Please edit the config manually" +} \ No newline at end of file diff --git a/libjf-config-ui-tiny-v1/src/main/resources/fabric.mod.json b/libjf-config-ui-tiny/src/main/resources/fabric.mod.json similarity index 90% rename from libjf-config-ui-tiny-v1/src/main/resources/fabric.mod.json rename to libjf-config-ui-tiny/src/main/resources/fabric.mod.json index a1ff522..65c4e50 100644 --- a/libjf-config-ui-tiny-v1/src/main/resources/fabric.mod.json +++ b/libjf-config-ui-tiny/src/main/resources/fabric.mod.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "id": "libjf-config-ui-tiny-v1", + "id": "libjf-config-ui-tiny", "name": "LibJF Config UI: Tiny", "version": "${version}", "authors": ["JFronny"], @@ -20,7 +20,7 @@ "minecraft": "*", "fabric-resource-loader-v0": "*", "libjf-base": ">=${version}", - "libjf-config-core-v1": ">=${version}" + "libjf-config-core-v2": ">=${version}" }, "custom": { "modmenu": { diff --git a/libjf-config-ui-tiny-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java b/libjf-config-ui-tiny/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java similarity index 92% rename from libjf-config-ui-tiny-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java rename to libjf-config-ui-tiny/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java index 15781f1..4fe7487 100644 --- a/libjf-config-ui-tiny-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java +++ b/libjf-config-ui-tiny/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.libjf.config.test.tiny; -import io.gitlab.jfronny.libjf.config.api.v1.JfCustomConfig; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL; +import io.gitlab.jfronny.libjf.config.api.v2.JfCustomConfig; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.DSL; public class TestConfig implements JfCustomConfig { private int value1 = 0; diff --git a/libjf-config-ui-tiny/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/mixin/OptionsScreenMixin.java b/libjf-config-ui-tiny/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/mixin/OptionsScreenMixin.java new file mode 100644 index 0000000..e195779 --- /dev/null +++ b/libjf-config-ui-tiny/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/mixin/OptionsScreenMixin.java @@ -0,0 +1,38 @@ +package io.gitlab.jfronny.libjf.config.test.tiny.mixin; + +import io.gitlab.jfronny.libjf.config.api.v2.ConfigHolder; +import io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.option.OptionsScreen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.GridWidget; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.function.Supplier; + +@Mixin(OptionsScreen.class) +public abstract class OptionsScreenMixin extends Screen { + @Shadow @Final private Screen parent; + + @Shadow protected abstract ButtonWidget createButton(Text message, Supplier screenSupplier); + + protected OptionsScreenMixin(Text title) { + super(title); + } + + @Inject(method = "init()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/GridWidget;refreshPositions()V"), locals = LocalCapture.CAPTURE_FAILHARD) + void injectButton(CallbackInfo ci, GridWidget gridWidget, GridWidget.Adder adder) { + ConfigHolder.getInstance().getRegistered().forEach((key, config) -> { + adder.add( + createButton(Text.translatable(key + ".jfconfig.title"), () -> ConfigScreenFactory.getInstance() + .create(config, this) + .get()) + ); + }); + } +} diff --git a/libjf-config-ui-tiny/src/testmod/resources/assets/libjf-config-ui-tiny-testmod/lang/en_us.json b/libjf-config-ui-tiny/src/testmod/resources/assets/libjf-config-ui-tiny-testmod/lang/en_us.json new file mode 100644 index 0000000..c2ae08f --- /dev/null +++ b/libjf-config-ui-tiny/src/testmod/resources/assets/libjf-config-ui-tiny-testmod/lang/en_us.json @@ -0,0 +1,22 @@ +{ + "libjf-config-ui-tiny-testmod.jfconfig.title": "JfConfig Tiny Example", + "libjf-config-ui-tiny-testmod.jfconfig.ca1.title": "Category 1", + "libjf-config-ui-tiny-testmod.jfconfig.ca1.tooltip": "This is category 1\nIt has an excessively long description to test multiline descriptions and wrapping, which are required for this to look good.\nThis is supported btw.", + "libjf-config-ui-tiny-testmod.jfconfig.ca1.value1": "Value 1", + "libjf-config-ui-tiny-testmod.jfconfig.ca1.doubleValue": "Double Value", + "libjf-config-ui-tiny-testmod.jfconfig.ca2.title": "Category 2", + "libjf-config-ui-tiny-testmod.jfconfig.ca2.tooltip": "This is category 2", + "libjf-config-ui-tiny-testmod.jfconfig.ca2.value2": "Value 2", + "libjf-config-ui-tiny-testmod.jfconfig.ca3.title": "Category 3", + "libjf-config-ui-tiny-testmod.jfconfig.ca3.tooltip": "This is category 3", + "libjf-config-ui-tiny-testmod.jfconfig.ca3.value3": "Value 3", + "libjf-config-ui-tiny-testmod.jfconfig.ca4.title": "Category 4", + "libjf-config-ui-tiny-testmod.jfconfig.ca4.tooltip": "This is category 4", + "libjf-config-ui-tiny-testmod.jfconfig.ca4.value4": "Value 4", + "libjf-config-ui-tiny-testmod.jfconfig.ca5.title": "Category 5", + "libjf-config-ui-tiny-testmod.jfconfig.ca5.tooltip": "This is category 5", + "libjf-config-ui-tiny-testmod.jfconfig.ca5.value5": "Value 5", + "libjf-config-ui-tiny-testmod.jfconfig.ca6.title": "Category 6", + "libjf-config-ui-tiny-testmod.jfconfig.ca6.tooltip": "This is category 6", + "libjf-config-ui-tiny-testmod.jfconfig.ca6.value6": "Value 6" +} diff --git a/libjf-config-ui-tiny-v1/src/testmod/resources/fabric.mod.json b/libjf-config-ui-tiny/src/testmod/resources/fabric.mod.json similarity index 74% rename from libjf-config-ui-tiny-v1/src/testmod/resources/fabric.mod.json rename to libjf-config-ui-tiny/src/testmod/resources/fabric.mod.json index e3315aa..d7c5c53 100644 --- a/libjf-config-ui-tiny-v1/src/testmod/resources/fabric.mod.json +++ b/libjf-config-ui-tiny/src/testmod/resources/fabric.mod.json @@ -1,9 +1,10 @@ { "schemaVersion": 1, - "id": "libjf-config-ui-tiny-v1-testmod", + "id": "libjf-config-ui-tiny-testmod", "name": "LibJF Config UI: Tiny", "version": "1.0", "environment": "*", + "mixins": ["libjf-config-ui-tiny-testmod.mixins.json"], "entrypoints": { "libjf:config": [ "io.gitlab.jfronny.libjf.config.test.tiny.TestConfig" diff --git a/libjf-config-ui-tiny/src/testmod/resources/libjf-config-ui-tiny-testmod.mixins.json b/libjf-config-ui-tiny/src/testmod/resources/libjf-config-ui-tiny-testmod.mixins.json new file mode 100644 index 0000000..6253d36 --- /dev/null +++ b/libjf-config-ui-tiny/src/testmod/resources/libjf-config-ui-tiny-testmod.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.gitlab.jfronny.libjf.config.test.tiny.mixin", + "compatibilityLevel": "JAVA_16", + "mixins": [ + ], + "client": [ + "OptionsScreenMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} 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 ea42e55..308ea49 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 @@ -57,8 +57,8 @@ public class UserResourceEvents { public static final Event FIND_RESOURCE = EventFactory.createArrayBacked(FindResource.class, listeners -> (type, namespace, prefix, previous, pack) -> { ResourcePack.ResultConsumer lazy = previous; - for (FindResource listener : listeners) { - lazy = listener.findResources(type, namespace, prefix, lazy, pack); + for (int i = listeners.length - 1; i >= 0; i--) { + lazy = listeners[i].findResources(type, namespace, prefix, lazy, pack); } return lazy; }); diff --git a/libjf-mainhttp-v0/build.gradle.kts b/libjf-mainhttp-v0/build.gradle.kts new file mode 100644 index 0000000..fd0c61f --- /dev/null +++ b/libjf-mainhttp-v0/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + id("jfmod.module") +} + +base { + archivesName.set("libjf-mainhttp-v0") +} + +dependencies { + val fabricVersion: String by rootProject.extra + implementation(fabricApi.module("fabric-api-base", fabricVersion)) +} diff --git a/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/api/v0/MainHttpHandler.java b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/api/v0/MainHttpHandler.java new file mode 100644 index 0000000..e1af3e2 --- /dev/null +++ b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/api/v0/MainHttpHandler.java @@ -0,0 +1,11 @@ +package io.gitlab.jfronny.libjf.mainhttp.api.v0; + +import org.jetbrains.annotations.Nullable; + +public interface MainHttpHandler { + default boolean isActive() { + return true; + } + + byte @Nullable [] handle(byte[] request); +} diff --git a/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/api/v0/ServerState.java b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/api/v0/ServerState.java new file mode 100644 index 0000000..15d9132 --- /dev/null +++ b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/api/v0/ServerState.java @@ -0,0 +1,17 @@ +package io.gitlab.jfronny.libjf.mainhttp.api.v0; + +import io.gitlab.jfronny.libjf.mainhttp.impl.MainHttp; + +public interface ServerState { + static void onActivate(Runnable listener) { + MainHttp.ON_ACTIVATE.register(listener); + } + + static boolean isActive() { + return !MainHttp.GAME_PORT.isEmpty(); + } + + static int getPort() { + return MainHttp.GAME_PORT.getTopmost(); + } +} diff --git a/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/HttpDecoder.java b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/HttpDecoder.java new file mode 100644 index 0000000..28897eb --- /dev/null +++ b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/HttpDecoder.java @@ -0,0 +1,58 @@ +package io.gitlab.jfronny.libjf.mainhttp.impl; + +import io.gitlab.jfronny.libjf.mainhttp.impl.util.Trie; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class HttpDecoder extends ChannelInboundHandlerAdapter { + private static final Trie METHOD = Trie.of(List.of( + "GET", + "HEAD", + "POST", + "PUT", + "PATCH", + "DELETE", + + "OPTIONS", "TRACE", "CONNECT" + )); + + @Override + public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) throws Exception { + ByteBuf buf = (ByteBuf) msg; + buf.markReaderIndex(); + boolean passOn = true; + try { + // Check whether buf starts with an HTTP method, as a request would + Trie current = METHOD; + while (buf.isReadable() + && current != null + && current.content == null) + current = current.next.get((char) buf.readByte()); + if (current == null || current.content == null) return; + // Method identified, this is HTTP! + passOn = false; + // Read all data from buffer + buf.resetReaderIndex(); + byte[] data = new byte[buf.readableBytes()]; + buf.readBytes(data); + buf.release(); + // Process request + ctx.pipeline() + .firstContext() + .writeAndFlush(Unpooled.wrappedBuffer(MainHttp.handle(data))) + .addListener(ChannelFutureListener.CLOSE); + } catch (RuntimeException re) { + MainHttp.LOGGER.error("Could not process HTTP", re); + } finally { + if (passOn) { + buf.resetReaderIndex(); + ctx.channel().pipeline().remove(this); + ctx.fireChannelRead(msg); + } + } + } +} diff --git a/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/MainHttp.java b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/MainHttp.java new file mode 100644 index 0000000..f820821 --- /dev/null +++ b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/MainHttp.java @@ -0,0 +1,42 @@ +package io.gitlab.jfronny.libjf.mainhttp.impl; + +import io.gitlab.jfronny.libjf.mainhttp.api.v0.MainHttpHandler; +import io.gitlab.jfronny.libjf.mainhttp.impl.util.ClaimPool; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.fabricmc.loader.api.FabricLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class MainHttp { + public static final Event ON_ACTIVATE = EventFactory.createArrayBacked(Runnable.class, listeners -> () -> { + for (Runnable listener : listeners) listener.run(); + }); + public static final ClaimPool GAME_PORT = new ClaimPool<>(); + public static final String MOD_ID = "libjf-mainhttp"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + private static final List activeHandlers = FabricLoader.getInstance() + .getEntrypoints(MOD_ID + ":v0", MainHttpHandler.class) + .stream() + .filter(MainHttpHandler::isActive) + .toList(); + private static final byte[] NOT_FOUND = """ + HTTP/1.1 404 Not Found + Connection: keep-alive + Content-Length: 0 + """.getBytes(); + + public static boolean isEnabled() { + return !activeHandlers.isEmpty(); + } + + public static byte[] handle(byte[] request) { + for (MainHttpHandler handler : activeHandlers) { + byte[] option = handler.handle(request); + if (option != null) return option; + } + return NOT_FOUND; + } +} diff --git a/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/mixin/JfMainHTTPMixinPlugin.java b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/mixin/JfMainHTTPMixinPlugin.java new file mode 100644 index 0000000..deb7953 --- /dev/null +++ b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/mixin/JfMainHTTPMixinPlugin.java @@ -0,0 +1,47 @@ +package io.gitlab.jfronny.libjf.mainhttp.impl.mixin; + +import io.gitlab.jfronny.libjf.mainhttp.impl.MainHttp; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class JfMainHTTPMixinPlugin implements IMixinConfigPlugin { + private static final String MIXIN_PACKAGE = "io.gitlab.jfronny.libjf.mainhttp.impl.mixin."; + + @Override + public void onLoad(String mixinPackage) { + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return switch (mixinClassName) { + case MIXIN_PACKAGE + "ServerNetworkIoMixin", MIXIN_PACKAGE + "ServerNetworkIo$1Mixin" -> MainHttp.isEnabled(); + default -> throw new IllegalArgumentException("Unexpected mixin: " + mixinClassName); + }; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + } +} diff --git a/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/mixin/ServerNetworkIo$1Mixin.java b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/mixin/ServerNetworkIo$1Mixin.java new file mode 100644 index 0000000..38c164c --- /dev/null +++ b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/mixin/ServerNetworkIo$1Mixin.java @@ -0,0 +1,16 @@ +package io.gitlab.jfronny.libjf.mainhttp.impl.mixin; + +import io.gitlab.jfronny.libjf.mainhttp.impl.HttpDecoder; +import io.netty.channel.Channel; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(targets = "net.minecraft.server.ServerNetworkIo$1") +public class ServerNetworkIo$1Mixin { + @Inject(method = "initChannel(Lio/netty/channel/Channel;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;addHandlers(Lio/netty/channel/ChannelPipeline;Lnet/minecraft/network/NetworkSide;Lnet/minecraft/network/handler/PacketSizeLogger;)V")) + private void inject(Channel channel, CallbackInfo ci) { + channel.pipeline().addAfter("legacy_query", "libjf_http", new HttpDecoder()); + } +} diff --git a/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/mixin/ServerNetworkIoMixin.java b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/mixin/ServerNetworkIoMixin.java new file mode 100644 index 0000000..308fd31 --- /dev/null +++ b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/mixin/ServerNetworkIoMixin.java @@ -0,0 +1,31 @@ +package io.gitlab.jfronny.libjf.mainhttp.impl.mixin; + +import io.gitlab.jfronny.libjf.mainhttp.impl.MainHttp; +import io.gitlab.jfronny.libjf.mainhttp.impl.util.ClaimPool; +import net.minecraft.server.ServerNetworkIo; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.net.InetAddress; +import java.util.HashSet; +import java.util.Set; + +@Mixin(ServerNetworkIo.class) +public class ServerNetworkIoMixin { + @Unique + private final Set.Claim> libjf$portClaim = new HashSet<>(); + + @Inject(method = "bind(Ljava/net/InetAddress;I)V", at = @At("HEAD")) + void onBind(InetAddress address, int port, CallbackInfo ci) { + libjf$portClaim.add(MainHttp.GAME_PORT.claim(port)); + MainHttp.ON_ACTIVATE.invoker().run(); + } + + @Inject(method = "stop()V", at = @At("HEAD")) + void onStop(CallbackInfo ci) { + for (ClaimPool.Claim claim : libjf$portClaim) claim.release(); + } +} diff --git a/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/util/ClaimPool.java b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/util/ClaimPool.java new file mode 100644 index 0000000..935ed15 --- /dev/null +++ b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/util/ClaimPool.java @@ -0,0 +1,37 @@ +package io.gitlab.jfronny.libjf.mainhttp.impl.util; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class ClaimPool { + private final List content = new LinkedList<>(); + + public Claim claim(T value) { + return new Claim(value); + } + + public T getTopmost() { + return content.isEmpty() ? null : content.get(content.size() - 1).value; + } + + public boolean isEmpty() { + return content.isEmpty(); + } + + public class Claim { + private final T value; + private final AtomicBoolean active = new AtomicBoolean(true); + + private Claim(T value) { + this.value = value; + content.add(this); + } + + public void release() { + if (!active.getAndSet(false)) + throw new UnsupportedOperationException("Cannot release claim that is already released"); + content.remove(this); + } + } +} diff --git a/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/util/Trie.java b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/util/Trie.java new file mode 100644 index 0000000..553c5c8 --- /dev/null +++ b/libjf-mainhttp-v0/src/main/java/io/gitlab/jfronny/libjf/mainhttp/impl/util/Trie.java @@ -0,0 +1,38 @@ +package io.gitlab.jfronny.libjf.mainhttp.impl.util; + +import it.unimi.dsi.fastutil.chars.Char2ObjectArrayMap; +import it.unimi.dsi.fastutil.chars.Char2ObjectMap; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class Trie { + public final Char2ObjectMap> next; + public T content; + + public Trie() { + this.next = new Char2ObjectArrayMap<>(); + } + + public void add(Map next) { + next.forEach(this::add); + } + + public void add(String key, T value) { + if (key.isEmpty()) this.content = value; + else this.next.computeIfAbsent(key.charAt(0), k -> new Trie<>()) + .add(key.substring(1), value); + } + + public static Trie of(Map source) { + Trie root = new Trie<>(); + root.add(source); + return root; + } + + public static Trie of(List source) { + return of(source.stream().collect(Collectors.toMap(Function.identity(), Function.identity()))); + } +} diff --git a/libjf-mainhttp-v0/src/main/resources/fabric.mod.json b/libjf-mainhttp-v0/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..f76bbb8 --- /dev/null +++ b/libjf-mainhttp-v0/src/main/resources/fabric.mod.json @@ -0,0 +1,28 @@ +{ + "schemaVersion": 1, + "id": "libjf-mainhttp-v0", + "name": "LibJF MainHTTP", + "version": "${version}", + "authors": [ + "JFronny" + ], + "contact": { + "email": "projects.contact@frohnmeyer-wds.de", + "homepage": "https://jfronny.gitlab.io", + "issues": "https://git.frohnmeyer-wds.de/JfMods/LibJF/issues", + "sources": "https://git.frohnmeyer-wds.de/JfMods/LibJF" + }, + "license": "MIT", + "environment": "*", + "mixins": ["libjf-mainhttp-v0.mixins.json"], + "depends": { + "fabricloader": ">=0.12.0", + "minecraft": "*" + }, + "custom": { + "modmenu": { + "parent": "libjf", + "badges": ["library"] + } + } +} diff --git a/libjf-mainhttp-v0/src/main/resources/libjf-mainhttp-v0.mixins.json b/libjf-mainhttp-v0/src/main/resources/libjf-mainhttp-v0.mixins.json new file mode 100644 index 0000000..ec0a860 --- /dev/null +++ b/libjf-mainhttp-v0/src/main/resources/libjf-mainhttp-v0.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.gitlab.jfronny.libjf.mainhttp.impl.mixin", + "compatibilityLevel": "JAVA_16", + "plugin": "io.gitlab.jfronny.libjf.mainhttp.impl.mixin.JfMainHTTPMixinPlugin", + "server": [ + "ServerNetworkIo$1Mixin", + "ServerNetworkIoMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libjf-translate-v1/build.gradle.kts b/libjf-translate-v1/build.gradle.kts index 2bbd137..3e400d0 100644 --- a/libjf-translate-v1/build.gradle.kts +++ b/libjf-translate-v1/build.gradle.kts @@ -10,5 +10,5 @@ base { dependencies { api(devProject(":libjf-base")) - api(devProject(":libjf-config-core-v1")) + api(devProject(":libjf-config-core-v2")) } diff --git a/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/TranslateConfig.java b/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/TranslateConfig.java index 9a93c47..329f80a 100644 --- a/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/TranslateConfig.java +++ b/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/TranslateConfig.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.libjf.translate.impl; -import io.gitlab.jfronny.libjf.config.api.v1.JfCustomConfig; -import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL; +import io.gitlab.jfronny.libjf.config.api.v2.JfCustomConfig; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.DSL; import io.gitlab.jfronny.libjf.translate.api.TranslateService; import io.gitlab.jfronny.libjf.translate.impl.google.GoogleTranslateService; import io.gitlab.jfronny.libjf.translate.impl.libretranslate.LibreTranslateService; diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/AdvancedSubServer.java b/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/AdvancedSubServer.java deleted file mode 100644 index b570904..0000000 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/AdvancedSubServer.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.gitlab.jfronny.libjf.web.api; - -public interface AdvancedSubServer extends SubServer { - void onStop(); - void onStart(); -} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/ContentProvider.java b/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/ContentProvider.java deleted file mode 100644 index 1687919..0000000 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/ContentProvider.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.gitlab.jfronny.libjf.web.api; - -import io.gitlab.jfronny.libjf.web.impl.util.bluemapcore.HttpRequest; -import io.gitlab.jfronny.libjf.web.impl.util.bluemapcore.HttpResponse; - -import java.io.IOException; - -public interface ContentProvider { - HttpResponse handle(HttpRequest request) throws IOException; -} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/SubServer.java b/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/SubServer.java deleted file mode 100644 index 15c6d76..0000000 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/SubServer.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.gitlab.jfronny.libjf.web.api; - -import io.gitlab.jfronny.libjf.web.impl.util.bluemapcore.HttpRequest; -import io.gitlab.jfronny.libjf.web.impl.util.bluemapcore.HttpResponse; - -import java.io.IOException; - -public interface SubServer { - HttpResponse handle(HttpRequest request, String[] segments) throws IOException; -} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/WebInit.java b/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/WebInit.java deleted file mode 100644 index 4853388..0000000 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/WebInit.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.gitlab.jfronny.libjf.web.api; - -public interface WebInit { - void register(WebServer api); -} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/WebServer.java b/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/WebServer.java deleted file mode 100644 index 3654962..0000000 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/api/WebServer.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.gitlab.jfronny.libjf.web.api; - -import io.gitlab.jfronny.libjf.web.impl.JfWeb; - -import java.io.IOException; -import java.nio.file.Path; - -public interface WebServer { - String register(String webPath, ContentProvider provider); - String registerFile(String webPath, Path file, Boolean readOnSend) throws IOException; - String registerFile(String webPath, byte[] data, String contentType); - String registerDir(String webPath, Path dir, Boolean readOnSend) throws IOException; - String registerSubServer(String webPath, SubServer subServer); - String registerSubServer(String webPath, AdvancedSubServer subServer); - String getServerRoot(); - void stop(); - void restart(); - boolean isActive(); - - static WebServer getInstance() { - return JfWeb.SERVER; - } -} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWebServer.java b/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWebServer.java deleted file mode 100644 index 3049646..0000000 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWebServer.java +++ /dev/null @@ -1,206 +0,0 @@ -package io.gitlab.jfronny.libjf.web.impl; - -import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.web.api.*; -import io.gitlab.jfronny.libjf.web.impl.util.WebPaths; -import io.gitlab.jfronny.libjf.web.impl.util.bluemapcore.*; -import net.fabricmc.loader.api.FabricLoader; - -import javax.management.openmbean.KeyAlreadyExistsException; -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; -import java.util.stream.Stream; - -public class JfWebServer implements WebServer { - private HttpServer server = null; - private final RequestHandler handler = new RequestHandler(); - private final int port; - private final int maxConnections; - private final DefaultFileHost dfh = new DefaultFileHost(); - public JfWebServer(int port, int maxConnections) { - this.port = port; - this.maxConnections = maxConnections; - } - - @Override - public String register(String webPath, ContentProvider provider) { - webPath = WebPaths.simplify(webPath); - if (handler.contentProviders.containsKey(webPath)) - throw new KeyAlreadyExistsException("A ContentProvider already exists at that address (" + handler.contentProviders.get(webPath).getClass() + ")"); - handler.contentProviders.put(webPath, provider); - return WebPaths.concat(getServerRoot(), webPath); - } - - @Override - public String registerFile(String webPath, Path file, Boolean readOnSend) throws IOException { - if (readOnSend) { - if (!Files.exists(file)) - throw new FileNotFoundException(); - register(webPath, s -> { - HttpResponse resp = new HttpResponse(HttpStatusCode.OK); - resp.addHeader("Content-Type", Files.probeContentType(file)); - resp.addHeader("Content-Length", String.valueOf(Files.size(file))); - FileInputStream fs = new FileInputStream(file.toFile()); - resp.setData(fs); - return resp; - }); - return WebPaths.concat(getServerRoot(), webPath); - } - else { - return registerFile(webPath, Files.readAllBytes(file), Files.probeContentType(file)); - } - } - - @Override - public String registerFile(String webPath, byte[] data, String contentType) { - return register(webPath, s -> { - HttpResponse resp = new HttpResponse(HttpStatusCode.OK); - resp.addHeader("Content-Type", contentType); - resp.addHeader("Content-Length", String.valueOf(data.length)); - ByteArrayInputStream fs = new ByteArrayInputStream(data); - resp.setData(fs); - return resp; - }); - } - - @Override - public String registerDir(String webPath, Path dir, Boolean readOnSend) throws IOException { - try (Stream contentPath = Files.walk(dir)) { - if (readOnSend) { - return registerSubServer(webPath, (s, t) -> { - final boolean[] c = {false}; - final Path[] p_f = new Path[1]; - contentPath.filter(Files::isRegularFile) - .filter(Files::isReadable) - .forEach(q -> { - if (c[0]) - return; - Path p = dir.toAbsolutePath().relativize(q.toAbsolutePath()); - String wp = webPath; - for (Path path : p) { - wp = WebPaths.concat(wp, path.toString()); - } - if (Objects.equals(WebPaths.simplify(wp), WebPaths.simplify(WebPaths.concat(t)))) { - p_f[0] = q; - c[0] = true; - } - }); - HttpResponse resp; - if (c[0]) { - resp = new HttpResponse(HttpStatusCode.OK); - resp.addHeader("Content-Type", Files.probeContentType(p_f[0])); - resp.addHeader("Content-Length", String.valueOf(Files.size(p_f[0]))); - FileInputStream fs = new FileInputStream(p_f[0].toFile()); - resp.setData(fs); - } else { - resp = new HttpResponse(HttpStatusCode.NOT_FOUND); - } - return resp; - }); - } else { - contentPath.filter(Files::isRegularFile) - .filter(Files::isReadable) - .forEach(s -> { - Path p = dir.toAbsolutePath().relativize(s.toAbsolutePath()); - String wp = webPath; - for (Path path : p) wp = WebPaths.concat(wp, path.toString()); - try { - registerFile(wp, s, false); - } catch (IOException e) { - LibJf.LOGGER.error("Could not register static file", e); - } - }); - } - return WebPaths.concat(getServerRoot(), webPath); - } - } - - @Override - public String registerSubServer(String webPath, SubServer subServer) { - return registerSubServer(webPath, new AdvancedSubServer() { - @Override - public void onStop() { - - } - - @Override - public void onStart() { - - } - - @Override - public HttpResponse handle(HttpRequest request, String[] segments) throws IOException { - return subServer.handle(request, segments); - } - }); - } - - @Override - public String registerSubServer(String webPath, AdvancedSubServer subServer) { - webPath = WebPaths.simplify(webPath); - if (handler.subServers.containsKey(webPath)) - throw new KeyAlreadyExistsException("A Subserver already exists at that address (" + handler.subServers.get(webPath).getClass() + ")"); - handler.subServers.put(webPath, subServer); - return WebPaths.concat(getServerRoot(), webPath); - } - - @Override - public String getServerRoot() { - String ip = JfWebConfig.serverIp; - if (!ip.startsWith("http")) - ip = "http://" + ip; - if (JfWebConfig.portOverride != -1) { - return WebPaths.simplify(ip) + ":" + JfWebConfig.portOverride; - } - return WebPaths.simplify(ip) + ":" + JfWebConfig.port; - } - - @Override - public synchronized void stop() { - for (AdvancedSubServer subServer : handler.subServers.values()) subServer.onStop(); - if (server != null) { - try { - server.close(); - server.join(); - } - catch (InterruptedException e) { - //It is most likely already dead - } - } - } - - @Override - public synchronized void restart() { - JfWebConfig.ensureValidPort(); - int tmpPort = port; - if (server != null) { - tmpPort = server.getPort(); - stop(); - } - handler.clear(); - server = new HttpServer(null, tmpPort, maxConnections, handler, () -> { - if (JfWebConfig.enableFileHost) dfh.register(this); - FabricLoader.getInstance().getEntrypointContainers(LibJf.MOD_ID + ":web", WebInit.class).forEach(entrypoint -> { - WebInit init = entrypoint.getEntrypoint(); - init.register(this); - }); - }); - server.start(); - try { - server.waitUntilReady(); - } catch (InterruptedException e) { - stop(); - LibJf.LOGGER.error("Server could not be readied", e); - } - for (AdvancedSubServer subServer : handler.subServers.values()) { - subServer.onStart(); - } - } - - @Override - public boolean isActive() { - return server != null && server.isAlive(); - } -} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/RequestHandler.java b/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/RequestHandler.java deleted file mode 100644 index 3c4953e..0000000 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/RequestHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.gitlab.jfronny.libjf.web.impl; - -import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.web.api.AdvancedSubServer; -import io.gitlab.jfronny.libjf.web.api.ContentProvider; -import io.gitlab.jfronny.libjf.web.impl.util.WebPaths; -import io.gitlab.jfronny.libjf.web.impl.util.bluemapcore.*; - -import java.util.*; - -public class RequestHandler implements HttpRequestHandler { - public Map subServers = new HashMap<>(); - public Map contentProviders = new HashMap<>(); - - @Override - public HttpResponse handle(HttpRequest request) { - HttpResponse resp = null; - try { - String webPath = WebPaths.simplify(request.getPath()); - if (webPath.length() == 0) - webPath = "index.html"; - if (contentProviders.containsKey(webPath)) { - resp = contentProviders.get(webPath).handle(request); - } - else { - String[] segments = webPath.split("/"); - for (int i = segments.length - 1; i >= 0; i--) { - String wp = WebPaths.concat(Arrays.copyOfRange(segments, 0, i)); - if (subServers.containsKey(wp)) { - resp = subServers.get(wp).handle(request, Arrays.copyOfRange(segments, i, segments.length)); - break; - } - } - if (resp == null) { - resp = new HttpResponse(HttpStatusCode.NOT_FOUND); - } - } - } catch (Throwable e) { - LibJf.LOGGER.error("Caught error while sending", e); - resp = new HttpResponse(HttpStatusCode.INTERNAL_SERVER_ERROR); - } - if (resp.getHeader("Cache-Control").size() == 0) - resp.addHeader("Cache-Control", "no-cache"); - if (resp.getHeader("Server").size() == 0) - resp.addHeader("Server", "LibWeb using BlueMapCore"); - return resp; - } - - public void clear() { - subServers.clear(); - contentProviders.clear(); - } -} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpRequest.java b/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpRequest.java deleted file mode 100644 index 6e3a09d..0000000 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpRequest.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.gitlab.jfronny.libjf.web.impl.util.bluemapcore; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class HttpRequest { - - private static final Pattern REQUEST_PATTERN = Pattern.compile("^(\\w+) (\\S+) (.+)$"); - - private final String method; - private final String adress; - private final String version; - private final Map> header; - private final Map> headerLC; - private byte[] data; - - private String path = null; - private Map getParams = null; - private String getParamString = null; - - public HttpRequest(String method, String adress, String version, Map> header) { - this.method = method; - this.adress = adress; - this.version = version; - this.header = header; - this.headerLC = new HashMap<>(); - - for (Entry> e : header.entrySet()){ - Set values = new HashSet<>(); - for (String v : e.getValue()){ - values.add(v.toLowerCase()); - } - - headerLC.put(e.getKey().toLowerCase(), values); - } - - this.data = new byte[0]; - } - - public String getMethod() { - return method; - } - - public String getAdress(){ - return adress; - } - - public String getVersion() { - return version; - } - - public Map> getHeader() { - return header; - } - - public Map> getLowercaseHeader() { - return headerLC; - } - - public Set getHeader(String key){ - Set headerValues = header.get(key); - if (headerValues == null) return Collections.emptySet(); - return headerValues; - } - - public Set getLowercaseHeader(String key){ - Set headerValues = headerLC.get(key.toLowerCase()); - if (headerValues == null) return Collections.emptySet(); - return headerValues; - } - - public String getPath() { - if (path == null) parseAdress(); - return path; - } - - public Map getGETParams() { - if (getParams == null) parseAdress(); - return Collections.unmodifiableMap(getParams); - } - - public String getGETParamString() { - if (getParamString == null) parseAdress(); - return getParamString; - } - - private void parseAdress() { - String adress = this.adress; - if (adress.isEmpty()) adress = "/"; - String[] adressParts = adress.split("\\?", 2); - String path = adressParts[0]; - this.getParamString = adressParts.length > 1 ? adressParts[1] : ""; - - Map getParams = new HashMap<>(); - for (String getParam : this.getParamString.split("&")){ - if (getParam.isEmpty()) continue; - String[] kv = getParam.split("=", 2); - String key = kv[0]; - String value = kv.length > 1 ? kv[1] : ""; - getParams.put(key, value); - } - - this.path = path; - this.getParams = getParams; - } - - public InputStream getData(){ - return new ByteArrayInputStream(data); - } - - public static HttpRequest read(InputStream in) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); - List header = new ArrayList<>(20); - while(header.size() < 1000){ - String headerLine = readLine(reader); - if (headerLine.isEmpty()) break; - header.add(headerLine); - } - - if (header.isEmpty()) throw new HttpConnection.InvalidRequestException(); - - Matcher m = REQUEST_PATTERN.matcher(header.remove(0)); - if (!m.find()) throw new HttpConnection.InvalidRequestException(); - - String method = m.group(1); - if (method == null) throw new HttpConnection.InvalidRequestException(); - - String adress = m.group(2); - if (adress == null) throw new HttpConnection.InvalidRequestException(); - - String version = m.group(3); - if (version == null) throw new HttpConnection.InvalidRequestException(); - - Map> headerMap = new HashMap>(); - for (String line : header){ - if (line.trim().isEmpty()) continue; - - String[] kv = line.split(":", 2); - if (kv.length < 2) continue; - - Set values = new HashSet<>(); - if (kv[0].trim().equalsIgnoreCase("If-Modified-Since")){ - values.add(kv[1].trim()); - } else { - for(String v : kv[1].split(",")){ - values.add(v.trim()); - } - } - - headerMap.put(kv[0].trim(), values); - } - - HttpRequest request = new HttpRequest(method, adress, version, headerMap); - - if (request.getLowercaseHeader("Transfer-Encoding").contains("chunked")){ - try { - ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); - while (dataStream.size() < 1000000){ - String hexSize = reader.readLine(); - int chunkSize = Integer.parseInt(hexSize, 16); - if (chunkSize <= 0) break; - byte[] data = new byte[chunkSize]; - in.read(data); - dataStream.write(data); - } - - if (dataStream.size() >= 1000000) { - throw new HttpConnection.InvalidRequestException(); - } - - request.data = dataStream.toByteArray(); - - return request; - } catch (NumberFormatException ex){ - return request; - } - } else { - Set clSet = request.getLowercaseHeader("Content-Length"); - if (clSet.isEmpty()){ - return request; - } else { - try { - int cl = Integer.parseInt(clSet.iterator().next()); - byte[] data = new byte[cl]; - in.read(data); - request.data = data; - return request; - } catch (NumberFormatException ex){ - return request; - } - } - } - } - - private static String readLine(BufferedReader in) throws IOException { - String line = in.readLine(); - if (line == null){ - throw new HttpConnection.ConnectionClosedException(); - } - return line; - } - -} diff --git a/libjf-web-v0/src/main/resources/assets/libjf-web-v0/lang/en_us.json b/libjf-web-v0/src/main/resources/assets/libjf-web-v0/lang/en_us.json deleted file mode 100644 index 38a4c7b..0000000 --- a/libjf-web-v0/src/main/resources/assets/libjf-web-v0/lang/en_us.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "libjf-web-v0.jfconfig.title": "LibJF Web v0", - "libjf-web-v0.jfconfig.serverIp": "Server IP", - "libjf-web-v0.jfconfig.serverIp.tooltip": "The public IP/host name to send to clients", - "libjf-web-v0.jfconfig.port": "Port", - "libjf-web-v0.jfconfig.port.tooltip": "The port to host content on", - "libjf-web-v0.jfconfig.portOverride": "Port Override", - "libjf-web-v0.jfconfig.portOverride.tooltip": "The port to send to clients (for reverse proxies, -1 to disable)", - "libjf-web-v0.jfconfig.maxConnections": "Max. Connections", - "libjf-web-v0.jfconfig.maxConnections.tooltip": "The maximum number of concurrent connections to this server", - "libjf-web-v0.jfconfig.enableFileHost": "Enable File Host", - "libjf-web-v0.jfconfig.enableFileHost.tooltip": "Whether files from config/wwwroot should be hosted as static resources" -} \ No newline at end of file diff --git a/libjf-web-v0/src/testmod/java/io/gitlab/jfronny/libjf/web/test/WebTest.java b/libjf-web-v0/src/testmod/java/io/gitlab/jfronny/libjf/web/test/WebTest.java deleted file mode 100644 index a92f49f..0000000 --- a/libjf-web-v0/src/testmod/java/io/gitlab/jfronny/libjf/web/test/WebTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.gitlab.jfronny.libjf.web.test; - -import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.web.api.WebInit; -import io.gitlab.jfronny.libjf.web.api.WebServer; -import io.gitlab.jfronny.libjf.web.impl.util.bluemapcore.HttpResponse; -import io.gitlab.jfronny.libjf.web.impl.util.bluemapcore.HttpStatusCode; -import net.fabricmc.loader.api.FabricLoader; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -public class WebTest implements WebInit { - @Override - public void register(WebServer api) { - Path sourcePath = FabricLoader.getInstance().getModContainer("libjf-web-v0-testmod").get().findPath("test.html").get(); - LibJf.LOGGER.info(api.register("/test/0.html", request -> new HttpResponse(HttpStatusCode.OK).setData(Files.readString(sourcePath)))); - try { - LibJf.LOGGER.info(api.registerFile("/test/1.html", sourcePath, false)); - LibJf.LOGGER.info(api.registerFile("/test/2.html", sourcePath, true)); - } catch (IOException e) { - throw new RuntimeException("Could not register hosted files", e); - } - } -} diff --git a/libjf-web-v0/build.gradle.kts b/libjf-web-v1/build.gradle.kts similarity index 77% rename from libjf-web-v0/build.gradle.kts rename to libjf-web-v1/build.gradle.kts index ed9bac7..9b27cd7 100644 --- a/libjf-web-v0/build.gradle.kts +++ b/libjf-web-v1/build.gradle.kts @@ -5,13 +5,14 @@ plugins { } base { - archivesName.set("libjf-web-v0") + archivesName.set("libjf-web-v1") } dependencies { val fabricVersion: String by rootProject.extra api(devProject(":libjf-base")) - api(devProject(":libjf-config-core-v1")) + api(devProject(":libjf-config-core-v2")) + api(devProject(":libjf-mainhttp-v0")) include(modImplementation(fabricApi.module("fabric-command-api-v2", fabricVersion))!!) annotationProcessor(project(":libjf-config-compiler-plugin-v2")) diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpRequest.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpRequest.java new file mode 100644 index 0000000..39f260c --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpRequest.java @@ -0,0 +1,30 @@ +package io.gitlab.jfronny.libjf.web.api.v1; + +import io.gitlab.jfronny.libjf.web.impl.util.HttpRequestImpl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Set; + +public interface HttpRequest { + static HttpRequest read(InputStream in) throws IOException { + return HttpRequestImpl.read(in); + } + + default HttpResponse createResponse(HttpStatusCode statusCode) { + return HttpResponse.create(statusCode); + } + + String getMethod(); + String getAddress(); + String getVersion(); + Map> getHeader(); + Map> getLowercaseHeader(); + Set getHeader(String key); + Set getLowercaseHeader(String key); + String getPath(); + Map getQuery(); + String getQueryString(); + InputStream getData(); +} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpRequestHandler.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpRequestHandler.java similarity index 78% rename from libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpRequestHandler.java rename to libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpRequestHandler.java index 7f5d490..2b8647e 100644 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpRequestHandler.java +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpRequestHandler.java @@ -22,9 +22,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.gitlab.jfronny.libjf.web.impl.util.bluemapcore; +package io.gitlab.jfronny.libjf.web.api.v1; + +import io.gitlab.jfronny.libjf.web.impl.host.VirtualHostBranch; + +import java.io.IOException; @FunctionalInterface public interface HttpRequestHandler { - HttpResponse handle(HttpRequest request); + HttpResponse handle(HttpRequest request) throws IOException; + + default VirtualHostNode asHostNode() { + VirtualHostBranch impl = new VirtualHostBranch(); + impl.setContent(this); + return impl; + } } diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpResponse.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpResponse.java new file mode 100644 index 0000000..7020775 --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpResponse.java @@ -0,0 +1,24 @@ +package io.gitlab.jfronny.libjf.web.api.v1; + +import io.gitlab.jfronny.libjf.web.impl.util.HttpResponseImpl; + +import java.io.*; +import java.util.Map; +import java.util.Set; + +public interface HttpResponse extends Closeable { + static HttpResponse create(HttpStatusCode statusCode) { + return new HttpResponseImpl(statusCode); + } + + HttpResponse addHeader(String key, String value); + HttpResponse removeHeader(String key, String value); + HttpResponse setData(InputStream data); + HttpResponse setData(String data); + void write(OutputStream out) throws IOException; + + HttpStatusCode getStatusCode(); + String getVersion(); + Map> getHeader(); + Set getHeader(String key); +} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpStatusCode.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpStatusCode.java similarity index 97% rename from libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpStatusCode.java rename to libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpStatusCode.java index d25f391..d72b634 100644 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpStatusCode.java +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/HttpStatusCode.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.gitlab.jfronny.libjf.web.impl.util.bluemapcore; +package io.gitlab.jfronny.libjf.web.api.v1; public enum HttpStatusCode { CONTINUE (100, "Continue"), diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/PathSegment.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/PathSegment.java new file mode 100644 index 0000000..0129d97 --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/PathSegment.java @@ -0,0 +1,50 @@ +package io.gitlab.jfronny.libjf.web.api.v1; + +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public record PathSegment(String segment, @Nullable PathSegment next) { + public PathSegment(String segment, @Nullable PathSegment next) { + if (segment.isEmpty() || segment.equals(".") || segment.contains("/")) { + PathSegment from = Objects.requireNonNull(of(segment, next)); + this.segment = from.segment; + this.next = from.next; + } else { + this.segment = segment; + this.next = next; + } + } + + public PathSegment(String path) { + this(path, null); + } + + @Override + public String toString() { + return next == null ? segment : segment + "/" + next; + } + + public PathSegment concat(@Nullable PathSegment seg) { + return seg == null ? this : new PathSegment(segment, next == null ? seg : next.concat(seg)); + } + + public static @Nullable PathSegment concat(@Nullable PathSegment seg1, @Nullable PathSegment seg2) { + return seg1 == null ? seg2 : seg1.concat(seg2); + } + + public static @Nullable PathSegment of(String path) { + return of(path, null); + } + + private static @Nullable PathSegment of(String path, PathSegment next) { + Deque segmentStack = new LinkedList<>(); + for (String s : path.split("/")) { + if (s.isEmpty() || s.equals(".")) continue; + if (s.equals("..")) segmentStack.pop(); + segmentStack.push(s); + } + for (String s : segmentStack) next = new PathSegment(s, next); + return next; + } +} diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/VirtualHostNode.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/VirtualHostNode.java new file mode 100644 index 0000000..a26c456 --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/VirtualHostNode.java @@ -0,0 +1,10 @@ +package io.gitlab.jfronny.libjf.web.api.v1; + +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; + +@FunctionalInterface +public interface VirtualHostNode { + HttpResponse handle(HttpRequest request, @Nullable PathSegment path) throws IOException; +} diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/WebEntrypoint.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/WebEntrypoint.java new file mode 100644 index 0000000..3196e75 --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/WebEntrypoint.java @@ -0,0 +1,5 @@ +package io.gitlab.jfronny.libjf.web.api.v1; + +public interface WebEntrypoint { + void register(WebServer api); +} diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/WebServer.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/WebServer.java new file mode 100644 index 0000000..ce3e085 --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/api/v1/WebServer.java @@ -0,0 +1,26 @@ +package io.gitlab.jfronny.libjf.web.api.v1; + +import io.gitlab.jfronny.libjf.web.impl.JfWeb; + +import java.io.IOException; +import java.nio.file.Path; + +public interface WebServer { + String register(PathSegment path, VirtualHostNode provider); + default String register(PathSegment path, HttpRequestHandler provider) { + return register(path, provider.asHostNode()); + } + String registerFile(PathSegment path, Path file, boolean readOnSend) throws IOException; + String registerFile(PathSegment path, byte[] data, String contentType); + String registerDir(PathSegment path, Path dir, boolean readOnSend) throws IOException; + String getServerRoot(); + void onStart(Runnable listener); + void onStop(Runnable listener); + void stop(); + void queueRestart(Runnable callback); + boolean isActive(); + + static WebServer getInstance() { + return JfWeb.SERVER; + } +} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWeb.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWeb.java similarity index 64% rename from libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWeb.java rename to libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWeb.java index 4ede783..d883aea 100644 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWeb.java +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWeb.java @@ -1,31 +1,49 @@ package io.gitlab.jfronny.libjf.web.impl; import com.mojang.brigadier.Command; +import io.gitlab.jfronny.commons.ref.R; import io.gitlab.jfronny.libjf.Flags; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.coprocess.CoProcess; -import io.gitlab.jfronny.libjf.web.api.WebServer; +import io.gitlab.jfronny.libjf.web.api.v1.WebServer; +import io.gitlab.jfronny.libjf.web.impl.host.RequestHandler; +import io.gitlab.jfronny.libjf.web.impl.variant.hosted.HostedWebServer; +import io.gitlab.jfronny.libjf.web.impl.variant.shared.SharedWebServer; +import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.text.Text; +import org.jetbrains.annotations.ApiStatus; import static net.minecraft.server.command.CommandManager.literal; public class JfWeb implements CoProcess, ModInitializer { + private static final RequestHandler handler; public static final WebServer SERVER; + static { JfWebConfig.ensureValidPort(); - SERVER = new JfWebServer(JfWebConfig.port, JfWebConfig.maxConnections); + handler = new RequestHandler(); + if (JfWebConfig.port != -1) SERVER = new HostedWebServer(handler, JfWebConfig.port, JfWebConfig.maxConnections); + else if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) + SERVER = new HostedWebServer(handler, 0, JfWebConfig.maxConnections); + else SERVER = new SharedWebServer(handler); + } + + @ApiStatus.Internal + public static RequestHandler getHandler() { + return handler; } @Override public void start() { - if (isEnabled()) SERVER.restart(); + if (isEnabled()) SERVER.queueRestart(R::nop); } @Override public void stop() { - if (isEnabled()) SERVER.stop(); + if (!(SERVER instanceof SharedWebServer)) SERVER.stop(); } @Override @@ -43,7 +61,9 @@ public class JfWeb implements CoProcess, ModInitializer { }).then(literal("restart").executes(context -> { try { context.getSource().sendFeedback(() -> Text.literal("Restarting LibWeb"), true); - SERVER.restart(); + SERVER.queueRestart(() -> { + context.getSource().sendFeedback(() -> Text.literal("LibWeb restarted"), true); + }); } catch (Exception e) { LibJf.LOGGER.error("Failed to run restart command", e); @@ -53,7 +73,6 @@ public class JfWeb implements CoProcess, ModInitializer { })))); }); } - Runtime.getRuntime().addShutdownHook(new Thread(SERVER::stop)); } private boolean isEnabled() { diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWebConfig.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWebConfig.java similarity index 58% rename from libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWebConfig.java rename to libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWebConfig.java index 424dad3..4a258ad 100644 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWebConfig.java +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/JfWebConfig.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.libjf.web.impl; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.config.api.v1.*; +import io.gitlab.jfronny.libjf.config.api.v2.*; import java.io.IOException; import java.net.ServerSocket; @@ -9,19 +9,24 @@ import java.net.ServerSocket; @JfConfig public class JfWebConfig { @Entry public static String serverIp = "http://127.0.0.1"; - @Entry(min = 0, max = 35535) public static int port = 0; + @Entry(min = -1, max = 35535) public static int port = 0; @Entry(min = -1, max = 35535) public static int portOverride = -1; @Entry(min = 8, max = 64) public static int maxConnections = 20; @Entry public static boolean enableFileHost = false; public static void ensureValidPort() { if (port == 0) { - try (ServerSocket socket = new ServerSocket(0)) { - port = socket.getLocalPort(); - } catch (IOException e) { - LibJf.LOGGER.error("Could not bind port to identify available", e); - } - ConfigHolder.getInstance().getRegistered().get("libjf-web-v0").write(); + port = findAvailablePort(); + ConfigHolder.getInstance().getRegistered().get("libjf-web-v1").write(); + } + } + + public static int findAvailablePort() { + try (ServerSocket socket = new ServerSocket(0)) { + return socket.getLocalPort(); + } catch (IOException e) { + LibJf.LOGGER.error("Could not bind port to identify available", e); + return 0; } } diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/DefaultFileHost.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/DefaultFileHost.java similarity index 70% rename from libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/DefaultFileHost.java rename to libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/DefaultFileHost.java index df20a97..738e644 100644 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/DefaultFileHost.java +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/DefaultFileHost.java @@ -1,15 +1,15 @@ -package io.gitlab.jfronny.libjf.web.impl; +package io.gitlab.jfronny.libjf.web.impl.host; import io.gitlab.jfronny.libjf.LibJf; -import io.gitlab.jfronny.libjf.web.api.WebInit; -import io.gitlab.jfronny.libjf.web.api.WebServer; +import io.gitlab.jfronny.libjf.web.api.v1.WebEntrypoint; +import io.gitlab.jfronny.libjf.web.api.v1.WebServer; import net.fabricmc.loader.api.FabricLoader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -public class DefaultFileHost implements WebInit { +public class DefaultFileHost implements WebEntrypoint { @Override public void register(WebServer api) { Path p = FabricLoader.getInstance().getConfigDir().resolve("wwwroot"); @@ -21,7 +21,7 @@ public class DefaultFileHost implements WebInit { } } try { - LibJf.LOGGER.info(api.registerDir("/", p, false)); + LibJf.LOGGER.info(api.registerDir(null, p, false)); } catch (IOException e) { LibJf.LOGGER.error("Could not register wwwroot", e); } diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/ReadOnSendDirNode.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/ReadOnSendDirNode.java new file mode 100644 index 0000000..0496155 --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/ReadOnSendDirNode.java @@ -0,0 +1,38 @@ +package io.gitlab.jfronny.libjf.web.impl.host; + +import io.gitlab.jfronny.libjf.web.api.v1.*; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +public record ReadOnSendDirNode(Path fsPath) implements VirtualHostNode { + @Override + public HttpResponse handle(HttpRequest request, @Nullable PathSegment path) throws IOException { + return handle(request, path, fsPath); + } + + private static HttpResponse handle(HttpRequest request, @Nullable PathSegment path, Path fsPath) throws IOException { + if (path == null) { + if (Files.isRegularFile(fsPath) && Files.isReadable(fsPath)) { + HttpResponse resp = request.createResponse(HttpStatusCode.OK); + resp.addHeader("Content-Type", Files.probeContentType(fsPath)); + resp.addHeader("Content-Length", String.valueOf(Files.size(fsPath))); + resp.setData(Files.newInputStream(fsPath)); + return resp; + } else return request.createResponse(HttpStatusCode.NOT_FOUND); + } else { + if (!Files.isDirectory(fsPath)) return request.createResponse(HttpStatusCode.NOT_FOUND); + try (Stream s = Files.list(fsPath)) { + for (Path sub : s.toList()) { + if (path.segment().equals(sub.getFileName().toString())) { + return handle(request, path.next(), sub); + } + } + } + return request.createResponse(HttpStatusCode.NOT_FOUND); + } + } +} diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/RequestHandler.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/RequestHandler.java new file mode 100644 index 0000000..1f480ac --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/RequestHandler.java @@ -0,0 +1,29 @@ +package io.gitlab.jfronny.libjf.web.impl.host; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.web.api.v1.*; +import io.gitlab.jfronny.libjf.web.api.v1.HttpRequestHandler; + +public class RequestHandler extends VirtualHostBranch implements HttpRequestHandler { + @Override + public HttpResponse handle(HttpRequest request) { + HttpResponse resp; + try { + PathSegment path = PathSegment.of(request.getPath()); + if (path == null) path = new PathSegment("index.html"); + resp = handle(request, path); + } catch (Throwable e) { + LibJf.LOGGER.error("Caught error while sending", e); + resp = request.createResponse(HttpStatusCode.INTERNAL_SERVER_ERROR); + } + if (resp.getHeader("Cache-Control").isEmpty()) + resp.addHeader("Cache-Control", "no-cache"); + if (resp.getHeader("Server").isEmpty()) + resp.addHeader("Server", "LibWeb using BlueMapCore"); + return resp; + } + + public void clear() { + children.clear(); + } +} diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/VirtualHostBranch.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/VirtualHostBranch.java new file mode 100644 index 0000000..c66333b --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/host/VirtualHostBranch.java @@ -0,0 +1,47 @@ +package io.gitlab.jfronny.libjf.web.impl.host; + +import io.gitlab.jfronny.libjf.web.api.v1.*; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.*; + +public class VirtualHostBranch implements VirtualHostNode { + protected final Map children = new HashMap<>(); + protected HttpRequestHandler content; + + @Override + public HttpResponse handle(HttpRequest request, @Nullable PathSegment path) throws IOException { + if (path == null) { + if (content != null) return content.handle(request); + else return request.createResponse(HttpStatusCode.NOT_FOUND); + } else { + VirtualHostNode child = children.get(path.segment()); + if (child == null) return request.createResponse(HttpStatusCode.NOT_FOUND); + else return child.handle(request, path.next()); + } + } + + public void register(PathSegment path, VirtualHostNode node) { + Objects.requireNonNull(path); + if (path.next() == null) { + if (children.containsKey(path.segment())) { + VirtualHostNode childNode = children.get(path.segment()); + if (node instanceof VirtualHostBranch next + && childNode instanceof VirtualHostBranch source) { + if (next.content != null) source.setContent(next.content); + next.children.forEach((k, v) -> source.register(PathSegment.of(k), v)); + } else throw new UnsupportedOperationException("VirtualHostNode already exists for path and merging is unsupported for " + childNode.getClass() + " and " + node.getClass()); + } else children.put(path.segment(), node); + } else { + VirtualHostNode child = children.computeIfAbsent(path.segment(), s -> new VirtualHostBranch()); + if (child instanceof VirtualHostBranch source) source.register(path.next(), node); + else throw new UnsupportedOperationException("Cannot register VirtualHostNode to non-branch VirtualHostNode " + child.getClass()); + } + } + + public void setContent(HttpRequestHandler content) { + if (this.content != null) throw new UnsupportedOperationException("Content already set for virtual host node"); + this.content = Objects.requireNonNull(content); + } +} diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/HttpRequestImpl.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/HttpRequestImpl.java new file mode 100644 index 0000000..16f8aed --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/HttpRequestImpl.java @@ -0,0 +1,249 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.gitlab.jfronny.libjf.web.impl.util; + +import io.gitlab.jfronny.libjf.web.api.v1.*; +import io.gitlab.jfronny.libjf.web.impl.variant.hosted.HttpConnection; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HttpRequestImpl implements HttpRequest { + private static final Pattern REQUEST_PATTERN = Pattern.compile("^(\\w+) (\\S+) (.+)$"); + + private final String method; + private final String address; + private final String version; + private final Map> header; + private final Map> headerLC; + private byte[] data; + + private String path = null; + private Map queryParameters = null; + private String queryString = null; + + public HttpRequestImpl(String method, String address, String version, Map> header) { + this.method = method; + this.address = address; + this.version = version; + this.header = header; + this.headerLC = new HashMap<>(); + + for (Entry> e : header.entrySet()){ + Set values = new HashSet<>(); + for (String v : e.getValue()){ + values.add(v.toLowerCase()); + } + + headerLC.put(e.getKey().toLowerCase(), values); + } + + this.data = new byte[0]; + } + + @Override + public String getMethod() { + return method; + } + + @Override + public String getAddress(){ + return address; + } + + @Override + public String getVersion() { + return version; + } + + @Override + public Map> getHeader() { + return header; + } + + @Override + public Map> getLowercaseHeader() { + return headerLC; + } + + @Override + public Set getHeader(String key){ + Set headerValues = header.get(key); + if (headerValues == null) return Collections.emptySet(); + return headerValues; + } + + @Override + public Set getLowercaseHeader(String key){ + Set headerValues = headerLC.get(key.toLowerCase()); + if (headerValues == null) return Collections.emptySet(); + return headerValues; + } + + @Override + public String getPath() { + if (path == null) parseAddress(); + return path; + } + + @Override + public Map getQuery() { + if (queryParameters == null) parseAddress(); + return Collections.unmodifiableMap(queryParameters); + } + + @Override + public String getQueryString() { + if (queryString == null) parseAddress(); + return queryString; + } + + private void parseAddress() { + String adress = this.address; + if (adress.isEmpty()) adress = "/"; + String[] addressParts = adress.split("\\?", 2); + String path = addressParts[0]; + this.queryString = addressParts.length > 1 ? addressParts[1] : ""; + + Map queryParams = new HashMap<>(); + for (String queryParam : this.queryString.split("&")){ + if (queryParam.isEmpty()) continue; + String[] kv = queryParam.split("=", 2); + String key = kv[0]; + String value = kv.length > 1 ? kv[1] : ""; + queryParams.put(key, value); + } + + this.path = path; + this.queryParameters = queryParams; + } + + @Override + public InputStream getData(){ + return new ByteArrayInputStream(data); + } + + public static HttpRequestImpl read(InputStream in) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); + HttpRequestImpl request = fromHeaders(extractHeaders(reader)); + readData(in, request, reader); + return request; + } + + private static void readData(InputStream in, HttpRequestImpl request, BufferedReader reader) throws IOException { + if (request.getLowercaseHeader("Transfer-Encoding").contains("chunked")) { + try { + ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); + while (dataStream.size() < 1000000) { + String hexSize = reader.readLine(); + int chunkSize = Integer.parseInt(hexSize, 16); + if (chunkSize <= 0) break; + byte[] data = new byte[chunkSize]; + in.read(data); + dataStream.write(data); + } + + if (dataStream.size() >= 1000000) { + throw new HttpConnection.InvalidRequestException(); + } + + request.data = dataStream.toByteArray(); + } catch (NumberFormatException ex) { + } + } else { + Set clSet = request.getLowercaseHeader("Content-Length"); + if (clSet.isEmpty()) return; + try { + int cl = Integer.parseInt(clSet.iterator().next()); + byte[] data = new byte[cl]; + in.read(data); + request.data = data; + } catch (NumberFormatException ex) { + } + } + } + + private static List extractHeaders(BufferedReader reader) throws IOException { + List headers = new ArrayList<>(20); + while (headers.size() < 1000) { + String headerLine = readLine(reader); + if (headerLine.isEmpty()) break; + headers.add(headerLine); + } + return headers; + } + + private static HttpRequestImpl fromHeaders(List headers) throws HttpConnection.InvalidRequestException { + if (headers.isEmpty()) throw new HttpConnection.InvalidRequestException(); + + Matcher m = REQUEST_PATTERN.matcher(headers.remove(0)); + if (!m.find()) throw new HttpConnection.InvalidRequestException(); + + String method = m.group(1); + if (method == null) throw new HttpConnection.InvalidRequestException(); + + String adress = m.group(2); + if (adress == null) throw new HttpConnection.InvalidRequestException(); + + String version = m.group(3); + if (version == null) throw new HttpConnection.InvalidRequestException(); + + return new HttpRequestImpl(method, adress, version, parseExtraHeaders(headers)); + } + + private static Map> parseExtraHeaders(List header) { + Map> headerMap = new HashMap<>(); + for (String line : header) { + if (line.trim().isEmpty()) continue; + + String[] kv = line.split(":", 2); + if (kv.length < 2) continue; + + Set values = new HashSet<>(); + if (kv[0].trim().equalsIgnoreCase("If-Modified-Since")) { + values.add(kv[1].trim()); + } else { + for (String v : kv[1].split(",")) { + values.add(v.trim()); + } + } + + headerMap.put(kv[0].trim(), values); + } + return headerMap; + } + + private static String readLine(BufferedReader in) throws IOException { + String line = in.readLine(); + if (line == null) { + throw new HttpConnection.ConnectionClosedException(); + } + return line; + } +} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpResponse.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/HttpResponseImpl.java similarity index 65% rename from libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpResponse.java rename to libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/HttpResponseImpl.java index 5460420..16512d5 100644 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpResponse.java +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/HttpResponseImpl.java @@ -22,8 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.gitlab.jfronny.libjf.web.impl.util.bluemapcore; +package io.gitlab.jfronny.libjf.web.impl.util; +import io.gitlab.jfronny.libjf.web.api.v1.HttpResponse; +import io.gitlab.jfronny.libjf.web.api.v1.HttpStatusCode; import org.apache.commons.lang3.StringUtils; import java.io.*; @@ -31,39 +33,48 @@ import java.nio.charset.StandardCharsets; import java.util.*; import java.util.Map.Entry; -public class HttpResponse implements Closeable { +public class HttpResponseImpl implements HttpResponse { private final String version; private final HttpStatusCode statusCode; private final Map> header; + private boolean closed = false; private InputStream data; - public HttpResponse(HttpStatusCode statusCode) { + public HttpResponseImpl(HttpStatusCode statusCode) { this.version = "HTTP/1.1"; this.statusCode = statusCode; - this.header = new HashMap<>(); + this.header = new LinkedHashMap<>(); addHeader("Connection", "keep-alive"); } - public HttpResponse addHeader(String key, String value){ - Set valueSet = header.computeIfAbsent(key, k -> new HashSet<>()); + @Override + public HttpResponseImpl addHeader(String key, String value) { + ensureOpen(); + Set valueSet = header.computeIfAbsent(key, k -> new LinkedHashSet<>()); valueSet.add(value); return this; } - public HttpResponse removeHeader(String key, String value){ - Set valueSet = header.computeIfAbsent(key, k -> new HashSet<>()); + @Override + public HttpResponseImpl removeHeader(String key, String value) { + ensureOpen(); + Set valueSet = header.computeIfAbsent(key, k -> new LinkedHashSet<>()); valueSet.remove(value); return this; } - public HttpResponse setData(InputStream dataStream){ + @Override + public HttpResponseImpl setData(InputStream dataStream) { + ensureOpen(); this.data = dataStream; return this; } - public HttpResponse setData(String data){ + @Override + public HttpResponseImpl setData(String data) { + ensureOpen(); setData(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8))); return this; } @@ -73,17 +84,19 @@ public class HttpResponse implements Closeable { *
* This method closes the data-Stream of this response so it can't be used again! */ - public HttpResponse write(OutputStream out) throws IOException { + @Override + public void write(OutputStream out) throws IOException { OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); - if (data != null){ - addHeader("Transfer-Encoding", "chunked"); + Map> finalHeaders = new LinkedHashMap<>(header); + if (data != null) { + finalHeaders.computeIfAbsent("Transfer-Encoding", k -> new LinkedHashSet<>()).add("chunked"); } else { - addHeader("Content-Length", "0"); + finalHeaders.computeIfAbsent("Content-Length", k -> new LinkedHashSet<>()).add("0"); } writeLine(writer, version + " " + statusCode.getCode() + " " + statusCode.getMessage()); - for (Entry> e : header.entrySet()){ + for (Entry> e : finalHeaders.entrySet()) { if (e.getValue().isEmpty()) continue; writeLine(writer, e.getKey() + ": " + StringUtils.join(e.getValue(), ", ")); } @@ -91,17 +104,20 @@ public class HttpResponse implements Closeable { writeLine(writer, ""); writer.flush(); - if(data != null){ + if (data != null) { + boolean markSupported = data.markSupported(); + if (markSupported) data.mark(Integer.MAX_VALUE); chunkedPipe(data, out); out.flush(); - data.close(); + if (markSupported) data.reset(); + else close(); } - return this; } @Override public void close() throws IOException { - data.close(); + if (data != null) data.close(); + this.closed = true; } private void writeLine(OutputStreamWriter writer, String line) throws IOException { @@ -119,18 +135,26 @@ public class HttpResponse implements Closeable { output.write("0\r\n\r\n".getBytes()); } + private void ensureOpen() { + if (closed) throw new UnsupportedOperationException("Response cannot be changed after being closed or written"); + } + + @Override public HttpStatusCode getStatusCode(){ return statusCode; } + @Override public String getVersion(){ return version; } + @Override public Map> getHeader() { return header; } + @Override public Set getHeader(String key){ Set headerValues = header.get(key); if (headerValues == null) return Collections.emptySet(); diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/RunnableEvent.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/RunnableEvent.java new file mode 100644 index 0000000..9deb8af --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/RunnableEvent.java @@ -0,0 +1,12 @@ +package io.gitlab.jfronny.libjf.web.impl.util; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +public class RunnableEvent { + public static Event create() { + return EventFactory.createArrayBacked(Runnable.class, listeners -> () -> { + for (Runnable listener : listeners) listener.run(); + }); + } +} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/WebPaths.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/WebPaths.java similarity index 80% rename from libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/WebPaths.java rename to libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/WebPaths.java index 68051a2..df57a5c 100644 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/WebPaths.java +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/WebPaths.java @@ -5,12 +5,10 @@ public class WebPaths { return simplify(s1) + "/" + simplify(s2); } - public static String concat(String[] elements) { - StringBuilder s = new StringBuilder(); - for (String element : elements) { - s.append("/").append(element); - } - return simplify(s.toString()); + public static String getHttp(String ip) { + if (!ip.startsWith("http")) + ip = "http://" + ip; + return simplify(ip); } public static String simplify(String s) { @@ -28,8 +26,7 @@ public class WebPaths { StringBuilder q = new StringBuilder(); for (String s1 : simplifyPart(s, false).split("/")) { String w = simplifyPart(s1, true); - if (w != null && w.length() != 0) - q.append("/").append(w); + if (w != null && !w.isEmpty()) q.append("/").append(w); } String result = simplifyPart(q.toString(), false); if (http) result = "http://" + result; diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/AbstractWebServer.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/AbstractWebServer.java new file mode 100644 index 0000000..9d3402a --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/AbstractWebServer.java @@ -0,0 +1,123 @@ +package io.gitlab.jfronny.libjf.web.impl.variant; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.web.api.v1.*; +import io.gitlab.jfronny.libjf.web.impl.JfWebConfig; +import io.gitlab.jfronny.libjf.web.impl.host.*; +import io.gitlab.jfronny.libjf.web.impl.util.RunnableEvent; +import io.gitlab.jfronny.libjf.web.impl.util.WebPaths; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.ApiStatus; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +public abstract class AbstractWebServer implements WebServer { + protected final RequestHandler handler; + private final DefaultFileHost dfh = new DefaultFileHost(); + + protected AbstractWebServer(RequestHandler handler) { + this.handler = handler; + } + + @ApiStatus.Internal + public RequestHandler getHandler() { + return handler; + } + + @Override + public String register(PathSegment path, VirtualHostNode provider) { + handler.register(path, provider); + return toUrl(path); + } + + @Override + public String registerFile(PathSegment path, Path file, boolean readOnSend) throws IOException { + if (readOnSend) { + if (!Files.exists(file)) throw new FileNotFoundException(); + return register(path, s -> { + HttpResponse resp = HttpResponse.create(HttpStatusCode.OK); + resp.addHeader("Content-Type", Files.probeContentType(file)); + resp.addHeader("Content-Length", String.valueOf(Files.size(file))); + FileInputStream fs = new FileInputStream(file.toFile()); + resp.setData(fs); + return resp; + }); + } else { + return registerFile(path, Files.readAllBytes(file), Files.probeContentType(file)); + } + } + + @Override + public String registerFile(PathSegment path, byte[] data, String contentType) { + return register(path, s -> { + HttpResponse resp = HttpResponse.create(HttpStatusCode.OK); + resp.addHeader("Content-Type", contentType); + resp.addHeader("Content-Length", String.valueOf(data.length)); + ByteArrayInputStream fs = new ByteArrayInputStream(data); + resp.setData(fs); + return resp; + }); + } + + @Override + public String registerDir(PathSegment path, Path dir, boolean readOnSend) throws IOException { + if (readOnSend) return register(path, new ReadOnSendDirNode(dir)); + else { + try (Stream contentPath = Files.walk(dir)) { + contentPath.filter(Files::isRegularFile) + .filter(Files::isReadable) + .forEach(s -> { + Path p = dir.toAbsolutePath().normalize().relativize(s.toAbsolutePath().normalize()); + PathSegment subPath = path.concat(PathSegment.of(p.toString())); + try { + registerFile(subPath, s, false); + } catch (IOException e) { + LibJf.LOGGER.error("Could not register static file", e); + } + }); + } + return toUrl(path); + } + } + + private String toUrl(PathSegment path) { + return WebPaths.concat(getServerRoot(), path.toString()); + } + + private final Event onStart = RunnableEvent.create(); + @Override + public void onStart(Runnable listener) { + onStart.register(listener); + } + + protected void emitStart() { + onStart.invoker().run(); + } + + private final Event onStop = RunnableEvent.create(); + @Override + public void onStop(Runnable listener) { + onStop.register(listener); + } + + protected void emitStop() { + onStop.invoker().run(); + } + + protected void performRegistrations() { + if (JfWebConfig.enableFileHost) dfh.register(this); + FabricLoader.getInstance().getEntrypointContainers(LibJf.MOD_ID + ":web", WebEntrypoint.class).forEach(entrypoint -> { + WebEntrypoint init = entrypoint.getEntrypoint(); + init.register(this); + }); + } + + protected String getServerRoot(int hostedPort) { + return WebPaths.getHttp(JfWebConfig.serverIp) + ":" + + (JfWebConfig.portOverride != -1 ? JfWebConfig.portOverride : hostedPort); + } +} diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/hosted/HostedWebServer.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/hosted/HostedWebServer.java new file mode 100644 index 0000000..99974b6 --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/hosted/HostedWebServer.java @@ -0,0 +1,62 @@ +package io.gitlab.jfronny.libjf.web.impl.variant.hosted; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.web.impl.*; +import io.gitlab.jfronny.libjf.web.impl.host.RequestHandler; +import io.gitlab.jfronny.libjf.web.impl.variant.AbstractWebServer; + +public class HostedWebServer extends AbstractWebServer { + private HttpServer server = null; + private final int port; + private final int maxConnections; + + public HostedWebServer(RequestHandler handler, int port, int maxConnections) { + super(handler); + this.port = port; + this.maxConnections = maxConnections; + } + + @Override + public String getServerRoot() { + return getServerRoot(server.getPort()); + } + + @Override + public synchronized void stop() { + emitStop(); + if (server != null) { + try { + server.close(); + server.join(); + } + catch (InterruptedException e) { + //It is most likely already dead + } + } + } + + @Override + public void queueRestart(Runnable callback) { + int tmpPort = port; + if (server != null) { + tmpPort = server.getPort(); + stop(); + } else if (tmpPort == 0) tmpPort = JfWebConfig.findAvailablePort(); + handler.clear(); + server = new HttpServer(null, tmpPort, maxConnections, handler, this::performRegistrations); + server.start(); + try { + server.waitUntilReady(); + } catch (InterruptedException e) { + stop(); + LibJf.LOGGER.error("Server could not be readied", e); + } + emitStart(); + callback.run(); + } + + @Override + public boolean isActive() { + return server != null && server.isAlive(); + } +} diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpConnection.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/hosted/HttpConnection.java similarity index 90% rename from libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpConnection.java rename to libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/hosted/HttpConnection.java index aaab0d8..181533d 100644 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpConnection.java +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/hosted/HttpConnection.java @@ -22,9 +22,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.gitlab.jfronny.libjf.web.impl.util.bluemapcore; +package io.gitlab.jfronny.libjf.web.impl.variant.hosted; import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.web.api.v1.*; +import io.gitlab.jfronny.libjf.web.impl.util.HttpRequestImpl; +import io.gitlab.jfronny.libjf.web.impl.util.HttpResponseImpl; import java.io.*; import java.net.*; @@ -64,8 +67,9 @@ public class HttpConnection implements Runnable { sendResponse(response); } catch (InvalidRequestException e){ try { - sendResponse(new HttpResponse(HttpStatusCode.BAD_REQUEST)); - } catch (IOException e1) {} + sendResponse(HttpResponse.create(HttpStatusCode.BAD_REQUEST)); + } catch (IOException e1) { + } break; } catch (SocketTimeoutException | SocketException | ConnectionClosedException e) { break; @@ -82,7 +86,7 @@ public class HttpConnection implements Runnable { } } - private void log(HttpRequest request, HttpResponse response) { + private void log(HttpRequestImpl request, HttpResponseImpl response) { DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); Date date = new Date(); LibJf.LOGGER.info( diff --git a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpServer.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/hosted/HttpServer.java similarity index 97% rename from libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpServer.java rename to libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/hosted/HttpServer.java index cc0e9ac..91a6ace 100644 --- a/libjf-web-v0/src/main/java/io/gitlab/jfronny/libjf/web/impl/util/bluemapcore/HttpServer.java +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/hosted/HttpServer.java @@ -22,9 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.gitlab.jfronny.libjf.web.impl.util.bluemapcore; +package io.gitlab.jfronny.libjf.web.impl.variant.hosted; import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.web.api.v1.HttpRequestHandler; import java.io.IOException; import java.net.*; diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/shared/MainHttpHandlerImpl.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/shared/MainHttpHandlerImpl.java new file mode 100644 index 0000000..c4f3b6a --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/shared/MainHttpHandlerImpl.java @@ -0,0 +1,38 @@ +package io.gitlab.jfronny.libjf.web.impl.variant.shared; + +import io.gitlab.jfronny.libjf.mainhttp.api.v0.MainHttpHandler; +import io.gitlab.jfronny.libjf.mainhttp.api.v0.ServerState; +import io.gitlab.jfronny.libjf.web.api.v1.*; +import io.gitlab.jfronny.libjf.web.impl.JfWeb; +import io.gitlab.jfronny.libjf.web.impl.JfWebConfig; +import org.jetbrains.annotations.Nullable; + +import java.io.*; + +public class MainHttpHandlerImpl implements MainHttpHandler { + public MainHttpHandlerImpl() { + ServerState.onActivate(SharedWebServer::emitActive); + } + + @Override + public boolean isActive() { + return JfWebConfig.port == -1; + } + + @Override + public byte @Nullable [] handle(byte[] request) { + // Parse and process request + try (ByteArrayInputStream is = new ByteArrayInputStream(request); + HttpResponse response = JfWeb.getHandler().handle(HttpRequest.read(is))) { + if (response.getStatusCode() == HttpStatusCode.NOT_FOUND) return null; + // Write and send response + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + response.write(os); + os.flush(); + return os.toByteArray(); + } + } catch (IOException e) { + return null; + } + } +} diff --git a/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/shared/SharedWebServer.java b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/shared/SharedWebServer.java new file mode 100644 index 0000000..4579e60 --- /dev/null +++ b/libjf-web-v1/src/main/java/io/gitlab/jfronny/libjf/web/impl/variant/shared/SharedWebServer.java @@ -0,0 +1,50 @@ +package io.gitlab.jfronny.libjf.web.impl.variant.shared; + +import io.gitlab.jfronny.libjf.mainhttp.api.v0.ServerState; +import io.gitlab.jfronny.libjf.web.impl.host.RequestHandler; +import io.gitlab.jfronny.libjf.web.impl.variant.AbstractWebServer; + +import java.util.*; + +public class SharedWebServer extends AbstractWebServer { + public static final Set onActive = new LinkedHashSet<>(); + + public static void emitActive() { + for (Iterator iterator = onActive.iterator(); iterator.hasNext(); iterator.remove()) { + Runnable runnable = iterator.next(); + runnable.run(); + } + } + + public SharedWebServer(RequestHandler handler) { + super(handler); + } + + @Override + public String getServerRoot() { + if (!ServerState.isActive()) throw new UnsupportedOperationException("Attempted to get server root on unhosted server"); + else return getServerRoot(ServerState.getPort()); + } + + @Override + public void stop() { + throw new UnsupportedOperationException("A shared server cannot be stopped"); + } + + @Override + public void queueRestart(Runnable callback) { + onActive.add(() -> { + emitStop(); + handler.clear(); + performRegistrations(); + emitStart(); + callback.run(); + }); + if (isActive()) emitActive(); + } + + @Override + public boolean isActive() { + return ServerState.isActive(); + } +} diff --git a/libjf-web-v1/src/main/resources/assets/libjf-web-v1/lang/en_us.json b/libjf-web-v1/src/main/resources/assets/libjf-web-v1/lang/en_us.json new file mode 100644 index 0000000..b314596 --- /dev/null +++ b/libjf-web-v1/src/main/resources/assets/libjf-web-v1/lang/en_us.json @@ -0,0 +1,13 @@ +{ + "libjf-web-v1.jfconfig.title": "LibJF Web v0", + "libjf-web-v1.jfconfig.serverIp": "Server IP", + "libjf-web-v1.jfconfig.serverIp.tooltip": "The public IP/host name to send to clients", + "libjf-web-v1.jfconfig.port": "Port", + "libjf-web-v1.jfconfig.port.tooltip": "The port to host content on, 0 to choose a random one or -1 to reuse the minecraft port on servers (requires restart)", + "libjf-web-v1.jfconfig.portOverride": "Port Override", + "libjf-web-v1.jfconfig.portOverride.tooltip": "The port to send to clients (for reverse proxies, -1 to disable)", + "libjf-web-v1.jfconfig.maxConnections": "Max. Connections", + "libjf-web-v1.jfconfig.maxConnections.tooltip": "The maximum number of concurrent connections to this server", + "libjf-web-v1.jfconfig.enableFileHost": "Enable File Host", + "libjf-web-v1.jfconfig.enableFileHost.tooltip": "Whether files from config/wwwroot should be hosted as static resources" +} \ No newline at end of file diff --git a/libjf-web-v0/src/main/resources/fabric.mod.json b/libjf-web-v1/src/main/resources/fabric.mod.json similarity index 77% rename from libjf-web-v0/src/main/resources/fabric.mod.json rename to libjf-web-v1/src/main/resources/fabric.mod.json index 59e1042..813cedb 100644 --- a/libjf-web-v0/src/main/resources/fabric.mod.json +++ b/libjf-web-v1/src/main/resources/fabric.mod.json @@ -1,6 +1,7 @@ { "schemaVersion": 1, - "id": "libjf-web-v0", + "id": "libjf-web-v1", + "provides": ["libjf-web-v0"], "name": "LibJF Web", "version": "${version}", "authors": [ @@ -17,13 +18,15 @@ "entrypoints": { "main": ["io.gitlab.jfronny.libjf.web.impl.JfWeb"], "libjf:coprocess": ["io.gitlab.jfronny.libjf.web.impl.JfWeb"], - "libjf:config": ["io.gitlab.jfronny.libjf.web.impl.JFC_JfWebConfig"] + "libjf:config": ["io.gitlab.jfronny.libjf.web.impl.JFC_JfWebConfig"], + "libjf-mainhttp:v0": ["io.gitlab.jfronny.libjf.web.impl.variant.shared.MainHttpHandlerImpl"] }, "depends": { "fabricloader": ">=0.12.0", "minecraft": "*", "libjf-base": ">=${version}", - "libjf-config-core-v1": ">=${version}", + "libjf-config-core-v2": ">=${version}", + "libjf-mainhttp-v0": ">=${version}", "fabric-command-api-v2": "*" }, "custom": { diff --git a/libjf-web-v1/src/testmod/java/io/gitlab/jfronny/libjf/web/test/WebTest.java b/libjf-web-v1/src/testmod/java/io/gitlab/jfronny/libjf/web/test/WebTest.java new file mode 100644 index 0000000..65e8237 --- /dev/null +++ b/libjf-web-v1/src/testmod/java/io/gitlab/jfronny/libjf/web/test/WebTest.java @@ -0,0 +1,26 @@ +package io.gitlab.jfronny.libjf.web.test; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.web.api.v1.*; +import net.fabricmc.loader.api.FabricLoader; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class WebTest implements WebEntrypoint { + @Override + public void register(WebServer api) { + Path sourcePath = FabricLoader.getInstance() + .getModContainer("libjf-web-v1-testmod") + .flatMap(modContainer -> modContainer.findPath("test.html")) + .orElseThrow(); + LibJf.LOGGER.info(api.register(PathSegment.of("test/0.html"), request -> request.createResponse(HttpStatusCode.OK).setData(Files.readString(sourcePath)))); + try { + LibJf.LOGGER.info(api.registerFile(PathSegment.of("test/1.html"), sourcePath, false)); + LibJf.LOGGER.info(api.registerFile(PathSegment.of("test/2.html"), sourcePath, true)); + } catch (IOException e) { + throw new RuntimeException("Could not register hosted files", e); + } + } +} diff --git a/libjf-web-v0/src/testmod/resources/fabric.mod.json b/libjf-web-v1/src/testmod/resources/fabric.mod.json similarity index 90% rename from libjf-web-v0/src/testmod/resources/fabric.mod.json rename to libjf-web-v1/src/testmod/resources/fabric.mod.json index 01f70a7..bb77d58 100644 --- a/libjf-web-v0/src/testmod/resources/fabric.mod.json +++ b/libjf-web-v1/src/testmod/resources/fabric.mod.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "id": "libjf-web-v0-testmod", + "id": "libjf-web-v1-testmod", "name": "LibJF Web", "version": "1.0", "environment": "*", diff --git a/libjf-web-v0/src/testmod/resources/test.html b/libjf-web-v1/src/testmod/resources/test.html similarity index 100% rename from libjf-web-v0/src/testmod/resources/test.html rename to libjf-web-v1/src/testmod/resources/test.html diff --git a/settings.gradle.kts b/settings.gradle.kts index 2f8c2cd..83731fb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,15 +14,19 @@ rootProject.name = "libjf" include("libjf-base") -include("libjf-config-core-v1") -include("libjf-config-reflect-v1") -include("libjf-config-commands-v1") -include("libjf-config-ui-tiny-v1") +include("libjf-config-core-v2") +include("libjf-config-commands") +include("libjf-config-ui-tiny") +include("libjf-config-compiler-plugin-v2") + include("libjf-data-v0") include("libjf-data-manipulation-v0") -include("libjf-devutil") -include("libjf-translate-v1") -include("libjf-unsafe-v0") -include("libjf-web-v0") -include("libjf-config-compiler-plugin-v2") +include("libjf-devutil") + +include("libjf-translate-v1") + +include("libjf-unsafe-v0") + +include("libjf-mainhttp-v0") +include("libjf-web-v1")