Refactor into separate modules

This commit is contained in:
JFronny 2021-09-27 20:55:48 +02:00
parent 98c736af46
commit f939dadec6
No known key found for this signature in database
GPG Key ID: BEC5ACBBD4EE17E5
77 changed files with 970 additions and 227 deletions

View File

@ -26,4 +26,4 @@ deploy:
stage: deploy
when: manual
script:
- gradle --build-cache publishModrinth curseforge
- gradle --build-cache modrinth curseforge

View File

@ -1,43 +1,223 @@
apply from: "https://gitlab.com/-/snippets/2121059/raw/master/jfbase.gradle"
plugins {
id "java-library"
id "eclipse"
id "idea"
id "maven-publish"
id "fabric-loom" version "0.10-SNAPSHOT" apply false
id "com.matthewprenger.cursegradle" version "1.4.0"
id "com.modrinth.minotaur" version "1.1.0"
}
repositories {
maven {
name = 'TerraformersMC'
url = 'https://maven.terraformersmc.com/'
version = "$project.mod_version"
def moduleDependencies(project, List<String> depNames) {
def deps = depNames.iterator().collect { project.dependencies.project(path: ":$it", configuration: 'dev') }
project.dependencies {
deps.each {
api it
}
}
project.publishing {
publications {
mavenJava(MavenPublication) {
pom.withXml {
def depsNode = asNode().appendNode("dependencies")
deps.each {
def depNode = depsNode.appendNode("dependency")
depNode.appendNode("groupId", it.group)
depNode.appendNode("artifactId", it.name)
depNode.appendNode("version", it.version)
depNode.appendNode("scope", "compile")
}
}
}
}
}
}
sourceSets {
testmod {
compileClasspath += main.compileClasspath + main.output
runtimeClasspath += main.runtimeClasspath + main.output
allprojects {
apply plugin: "java-library"
apply plugin: "fabric-loom"
tasks.withType(JavaCompile).configureEach {
it.options.release = 16
}
group = "io.gitlab.jfronny.libjf"
sourceSets {
testmod {
compileClasspath += main.compileClasspath
runtimeClasspath += main.runtimeClasspath
}
}
loom {
runs {
testmodClient {
client()
ideConfigGenerated project.rootProject == project
name = "Testmod Client"
source sourceSets.testmod
}
testmodServer {
server()
ideConfigGenerated project.rootProject == project
name = "Testmod Server"
source sourceSets.testmod
}
}
}
dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.minecraft_version}+${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "com.terraformersmc:modmenu:2.0.10"
include modImplementation(fabricApi.module("fabric-tag-extensions-v0", "0.40.1+1.17"))
include modImplementation(fabricApi.module("fabric-resource-loader-v0", "0.40.1+1.17"))
}
configurations {
dev
}
loom {
shareRemapCaches = true
}
repositories {
maven {
name = 'TerraformersMC'
url = 'https://maven.terraformersmc.com/'
}
}
jar {
archiveClassifier = "dev"
}
afterEvaluate {
remapJar {
input = file("${project.buildDir}/libs/$archivesBaseName-${project.version}-dev.jar")
archiveFileName = "${archivesBaseName}-${project.version}.jar"
}
artifacts {
dev file: file("${project.buildDir}/libs/$archivesBaseName-${project.version}-dev.jar"), type: "jar", builtBy: jar
}
processResources {
inputs.property "version", project.version
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
}
task sourcesJar(type: Jar, dependsOn: classes) {
archiveClassifier = "sources"
from sourceSets.main.allSource
}
tasks.withType(AbstractArchiveTask) {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
}
subprojects {
dependencies {
testmodImplementation sourceSets.main.output
}
publishing {
publications {
mavenJava(MavenPublication) {
afterEvaluate {
artifact(remapJar) {
builtBy remapJar
}
artifact(sourcesJar) {
builtBy remapSourcesJar
}
}
}
}
}
}
subprojects.each { remapJar.dependsOn("${it.path}:remapJar") }
dependencies {
//to change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.minecraft_version}+${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
afterEvaluate {
subprojects.each {
api project(path: ":${it.name}", configuration: "dev")
include modImplementation(fabricApi.module("fabric-tag-extensions-v0", "0.40.1+1.17"))
include modImplementation(fabricApi.module("fabric-resource-loader-v0", "0.40.1+1.17"))
modImplementation "com.terraformersmc:modmenu:2.0.10"
}
include project("${it.name}:")
loom {
runs {
testmodClient {
client()
ideConfigGenerated project.rootProject == project
name = "Testmod Client"
source sourceSets.testmod
}
testmodServer {
server()
ideConfigGenerated project.rootProject == project
name = "Testmod Server"
source sourceSets.testmod
testmodImplementation project("${it.name}:").sourceSets.testmod.output
}
}
}
task modrinth(type: com.modrinth.minotaur.TaskModrinthUpload, dependsOn: remapJar) {
onlyIf {
System.getenv().MODRINTH_API_TOKEN
}
token = System.getenv().MODRINTH_API_TOKEN
projectId = "WKwQAwke"
versionNumber = version
versionName = "[${project.minecraft_version}] ${project.mod_version}"
uploadFile = remapJar
addGameVersion("${project.minecraft_version}")
addLoader('fabric')
}
curseforge {
if (System.getenv().CURSEFORGE_API_TOKEN) {
apiKey = System.getenv().CURSEFORGE_API_TOKEN
} else {
println "No CURSEFORGE_API_TOKEN specified"
}
project {
id = "482600"
releaseType = 'release'
addGameVersion "Fabric"
addGameVersion "${project.minecraft_version}"
changelog = ""
mainArtifact(file("${project.buildDir}/libs/${archivesBaseName}-${version}.jar"))
mainArtifact.displayName = "[${project.minecraft_version}] ${project.mod_version}"
afterEvaluate {
uploadTask.dependsOn(remapJar)
}
}
options {
forgeGradleIntegration = false
}
}
task remapMavenJar(type: net.fabricmc.loom.task.RemapJarTask, dependsOn: jar) {
input = jar.archiveFile
archiveFileName = "${archivesBaseName}-${project.version}-maven.jar"
addNestedDependencies = false
}
build.dependsOn remapMavenJar
publishing {
publications {
maven(MavenPublication) {
artifact(remapMavenJar) {
builtBy remapMavenJar
}
artifact(sourcesJar) {
builtBy remapSourcesJar
}
}
}
}

21
ensure-jitpack-java-16 Normal file
View File

@ -0,0 +1,21 @@
#!/bin/bash
# https://github.com/jitpack/jitpack.io/issues/4355#issuecomment-744678253
JV=`java -version 2>&1 >/dev/null | head -1`
echo $JV | sed -E 's/^.*version "([^".]*)\.[^"]*".*$/\1/'
if [ "$JV" != 16 ]; then
case "$1" in
install)
echo "installing sdkman..."
curl -s "https://get.sdkman.io" | bash
source ~/.sdkman/bin/sdkman-init.sh
sdk install java 16.0.1-open
;;
use)
echo "must source ~/.sdkman/bin/sdkman-init.sh"
exit 1
;;
esac
fi

View File

@ -9,10 +9,3 @@ loader_version=0.11.6
mod_version=1.2.3
maven_group=io.gitlab.jfronny
archives_base_name=libjf
modrinth_id=WKwQAwke
modrinth_required_dependencies=
modrinth_optional_dependencies=
curseforge_id=482600
curseforge_required_dependencies=
curseforge_optional_dependencies=

10
jitpack.yml Normal file
View File

@ -0,0 +1,10 @@
jdk:
- openjdk16
before_install:
- bash ensure-jitpack-java-16 install
install:
- if ! bash ensure-jitpack-java-16 use; then source ~/.sdkman/bin/sdkman-init.sh; fi
- java -version
- ./gradlew publishToMavenLocal

5
libjf-base/build.gradle Normal file
View File

@ -0,0 +1,5 @@
archivesBaseName = "libjf-base"
version = "1.0"
dependencies {
}

View File

@ -0,0 +1,22 @@
package io.gitlab.jfronny.libjf;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.gitlab.jfronny.libjf.gson.HiddenAnnotationExclusionStrategy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.Modifier;
public class LibJf {
private LibJf() {
}
public static final String MOD_ID = "libjf";
public static final Logger LOGGER = LogManager.getLogger(MOD_ID);
public static final Gson GSON = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
.excludeFieldsWithModifiers(Modifier.PRIVATE)
.addSerializationExclusionStrategy(new HiddenAnnotationExclusionStrategy())
.setPrettyPrinting()
.create();
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.data;
package io.gitlab.jfronny.libjf;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;

View File

@ -4,7 +4,9 @@ import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
public class HiddenAnnotationExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) { return false; }
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return fieldAttributes.getAnnotation(GsonHidden.class) != null;
}

View File

@ -0,0 +1,23 @@
{
"schemaVersion": 1,
"id": "libjf-base",
"version": "${version}",
"authors": [
"JFronny"
],
"contact": {
"website": "https://jfronny.gitlab.io",
"repo": "https://gitlab.com/jfmods/libjf"
},
"license": "MIT",
"environment": "*",
"depends": {
"fabricloader": ">=0.11.3",
"minecraft": "*"
},
"custom": {
"modmenu": {
"parent": "libjf"
}
}
}

View File

@ -0,0 +1,6 @@
{
"schemaVersion": 1,
"id": "libjf-base-testmod",
"version": "${version}",
"environment": "*"
}

View File

@ -0,0 +1,6 @@
archivesBaseName = "libjf-config-v0"
version = "1.0"
dependencies {
moduleDependencies(project, ["libjf-base", "libjf-unsafe-v0"])
}

View File

@ -1,6 +1,7 @@
package io.gitlab.jfronny.libjf.config;
import io.gitlab.jfronny.libjf.Libjf;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.entry.Entry;
import io.gitlab.jfronny.libjf.gson.GsonHidden;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@ -39,22 +40,22 @@ public class Config {
for (Field field : config.getFields()) {
EntryInfo info = new EntryInfo();
info.field = field;
if (field.isAnnotationPresent(Entry.class))
if (field.isAnnotationPresent(io.gitlab.jfronny.libjf.config.entry.Entry.class))
try {
info.defaultValue = field.get(null);
} catch (IllegalAccessException ignored) {}
entries.add(info);
}
try {
Libjf.GSON.fromJson(Files.newBufferedReader(path), config); }
LibJf.GSON.fromJson(Files.newBufferedReader(path), config); }
catch (Exception e) { write(); }
}
@Environment(EnvType.CLIENT)
public void initClient(EntryInfo info) {
if (!(info.field.isAnnotationPresent(Entry.class) || info.field.isAnnotationPresent(GsonHidden.class))) return;
if (!(info.field.isAnnotationPresent(io.gitlab.jfronny.libjf.config.entry.Entry.class) || info.field.isAnnotationPresent(GsonHidden.class))) return;
Class<?> type = info.field.getType();
Entry e = info.field.getAnnotation(Entry.class);
io.gitlab.jfronny.libjf.config.entry.Entry e = info.field.getAnnotation(Entry.class);
info.width = e != null ? e.width() : 0;
if (e == null) return;
@ -120,7 +121,7 @@ public class Config {
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
try {
if (!Files.exists(path)) Files.createFile(path);
Files.write(path, Libjf.GSON.toJson(configClass.getDeclaredConstructor().newInstance()).getBytes());
Files.write(path, LibJf.GSON.toJson(configClass.getDeclaredConstructor().newInstance()).getBytes());
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -0,0 +1,29 @@
package io.gitlab.jfronny.libjf.config;
import com.google.common.collect.ImmutableMap;
import java.util.HashMap;
import java.util.Map;
public class ConfigHolder {
private ConfigHolder() {
}
private static final Map<String, Config> configs = new HashMap<>();
public static void registerConfig(String modId, Class<?> config) {
if (!isRegistered(config))
configs.put(modId, new Config(modId, config));
}
public static Map<String, Config> getConfigs() {
return ImmutableMap.copyOf(configs);
}
public static boolean isRegistered(Class<?> config) {
for (Config value : configs.values()) {
if (value.configClass.equals(config))
return true;
}
return false;
}
}

View File

@ -2,8 +2,8 @@ package io.gitlab.jfronny.libjf.config;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import io.gitlab.jfronny.libjf.Libjf;
import io.gitlab.jfronny.libjf.config.gui.TinyConfigScreen;
import io.gitlab.jfronny.libjf.LibJf;
import java.util.HashMap;
import java.util.Map;
@ -12,8 +12,8 @@ public class ModMenu implements ModMenuApi {
@Override
public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
Map<String, ConfigScreenFactory<?>> factories = new HashMap<>();
for (Map.Entry<String, Config> entry : Libjf.getConfigs().entrySet()) {
if (!Libjf.MOD_ID.equals(entry.getKey()))
for (Map.Entry<String, Config> entry : ConfigHolder.getConfigs().entrySet()) {
if (!LibJf.MOD_ID.equals(entry.getKey()))
factories.put(entry.getKey(), buildFactory(entry.getValue()));
}
return factories;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.config;
package io.gitlab.jfronny.libjf.config.entry;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -1,17 +1,17 @@
package io.gitlab.jfronny.libjf.entry;
package io.gitlab.jfronny.libjf.config.entry;
import io.gitlab.jfronny.libjf.Libjf;
import io.gitlab.jfronny.libjf.config.Config;
import io.gitlab.jfronny.libjf.config.Entry;
import io.gitlab.jfronny.libjf.config.ConfigHolder;
import io.gitlab.jfronny.libjf.config.EntryInfo;
import io.gitlab.jfronny.libjf.gson.GsonHidden;
import io.gitlab.jfronny.libjf.LibJf;
import net.fabricmc.api.ClientModInitializer;
public class LibjfClient implements ClientModInitializer {
public class JfConfigClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
for (Config config : Libjf.getConfigs().values()) {
Libjf.LOGGER.info("Registring config UI for " + config.modid);
for (Config config : ConfigHolder.getConfigs().values()) {
LibJf.LOGGER.info("Registring config UI for " + config.modid);
for (EntryInfo info : config.entries) {
if (info.field.isAnnotationPresent(Entry.class) || info.field.isAnnotationPresent(GsonHidden.class))
try {

View File

@ -0,0 +1,18 @@
package io.gitlab.jfronny.libjf.config.entry;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.ConfigHolder;
import io.gitlab.jfronny.libjf.config.JfConfig;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.entrypoint.EntrypointContainer;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
public class JfConfigSafe implements PreLaunchEntrypoint {
@Override
public void onPreLaunch() {
for (EntrypointContainer<JfConfig> config : FabricLoader.getInstance().getEntrypointContainers(LibJf.MOD_ID + ":config", JfConfig.class)) {
ConfigHolder.registerConfig(config.getProvider().getMetadata().getId(), config.getEntrypoint().getClass());
LibJf.LOGGER.info("Registering config for " + config.getProvider().getMetadata().getId());
}
}
}

View File

@ -0,0 +1,17 @@
package io.gitlab.jfronny.libjf.config.entry;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.ConfigHolder;
import io.gitlab.jfronny.libjf.config.JfConfig;
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(LibJf.MOD_ID + ":config", JfConfig.class, s -> {
ConfigHolder.registerConfig(s.modId(), s.instance().getClass());
LibJf.LOGGER.info("Registering config for " + s.modId());
});
}
}

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.libjf.config.gui;
import io.gitlab.jfronny.libjf.Libjf;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.Config;
import io.gitlab.jfronny.libjf.config.Entry;
import io.gitlab.jfronny.libjf.config.entry.Entry;
import io.gitlab.jfronny.libjf.config.EntryInfo;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@ -54,7 +54,7 @@ public class TinyConfigScreen extends Screen {
this.addDrawableChild(new ButtonWidget(this.width / 2 - 154, this.height - 28, 150, 20, ScreenTexts.CANCEL, button -> {
try {
Libjf.GSON.fromJson(Files.newBufferedReader(config.path), config.configClass); }
LibJf.GSON.fromJson(Files.newBufferedReader(config.path), config.configClass); }
catch (Exception e) { config.write(); }
for (EntryInfo info : config.entries) {

View File

@ -0,0 +1,35 @@
{
"schemaVersion": 1,
"id": "libjf-base",
"name": "LibJF Base",
"version": "${version}",
"authors": [
"JFronny"
],
"contact": {
"website": "https://jfronny.gitlab.io",
"repo": "https://gitlab.com/jfmods/libjf"
},
"license": "MIT",
"environment": "*",
"entrypoints": {
"modmenu": [
"io.gitlab.jfronny.libjf.config.ModMenu"
],
"client": [
"io.gitlab.jfronny.libjf.config.entry.JfConfigClient"
],
"libjf:preEarly": [
"io.gitlab.jfronny.libjf.config.entry.JfConfigUnsafe"
],
"preLaunch": [
"io.gitlab.jfronny.libjf.config.entry.JfConfigSafe"
]
},
"custom": {
"modmenu": {
"badges": ["library"],
"parent": "libjf"
}
}
}

View File

@ -1,17 +1,19 @@
package io.gitlab.jfronny.libjf.test;
package io.gitlab.jfronny.libjf.config.test;
import io.gitlab.jfronny.libjf.config.Entry;
import io.gitlab.jfronny.libjf.config.JfConfig;
import io.gitlab.jfronny.libjf.config.entry.Entry;
import io.gitlab.jfronny.libjf.gson.GsonHidden;
public class TestMod implements JfConfig {
public class TestConfig implements JfConfig {
@Entry public static boolean disablePacks = false;
@Entry public static int intTest = 20;
@Entry public static double decimalTest = 20;
@Entry public static String dieStr = "lolz";
@Entry @GsonHidden public static String guiOnlyStr = "lolz";
@Entry @GsonHidden
public static String guiOnlyStr = "lolz";
public static String gsonOnlyStr = "lolz";
@Entry public static Test enumTest = Test.Test;
@Entry
public static Test enumTest = Test.Test;
public enum Test {
Test, ER

View File

@ -0,0 +1,11 @@
{
"libjf-config-v0-testmod.jfconfig.title": "JfConfig example",
"libjf-config-v0-testmod.jfconfig.disablePacks": "Disable resource packs",
"libjf-config-v0-testmod.jfconfig.intTest": "Int Test",
"libjf-config-v0-testmod.jfconfig.decimalTest": "Decimal Test",
"libjf-config-v0-testmod.jfconfig.dieStr": "String Test",
"libjf-config-v0-testmod.jfconfig.enumTest": "Enum Test",
"libjf-config-v0-testmod.jfconfig.enumTest.tooltip": "Enum Test Tooltip",
"libjf-config-v0-testmod.jfconfig.enum.Test.Test": "Test",
"libjf-config-v0-testmod.jfconfig.enum.Test.ER": "ER"
}

View File

@ -0,0 +1,11 @@
{
"schemaVersion": 1,
"id": "libjf-config-v0-testmod",
"version": "${version}",
"environment": "*",
"entrypoints": {
"libjf:config": [
"io.gitlab.jfronny.libjf.config.test.TestConfig"
]
}
}

View File

@ -0,0 +1,6 @@
archivesBaseName = "libjf-data-manipulation-v0"
version = "1.0"
dependencies {
moduleDependencies(project, ["libjf-base"])
}

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.libjf.data;
package io.gitlab.jfronny.libjf.data.manipulation;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
@ -14,8 +15,8 @@ public class RecipeUtil {
REMOVAL_BY_ID.add(identifier);
}
public static void removeRecipeFor(ItemStack product) {
RECIPES_FOR_REMOVAL.add(product);
public static void removeRecipeFor(Item product) {
RECIPES_FOR_REMOVAL.add(product.getDefaultStack());
}
public static boolean isIdBlocked(Identifier identifier) {

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.data;
package io.gitlab.jfronny.libjf.data.manipulation;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;

View File

@ -1,6 +1,6 @@
package io.gitlab.jfronny.libjf.data;
package io.gitlab.jfronny.libjf.data.manipulation;
import io.gitlab.jfronny.libjf.data.impl.WrappedResourcePack;
import io.gitlab.jfronny.libjf.data.manipulation.impl.WrappedResourcePack;
import net.minecraft.resource.ResourcePack;
//This is a class for binary compatibility with mods using libjf

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.libjf.data.impl;
package io.gitlab.jfronny.libjf.data.manipulation.impl;
import io.gitlab.jfronny.libjf.data.ResourcePath;
import io.gitlab.jfronny.libjf.data.UserResourceEvents;
import io.gitlab.jfronny.libjf.data.WrappedPack;
import io.gitlab.jfronny.libjf.ResourcePath;
import io.gitlab.jfronny.libjf.data.manipulation.UserResourceEvents;
import io.gitlab.jfronny.libjf.data.manipulation.WrappedPack;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;

View File

@ -1,6 +1,6 @@
package io.gitlab.jfronny.libjf.data.impl;
package io.gitlab.jfronny.libjf.data.manipulation.impl;
import io.gitlab.jfronny.libjf.data.WrappedPack;
import io.gitlab.jfronny.libjf.data.manipulation.WrappedPack;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import net.minecraft.resource.metadata.ResourceMetadataReader;

View File

@ -1,9 +1,9 @@
package io.gitlab.jfronny.libjf.mixin;
package io.gitlab.jfronny.libjf.data.manipulation.mixin;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonObject;
import io.gitlab.jfronny.libjf.Libjf;
import io.gitlab.jfronny.libjf.data.RecipeUtil;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.data.manipulation.RecipeUtil;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeManager;
import net.minecraft.util.Identifier;
@ -26,7 +26,7 @@ public class RecipeManagerMixin {
Identifier recipeId = cur.getKey();
if (RecipeUtil.isIdBlocked(recipeId)) {
Libjf.LOGGER.info("Blocking recipe by identifier: " + recipeId);
LibJf.LOGGER.info("Blocking recipe by identifier: " + recipeId);
} else {
replacement.add(cur);
}
@ -41,7 +41,7 @@ public class RecipeManagerMixin {
Recipe<?> recipe = (Recipe<?>) value;
if (RecipeUtil.isOutputBlocked(recipe.getOutput())) {
Libjf.LOGGER.info("Blocked recipe by predicate: " + recipe.getId());
LibJf.LOGGER.info("Blocked recipe by predicate: " + recipe.getId());
return builder;
}

View File

@ -1,6 +1,6 @@
package io.gitlab.jfronny.libjf.mixin;
package io.gitlab.jfronny.libjf.data.manipulation.mixin;
import io.gitlab.jfronny.libjf.data.WrappedPack;
import io.gitlab.jfronny.libjf.data.manipulation.WrappedPack;
import net.fabricmc.fabric.impl.resource.loader.FabricModResourcePack;
import net.fabricmc.fabric.impl.resource.loader.ModNioResourcePack;
import net.minecraft.resource.ReloadableResourceManagerImpl;

View File

@ -0,0 +1,20 @@
{
"schemaVersion": 1,
"id": "libjf-data-manipulation-v0",
"version": "${version}",
"authors": [
"JFronny"
],
"contact": {
"website": "https://jfronny.gitlab.io",
"repo": "https://gitlab.com/jfmods/libjf"
},
"license": "MIT",
"environment": "*",
"mixins": ["libjf-data-manipulation-v0.mixins.json"],
"custom": {
"modmenu": {
"parent": "libjf"
}
}
}

View File

@ -0,0 +1,15 @@
{
"required": true,
"minVersion": "0.8",
"package": "io.gitlab.jfronny.libjf.data.manipulation.mixin",
"compatibilityLevel": "JAVA_16",
"mixins": [
"RecipeManagerMixin",
"ReloadableResourceManagerImplMixin"
],
"client": [
],
"injectors": {
"defaultRequire": 1
}
}

View File

@ -0,0 +1,28 @@
package io.gitlab.jfronny.libjf.data.manipulation.test;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.data.manipulation.RecipeUtil;
import io.gitlab.jfronny.libjf.data.manipulation.UserResourceEvents;
import net.fabricmc.api.ModInitializer;
import net.minecraft.item.Items;
import net.minecraft.resource.AbstractFileResourcePack;
public class TestEntrypoint implements ModInitializer {
@Override
public void onInitialize() {
// This should prevent resource packs from doing anything if my hooks are working and
UserResourceEvents.OPEN.register((type, id, previous, pack) -> {
if (pack.getUnderlying() instanceof AbstractFileResourcePack) {
LibJf.LOGGER.info(pack.getName() + " opened " + type.name() + "/" + id.toString());
}
return previous;
});
UserResourceEvents.CONTAINS.register((type, id, previous, pack) -> {
if (pack.getUnderlying() instanceof AbstractFileResourcePack) {
return false;
}
return previous;
});
RecipeUtil.removeRecipeFor(Items.DIAMOND_SWORD);
}
}

View File

@ -0,0 +1,11 @@
{
"schemaVersion": 1,
"id": "libjf-data-manipulation-v0-testmod",
"version": "${version}",
"environment": "*",
"entrypoints": {
"main": [
"io.gitlab.jfronny.libjf.data.manipulation.test.TestEntrypoint"
]
}
}

View File

@ -0,0 +1,6 @@
archivesBaseName = "libjf-data-v0"
version = "1.0"
dependencies {
moduleDependencies(project, ["libjf-base"])
}

View File

@ -0,0 +1,12 @@
package io.gitlab.jfronny.libjf.data;
import io.gitlab.jfronny.libjf.LibJf;
import net.fabricmc.fabric.api.tag.TagFactory;
import net.minecraft.item.Item;
import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier;
public class Tags {
public static final Tag<Item> SHULKER_ILLEGAL = TagFactory.ITEM.create(new Identifier(LibJf.MOD_ID, "shulker_boxes_illegal"));
public static final Tag<Item> OVERPOWERED = TagFactory.ITEM.create(new Identifier(LibJf.MOD_ID, "overpowered"));
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.mixin;
package io.gitlab.jfronny.libjf.data.mixin;
import io.gitlab.jfronny.libjf.data.Tags;
import net.minecraft.entity.Entity;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.mixin;
package io.gitlab.jfronny.libjf.data.mixin;
import io.gitlab.jfronny.libjf.data.Tags;
import net.minecraft.block.entity.ShulkerBoxBlockEntity;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.mixin;
package io.gitlab.jfronny.libjf.data.mixin;
import io.gitlab.jfronny.libjf.data.Tags;
import net.minecraft.item.ItemStack;

View File

@ -0,0 +1,20 @@
{
"schemaVersion": 1,
"id": "libjf-data-v0",
"version": "${version}",
"authors": [
"JFronny"
],
"contact": {
"website": "https://jfronny.gitlab.io",
"repo": "https://gitlab.com/jfmods/libjf"
},
"license": "MIT",
"environment": "*",
"mixins": ["libjf-data-v0.mixins.json"],
"custom": {
"modmenu": {
"parent": "libjf"
}
}
}

View File

@ -1,12 +1,10 @@
{
"required": true,
"minVersion": "0.8",
"package": "io.gitlab.jfronny.libjf.mixin",
"package": "io.gitlab.jfronny.libjf.data.mixin",
"compatibilityLevel": "JAVA_16",
"mixins": [
"EntityMixin",
"RecipeManagerMixin",
"ReloadableResourceManagerImplMixin",
"ShulkerBoxBlockEntityMixin",
"ShulkerBoxSlotMixin"
],

View File

@ -0,0 +1,9 @@
{
"replace": false,
"values": [
"minecraft:netherite_helmet",
"minecraft:netherite_chestplate",
"minecraft:netherite_leggings",
"minecraft:netherite_boots"
]
}

View File

@ -0,0 +1,6 @@
{
"schemaVersion": 1,
"id": "libjf-data-v0-testmod",
"version": "${version}",
"environment": "*"
}

View File

@ -0,0 +1,6 @@
archivesBaseName = "libjf-unsafe-v0"
version = "1.0"
dependencies {
moduleDependencies(project, ["libjf-base"])
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.entry;
package io.gitlab.jfronny.libjf.unsafe;
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
import net.fabricmc.loader.ModContainer;

View File

@ -0,0 +1,15 @@
package io.gitlab.jfronny.libjf.unsafe;
import io.gitlab.jfronny.libjf.LibJf;
import net.fabricmc.loader.api.LanguageAdapter;
public class JfLanguageAdapter implements LanguageAdapter {
@Override
public native <T> T create(net.fabricmc.loader.api.ModContainer mod, String value, Class<T> type);
static {
DynamicEntry.execute(LibJf.MOD_ID + ":preEarly", UltraEarlyInit.class, s -> s.instance().init());
DynamicEntry.execute(LibJf.MOD_ID + ":early", UltraEarlyInit.class, s -> s.instance().init());
LibJf.LOGGER.info("LibJF unsafe init completed");
}
}

View File

@ -0,0 +1,81 @@
package io.gitlab.jfronny.libjf.unsafe;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.unsafe.asm.AsmConfig;
import io.gitlab.jfronny.libjf.unsafe.asm.AsmConfigBaker;
import io.gitlab.jfronny.libjf.unsafe.asm.AsmTransformer;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import org.spongepowered.asm.mixin.transformer.FabricMixinTransformerProxy;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;
public class MixinPlugin implements IMixinConfigPlugin {
@Override
public void onLoad(String mixinPackage) {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> classLoaderClass = classLoader.getClass();
Field delegateField = classLoaderClass.getDeclaredField("delegate");
delegateField.setAccessible(true);
Object delegate = delegateField.get(classLoader);
Class<?> delegateClass = delegate.getClass();
Field mixinTransformerField = delegateClass.getDeclaredField("mixinTransformer");
mixinTransformerField.setAccessible(true);
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
AsmTransformer mixinTransformer = (AsmTransformer) unsafe.allocateInstance(AsmTransformer.class);
mixinTransformer.delegate = (FabricMixinTransformerProxy) mixinTransformerField.get(delegate);
AsmConfigBaker baker = new AsmConfigBaker();
DynamicEntry.execute(LibJf.MOD_ID + ":asm", AsmConfig.class, s -> {
LibJf.LOGGER.info("Discovered LibJF asm plugin in " + s.modId());
baker.add(s.instance());
});
mixinTransformer.asmConfig = baker.bake();
mixinTransformerField.set(delegate, mixinTransformer);
} catch (NoSuchFieldException | IllegalAccessException | InstantiationException e) {
LibJf.LOGGER.error("Could not initialize LibJF ASM", e);
}
}
@Override
public String getRefMapperConfig() {
return null;
}
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
return false;
}
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
}
@Override
public List<String> 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) {
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.entry;
package io.gitlab.jfronny.libjf.unsafe;
public interface UltraEarlyInit {
void init();

View File

@ -0,0 +1,10 @@
package io.gitlab.jfronny.libjf.unsafe.asm;
import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch;
import java.util.Set;
public interface AsmConfig {
Set<String> skipClasses();
Set<Patch> getPatches();
}

View File

@ -0,0 +1,38 @@
package io.gitlab.jfronny.libjf.unsafe.asm;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class AsmConfigBaker {
private final Set<AsmConfig> configs = new LinkedHashSet<>();
public void add(AsmConfig config) {
configs.add(config);
}
public AsmConfig bake() {
Set<String> skipClasses = new HashSet<>();
Set<Patch> patches = new LinkedHashSet<>();
for (AsmConfig config : configs) {
Set<String> skipClassesC = config.skipClasses();
Set<Patch> patchesC = config.getPatches();
if (skipClassesC != null) skipClasses.addAll(skipClassesC);
if (patchesC != null) patches.addAll(patchesC);
}
LibJf.LOGGER.info("Applying " + patches.size() + " ASM patches");
return new AsmConfig() {
@Override
public Set<String> skipClasses() {
return skipClasses;
}
@Override
public Set<Patch> getPatches() {
return patches;
}
};
}
}

View File

@ -0,0 +1,41 @@
package io.gitlab.jfronny.libjf.unsafe.asm;
import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.transformer.FabricMixinTransformerProxy;
import org.spongepowered.asm.transformers.MixinClassWriter;
public class AsmTransformer extends FabricMixinTransformerProxy {
public FabricMixinTransformerProxy delegate;
public AsmConfig asmConfig;
@Override
public byte[] transformClassBytes(String name, String transformedName, byte[] basicClass) {
byte[] data = delegate.transformClassBytes(name, transformedName, basicClass);
if (data == null || name == null)
return basicClass;
basicClass = data;
if (name.startsWith("org.objectweb.asm")
|| name.startsWith("net.fabricmc.loader")
|| name.startsWith("net.minecraft")
|| name.startsWith("io.gitlab.jfronny.libjf.unsafe.asm")
|| name.startsWith("joptsimple")
)
return basicClass;
ClassNode klass = new ClassNode();
ClassReader reader = new ClassReader(basicClass);
reader.accept(klass, ClassReader.EXPAND_FRAMES);
for (Patch patch : asmConfig.getPatches()) {
patch.apply(klass);
}
ClassWriter writer = new MixinClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
klass.accept(writer);
basicClass = writer.toByteArray();
return basicClass;
}
}

View File

@ -0,0 +1,34 @@
package io.gitlab.jfronny.libjf.unsafe.asm.patch;
import io.gitlab.jfronny.libjf.LibJf;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodNode;
import java.util.Map;
import java.util.function.Consumer;
public abstract class InterfaceImplMethodReplacePatch implements Patch {
private final String targetInterface;
protected InterfaceImplMethodReplacePatch(String targetInterface) {
this.targetInterface = targetInterface;
}
public abstract Map<String, Consumer<InsnList>> getPatches();
@Override
public void apply(ClassNode klazz) {
if (klazz.interfaces.contains(targetInterface) || targetInterface.equals(klazz.superName)) {
LibJf.LOGGER.info("Found " + klazz.name + " implementing " + targetInterface);
Map<String, Consumer<InsnList>> patches = getPatches();
for (MethodNode method : klazz.methods) {
if (patches.containsKey(method.name)) {
LibJf.LOGGER.info("Patching " + method.name);
method.instructions.clear();
patches.get(method.name).accept(method.instructions);
}
}
}
}
}

View File

@ -0,0 +1,7 @@
package io.gitlab.jfronny.libjf.unsafe.asm.patch;
import org.objectweb.asm.tree.ClassNode;
public interface Patch {
void apply(ClassNode klazz);
}

View File

@ -0,0 +1,23 @@
{
"schemaVersion": 1,
"id": "libjf-unsafe-v0",
"version": "${version}",
"authors": [
"JFronny"
],
"contact": {
"website": "https://jfronny.gitlab.io",
"repo": "https://gitlab.com/jfmods/libjf"
},
"license": "MIT",
"environment": "*",
"languageAdapters": {
"libjf": "io.gitlab.jfronny.libjf.unsafe.JfLanguageAdapter"
},
"mixins": ["libjf-unsafe-v0.mixins.json"],
"custom": {
"modmenu": {
"parent": "libjf"
}
}
}

View File

@ -0,0 +1,14 @@
{
"required": true,
"minVersion": "0.8",
"package": "io.gitlab.jfronny.libjf.data.mixin",
"compatibilityLevel": "JAVA_16",
"plugin": "io.gitlab.jfronny.libjf.unsafe.MixinPlugin",
"mixins": [
],
"client": [
],
"injectors": {
"defaultRequire": 1
}
}

View File

@ -0,0 +1,45 @@
package io.gitlab.jfronny.libjf.unsafe.test;
import com.mojang.blaze3d.systems.RenderSystem;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.unsafe.asm.AsmConfig;
import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch;
import net.minecraft.client.main.Main;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import java.util.Set;
public class AsmTest implements AsmConfig {
@Override
public Set<String> skipClasses() {
return null;
}
@Override
public Set<Patch> getPatches() {
return Set.of(klazz -> {
if (klazz.name.equals("com/mojang/blaze3d/systems/RenderSystem")) {
for (MethodNode method : klazz.methods) {
if (method.name.equals("initRenderThread")) {
method.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getInternalName(AsmTest.class), "logSuccess", "()V"));
}
}
}
});
}
public static void logSuccess() {
LibJf.LOGGER.info("Successfully ASMd into RenderSystem\n" +
":::'###:::::'######::'##::::'##:'########:'########::'######::'########:\n" +
"::'## ##:::'##... ##: ###::'###:... ##..:: ##.....::'##... ##:... ##..::\n" +
":'##:. ##:: ##:::..:: ####'####:::: ##:::: ##::::::: ##:::..::::: ##::::\n" +
"'##:::. ##:. ######:: ## ### ##:::: ##:::: ######:::. ######::::: ##::::\n" +
" #########::..... ##: ##. #: ##:::: ##:::: ##...:::::..... ##:::: ##::::\n" +
" ##.... ##:'##::: ##: ##:.:: ##:::: ##:::: ##:::::::'##::: ##:::: ##::::\n" +
" ##:::: ##:. ######:: ##:::: ##:::: ##:::: ########:. ######::::: ##::::\n" +
"..:::::..:::......:::..:::::..:::::..:::::........:::......::::::..:::::");
}
}

View File

@ -0,0 +1,18 @@
package io.gitlab.jfronny.libjf.unsafe.test;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.unsafe.UltraEarlyInit;
public class UnsafeEntryTest implements UltraEarlyInit {
@Override
public void init() {
LibJf.LOGGER.info("Successfully executed code before that should be possible\n" +
"'||' '|' '|| . '||''''| '|| \n" +
" || | || .||. ... .. .... || . .... ... .. || .... ... \n" +
" || | || || ||' '' '' .|| ||''| '' .|| ||' '' || '|. | \n" +
" || | || || || .|' || || .|' || || || '|.| \n" +
" '|..' .||. '|.' .||. '|..'|' .||.....| '|..'|' .||. .||. '| \n" +
" .. | \n" +
" '' ");
}
}

View File

@ -0,0 +1,14 @@
{
"schemaVersion": 1,
"id": "libjf-unsafe-v0-testmod",
"version": "${version}",
"environment": "*",
"entrypoints": {
"libjf:asm": [
"io.gitlab.jfronny.libjf.unsafe.test.AsmTest"
],
"libjf:early": [
"io.gitlab.jfronny.libjf.unsafe.test.UnsafeEntryTest"
]
}
}

View File

@ -7,3 +7,12 @@ pluginManagement {
gradlePluginPortal()
}
}
rootProject.name = "libjf"
include 'libjf-base'
include 'libjf-config-v0'
include 'libjf-data-v0'
include 'libjf-data-manipulation-v0'
include 'libjf-unsafe-v0'

View File

@ -1,41 +0,0 @@
package io.gitlab.jfronny.libjf;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.gitlab.jfronny.libjf.config.Config;
import io.gitlab.jfronny.libjf.gson.HiddenAnnotationExclusionStrategy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
public class Libjf {
public static final String MOD_ID = "libjf";
public static final Logger LOGGER = LogManager.getLogger(MOD_ID);
public static final Gson GSON = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
.excludeFieldsWithModifiers(Modifier.PRIVATE)
.addSerializationExclusionStrategy(new HiddenAnnotationExclusionStrategy())
.setPrettyPrinting()
.create();
private static final Map<String, Config> configs = new HashMap<>();
@Deprecated
public static void registerConfig(String modId, Class<?> config) {
if (!isRegistered(config))
configs.put(modId, new Config(modId, config));
}
public static Map<String, Config> getConfigs() {
return ImmutableMap.copyOf(configs);
}
public static boolean isRegistered(Class<?> config) {
for (Config value : configs.values()) {
if (value.configClass.equals(config))
return true;
}
return false;
}
}

View File

@ -1,12 +0,0 @@
package io.gitlab.jfronny.libjf.data;
import net.fabricmc.fabric.api.tag.TagFactory;
import net.minecraft.item.Item;
import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier;
import io.gitlab.jfronny.libjf.Libjf;
public class Tags {
public static Tag<Item> SHULKER_ILLEGAL = TagFactory.ITEM.create(new Identifier(Libjf.MOD_ID, "shulker_boxes_illegal"));
public static Tag<Item> OVERPOWERED = TagFactory.ITEM.create(new Identifier(Libjf.MOD_ID, "overpowered"));
}

View File

@ -1,18 +0,0 @@
package io.gitlab.jfronny.libjf.entry;
import io.gitlab.jfronny.libjf.Libjf;
import io.gitlab.jfronny.libjf.config.JfConfig;
import net.fabricmc.loader.api.LanguageAdapter;
public class JfLanguageAdapter implements LanguageAdapter {
@Override
public native <T> T create(net.fabricmc.loader.api.ModContainer mod, String value, Class<T> type);
static {
DynamicEntry.execute(Libjf.MOD_ID + ":config", JfConfig.class, s -> {
Libjf.registerConfig(s.modId(), s.instance().getClass());
Libjf.LOGGER.info("Registering config for " + s.modId());
});
DynamicEntry.execute(Libjf.MOD_ID + ":early", UltraEarlyInit.class, s -> s.instance().init());
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -14,20 +14,6 @@
"license": "MIT",
"icon": "assets/libjf/icon.png",
"environment": "*",
"entrypoints": {
"client": [
"io.gitlab.jfronny.libjf.entry.LibjfClient"
],
"modmenu": [
"io.gitlab.jfronny.libjf.config.ModMenu"
]
},
"languageAdapters": {
"libjf": "io.gitlab.jfronny.libjf.entry.JfLanguageAdapter"
},
"mixins": [
"libjf.mixins.json"
],
"depends": {
"fabricloader": ">=0.11.3",
"minecraft": "*"

View File

@ -1,26 +0,0 @@
package io.gitlab.jfronny.libjf.test;
import io.gitlab.jfronny.libjf.data.UserResourceEvents;
import net.fabricmc.api.ModInitializer;
import net.minecraft.resource.AbstractFileResourcePack;
import java.io.FileNotFoundException;
public class Entrypoint implements ModInitializer {
@Override
public void onInitialize() {
// This should prevent resource packs from doing anything if my hooks are working and
UserResourceEvents.OPEN.register((type, id, previous, pack) -> {
if (TestMod.disablePacks && pack.getUnderlying() instanceof AbstractFileResourcePack) {
throw new FileNotFoundException();
}
return previous;
});
UserResourceEvents.CONTAINS.register((type, id, previous, pack) -> {
if (TestMod.disablePacks && pack.getUnderlying() instanceof AbstractFileResourcePack) {
return false;
}
return previous;
});
}
}

View File

@ -1,11 +0,0 @@
{
"libjf-testmod.jfconfig.title": "JfConfig example",
"libjf-testmod.jfconfig.disablePacks": "Disable resource packs",
"libjf-testmod.jfconfig.intTest": "Int Test",
"libjf-testmod.jfconfig.decimalTest": "Decimal Test",
"libjf-testmod.jfconfig.dieStr": "String Test",
"libjf-testmod.jfconfig.enumTest": "Enum Test",
"libjf-testmod.jfconfig.enumTest.tooltip": "Enum Test Tooltip",
"libjf-testmod.jfconfig.enum.Test.Test": "Test",
"libjf-testmod.jfconfig.enum.Test.ER": "ER"
}

View File

@ -1,14 +0,0 @@
{
"schemaVersion": 1,
"id": "libjf-testmod",
"version": "${version}",
"environment": "*",
"entrypoints": {
"libjf:config": [
"io.gitlab.jfronny.libjf.test.TestMod"
],
"main": [
"io.gitlab.jfronny.libjf.test.Entrypoint"
]
}
}