diff --git a/.gitignore b/.gitignore index a61caf3..57080fd 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,8 @@ run/ # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar + +.classpath +bin +.project +.settings diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 53c590a..68605b4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,21 +9,23 @@ before_script: build_test: stage: deploy script: - - gradle --build-cache assemble + - gradle --build-cache build publish -PpublicMaven -Ppipeline=$CI_PIPELINE_ID - cp build/libs/* ./ - - mv *-dev.jar tmp.zip + - rm *-maven.jar *-sources.jar *-sources-dev.jar + - mv *-dev.jar dev.zip - mv *.jar latest.jar - - mv tmp.zip latest-dev.jar + - mv dev.zip latest-dev.jar artifacts: paths: - build/libs - latest.jar - latest-dev.jar - only: - - master deploy: stage: deploy when: manual script: - - gradle --build-cache publishModrinth curseforge + - gradle --build-cache publish modrinth curseforge -PpublicMaven + only: + - master + diff --git a/build.gradle b/build.gradle index 7f1ec41..f446861 100644 --- a/build.gradle +++ b/build.gradle @@ -1,43 +1,300 @@ -apply from: "https://gitlab.com/-/snippets/2121059/raw/master/jfbase.gradle" +import com.modrinth.minotaur.TaskModrinthUpload -repositories { - maven { - name = 'TerraformersMC' - url = 'https://maven.terraformersmc.com/' +plugins { + id "java" + id "idea" + id "eclipse" + id "java-library" + 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" +} + +def ENV = System.getenv() +ext.isPublicMaven = project.hasProperty('publicMaven') + +static Node getOrCreateNode(Node node, String name) { + Node dependencies = null + for(Node n : node) { + if(name == n.name()) { + dependencies = n + break + } + } + if(dependencies == null) { + dependencies = node.appendNode(name) + } + return dependencies +} + +def moduleDependencies(project, List 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 = getOrCreateNode(asNode(), "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") + } + } + } + } } } +allprojects { + apply plugin: "java-library" + apply plugin: "maven-publish" + apply plugin: "fabric-loom" + + tasks.withType(JavaCompile).configureEach { + it.options.release = 16 + } + + group = "io.gitlab.jfronny.libjf" + version = "$project.mod_version" + (project.hasProperty('pipeline') ? "+" + project.getProperty('pipeline') : "") + + 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}" + + modRuntime modCompileOnly("com.terraformersmc:modmenu:2.0.14") + include modImplementation(fabricApi.module("fabric-tag-extensions-v0", "${project.fabric_version}")) + include modImplementation(fabricApi.module("fabric-resource-loader-v0", "${project.fabric_version}")) + } + + configurations { + dev + } + + loom { + shareRemapCaches = true + } + + repositories { + maven { + name = 'TerraformersMC' + url = 'https://maven.terraformersmc.com/' + } + mavenLocal() + } + + 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 + } + } + } + } + + setupRepositories(repositories) + } + + loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava) + + javadoc.enabled = false + + afterEvaluate { + genSources.enabled = false + unpickJar.enabled = 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 { + mavenJava(MavenPublication) { + artifact(remapMavenJar) { + builtBy remapMavenJar + } + + artifact(sourcesJar) { + builtBy remapSourcesJar + } + + pom.withXml { + def depsNode = getOrCreateNode(asNode(), "dependencies") + subprojects.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") + } + } + } + } + + setupRepositories(repositories) +} + +loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava) + +void setupRepositories(RepositoryHandler repositories) { + //repositories.mavenLocal() // uncomment for testing + def ENV = System.getenv() + if (ext.isPublicMaven) { + repositories.maven { + url = "https://gitlab.com/api/v4/projects/25805200/packages/maven" + name = "gitlab" + + credentials(HttpHeaderCredentials) { + name = "Job-Token" + value = ENV.CI_JOB_TOKEN + } + authentication { + header(HttpHeaderAuthentication) + } + } + } + repositories.mavenLocal() +} + +subprojects.each { remapJar.dependsOn("${it.path}:remapJar") } + sourceSets { - testmod { - compileClasspath += main.compileClasspath + main.output - runtimeClasspath += main.runtimeClasspath + main.output - } + testmod } +def devOnlyModules = [ + "libjf-devutil-v0" +] + 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" -} + if (!(it.name in devOnlyModules)) { + include it + } -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 it.sourceSets.testmod.output } } } + +task modrinth(type: TaskModrinthUpload, dependsOn: remapJar) { + onlyIf { + ENV.MODRINTH_API_TOKEN + } + + token = ENV.MODRINTH_API_TOKEN + projectId = "WKwQAwke" + versionNumber = version + versionName = "[${project.minecraft_version}] ${project.mod_version}" + uploadFile = remapJar + addGameVersion("${project.minecraft_version}") + addLoader('fabric') +} + +curseforge { + if (ENV.CURSEFORGE_API_TOKEN) { + apiKey = ENV.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 + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index dbd4a2b..ef93896 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,15 +4,10 @@ org.gradle.jvmargs=-Xmx1G # check these on https://fabricmc.net/versions.html minecraft_version=1.17.1 yarn_mappings=build.61 -loader_version=0.11.6 +loader_version=0.12.1 # Mod Properties -mod_version=1.2.3 +mod_version=2.0 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= +fabric_version=0.40.6+1.17 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c..7454180 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0f80bbf..ffed3a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0..1b6c787 100644 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/libjf-base/build.gradle b/libjf-base/build.gradle new file mode 100644 index 0000000..e52c95f --- /dev/null +++ b/libjf-base/build.gradle @@ -0,0 +1,4 @@ +archivesBaseName = "libjf-base" + +dependencies { +} \ No newline at end of file diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java new file mode 100644 index 0000000..7930594 --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java @@ -0,0 +1,25 @@ +package io.gitlab.jfronny.libjf; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import io.gitlab.jfronny.libjf.gson.HiddenAnnotationExclusionStrategy; +import net.fabricmc.loader.api.FabricLoader; +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(); + // Only ever set through the libjf-unsafe-v0 testmod or user code since it causes logspam + public static boolean DEV = false; +} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/ResourcePath.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/ResourcePath.java new file mode 100644 index 0000000..d7a31d8 --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/ResourcePath.java @@ -0,0 +1,39 @@ +package io.gitlab.jfronny.libjf; + +import net.minecraft.resource.ResourceType; +import net.minecraft.util.Identifier; + +public class ResourcePath { + private final ResourceType type; + private final Identifier id; + + public ResourcePath(ResourceType type, Identifier id) { + this.type = type; + this.id = id; + } + + public ResourcePath(String name) throws IllegalStateException { + String[] s1 = name.split("/", 3); + if (s1.length != 3) { + throw new IllegalStateException("Could not split path string into resource type and ID due to insufficient length: " + name); + } + type = switch (s1[0]) { + case "assets" -> ResourceType.CLIENT_RESOURCES; + case "data" -> ResourceType.SERVER_DATA; + default -> throw new IllegalStateException("Unexpected value for resource type: " + s1[0] + " in: " + name); + }; + id = new Identifier(s1[1], s1[2]); + } + + public Identifier getId() { + return id; + } + + public ResourceType getType() { + return type; + } + + public String getName() { + return String.format("%s/%s/%s", type.getDirectory(), id.getNamespace(), id.getPath()); + } +} diff --git a/src/main/java/io/gitlab/jfronny/libjf/gson/GsonHidden.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/GsonHidden.java similarity index 100% rename from src/main/java/io/gitlab/jfronny/libjf/gson/GsonHidden.java rename to libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/GsonHidden.java diff --git a/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java similarity index 81% rename from src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java rename to libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java index c29e331..ea8a31c 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java @@ -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; } diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/interfaces/ThrowingRunnable.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/interfaces/ThrowingRunnable.java new file mode 100644 index 0000000..c663e99 --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/interfaces/ThrowingRunnable.java @@ -0,0 +1,5 @@ +package io.gitlab.jfronny.libjf.interfaces; + +public interface ThrowingRunnable { + void run() throws TEx; +} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/interfaces/ThrowingSupplier.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/interfaces/ThrowingSupplier.java new file mode 100644 index 0000000..5210e0d --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/interfaces/ThrowingSupplier.java @@ -0,0 +1,5 @@ +package io.gitlab.jfronny.libjf.interfaces; + +public interface ThrowingSupplier { + T get() throws TEx; +} diff --git a/libjf-base/src/main/resources/fabric.mod.json b/libjf-base/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..953dd5a --- /dev/null +++ b/libjf-base/src/main/resources/fabric.mod.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "id": "libjf-base", + "name": "LibJF Base", + "version": "${version}", + "environment": "*", + "license": "MIT", + "contact": { + "website": "https://jfronny.gitlab.io", + "repo": "https://gitlab.com/jfmods/libjf" + }, + "authors": [ + "JFronny" + ], + "depends": { + "fabricloader": ">=0.12.0", + "minecraft": "*" + }, + "custom": { + "modmenu": { + "parent": "libjf", + "badges": ["library"] + } + } +} diff --git a/libjf-base/src/testmod/resources/fabric.mod.json b/libjf-base/src/testmod/resources/fabric.mod.json new file mode 100644 index 0000000..ce8a846 --- /dev/null +++ b/libjf-base/src/testmod/resources/fabric.mod.json @@ -0,0 +1,6 @@ +{ + "schemaVersion": 1, + "id": "libjf-base-testmod", + "version": "1.0", + "environment": "*" +} \ No newline at end of file diff --git a/libjf-config-v0/build.gradle b/libjf-config-v0/build.gradle new file mode 100644 index 0000000..5acc31e --- /dev/null +++ b/libjf-config-v0/build.gradle @@ -0,0 +1,5 @@ +archivesBaseName = "libjf-config-v0" + +dependencies { + moduleDependencies(project, ["libjf-base", "libjf-unsafe-v0"]) +} diff --git a/src/main/java/io/gitlab/jfronny/libjf/config/Entry.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/api/Entry.java similarity index 89% rename from src/main/java/io/gitlab/jfronny/libjf/config/Entry.java rename to libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/api/Entry.java index 5c7ee6a..9db52f0 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/config/Entry.java +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/api/Entry.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config; +package io.gitlab.jfronny.libjf.config.api; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/api/JfConfig.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/api/JfConfig.java new file mode 100644 index 0000000..861dc5c --- /dev/null +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/api/JfConfig.java @@ -0,0 +1,4 @@ +package io.gitlab.jfronny.libjf.config.api; + +public interface JfConfig { +} diff --git a/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/Config.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/Config.java new file mode 100644 index 0000000..59f564f --- /dev/null +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/Config.java @@ -0,0 +1,50 @@ +package io.gitlab.jfronny.libjf.config.impl; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.config.api.Entry; +import net.fabricmc.loader.api.FabricLoader; + +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/** Based on https://github.com/TeamMidnightDust/MidnightLib which is based on https://github.com/Minenash/TinyConfig + * Credits to TeamMidnightDust and Minenash */ + +public class Config { + public final List entries = new ArrayList<>(); + public Path path; + public final String modid; + public final Class configClass; + + public Config(String modid, Class config) { + this.modid = modid; + configClass = config; + path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json"); + + for (Field field : config.getFields()) { + EntryInfo info = new EntryInfo(); + info.field = field; + if (field.isAnnotationPresent(Entry.class)) + try { + info.defaultValue = field.get(null); + } catch (IllegalAccessException ignored) {} + entries.add(info); + } + try { + LibJf.GSON.fromJson(Files.newBufferedReader(path), config); } + catch (Exception e) { write(); } + } + + public void write() { + 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()); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigHolder.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigHolder.java new file mode 100644 index 0000000..7e9289d --- /dev/null +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/ConfigHolder.java @@ -0,0 +1,29 @@ +package io.gitlab.jfronny.libjf.config.impl; + +import com.google.common.collect.ImmutableMap; + +import java.util.HashMap; +import java.util.Map; + +public class ConfigHolder { + private ConfigHolder() { + } + private static final Map configs = new HashMap<>(); + + public static void registerConfig(String modId, Class config) { + if (!isRegistered(config)) + configs.put(modId, new Config(modId, config)); + } + + public static Map 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; + } +} diff --git a/src/main/java/io/gitlab/jfronny/libjf/config/EntryInfo.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/EntryInfo.java similarity index 90% rename from src/main/java/io/gitlab/jfronny/libjf/config/EntryInfo.java rename to libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/EntryInfo.java index 194de70..cf07d0c 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/config/EntryInfo.java +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/EntryInfo.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config; +package io.gitlab.jfronny.libjf.config.impl; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.text.Text; diff --git a/src/main/java/io/gitlab/jfronny/libjf/config/ModMenu.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/ModMenu.java similarity index 68% rename from src/main/java/io/gitlab/jfronny/libjf/config/ModMenu.java rename to libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/ModMenu.java index 2396275..3fbbfb9 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/config/ModMenu.java +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/ModMenu.java @@ -1,9 +1,9 @@ -package io.gitlab.jfronny.libjf.config; +package io.gitlab.jfronny.libjf.config.impl; 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.config.impl.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> getProvidedConfigScreenFactories() { Map> factories = new HashMap<>(); - for (Map.Entry entry : Libjf.getConfigs().entrySet()) { - if (!Libjf.MOD_ID.equals(entry.getKey())) + for (Map.Entry entry : ConfigHolder.getConfigs().entrySet()) { + if (!LibJf.MOD_ID.equals(entry.getKey())) factories.put(entry.getKey(), buildFactory(entry.getValue())); } return factories; diff --git a/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/entry/JfConfigClient.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/entry/JfConfigClient.java new file mode 100644 index 0000000..85febc8 --- /dev/null +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/entry/JfConfigClient.java @@ -0,0 +1,20 @@ +package io.gitlab.jfronny.libjf.config.impl.entry; + +import io.gitlab.jfronny.libjf.config.impl.Config; +import io.gitlab.jfronny.libjf.config.impl.ConfigHolder; +import io.gitlab.jfronny.libjf.config.impl.EntryInfo; +import io.gitlab.jfronny.libjf.config.api.Entry; +import io.gitlab.jfronny.libjf.config.impl.gui.EntryInfoWidgetBuilder; +import io.gitlab.jfronny.libjf.gson.GsonHidden; +import io.gitlab.jfronny.libjf.LibJf; +import net.fabricmc.api.ClientModInitializer; + +public class JfConfigClient implements ClientModInitializer { + @Override + public void onInitializeClient() { + for (Config config : ConfigHolder.getConfigs().values()) { + LibJf.LOGGER.info("Registring config UI for " + config.modid); + EntryInfoWidgetBuilder.initConfig(config); + } + } +} diff --git a/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/entry/JfConfigSafe.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/entry/JfConfigSafe.java new file mode 100644 index 0000000..dfff695 --- /dev/null +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/entry/JfConfigSafe.java @@ -0,0 +1,18 @@ +package io.gitlab.jfronny.libjf.config.impl.entry; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.config.impl.ConfigHolder; +import io.gitlab.jfronny.libjf.config.api.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 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()); + } + } +} diff --git a/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/entry/JfConfigUnsafe.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/entry/JfConfigUnsafe.java new file mode 100644 index 0000000..acf710b --- /dev/null +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/entry/JfConfigUnsafe.java @@ -0,0 +1,18 @@ +package io.gitlab.jfronny.libjf.config.impl.entry; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.config.impl.ConfigHolder; +import io.gitlab.jfronny.libjf.config.api.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()); + }); + LibJf.LOGGER.info("Finished LibJF config entrypoint"); + } +} diff --git a/src/main/java/io/gitlab/jfronny/libjf/config/gui/ButtonEntry.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/ButtonEntry.java similarity index 98% rename from src/main/java/io/gitlab/jfronny/libjf/config/gui/ButtonEntry.java rename to libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/ButtonEntry.java index 07ce2e8..ed78f8b 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/config/gui/ButtonEntry.java +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/ButtonEntry.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.gui; +package io.gitlab.jfronny.libjf.config.impl.gui; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; diff --git a/src/main/java/io/gitlab/jfronny/libjf/config/Config.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/EntryInfoWidgetBuilder.java similarity index 50% rename from src/main/java/io/gitlab/jfronny/libjf/config/Config.java rename to libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/EntryInfoWidgetBuilder.java index b6b9fd9..6598364 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/config/Config.java +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/EntryInfoWidgetBuilder.java @@ -1,77 +1,62 @@ -package io.gitlab.jfronny.libjf.config; +package io.gitlab.jfronny.libjf.config.impl.gui; -import io.gitlab.jfronny.libjf.Libjf; +import io.gitlab.jfronny.libjf.config.api.Entry; +import io.gitlab.jfronny.libjf.config.impl.Config; +import io.gitlab.jfronny.libjf.config.impl.EntryInfo; import io.gitlab.jfronny.libjf.gson.GsonHidden; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.gui.widget.*; -import net.minecraft.text.*; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; import net.minecraft.util.Formatting; -import java.lang.reflect.Field; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.List; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Pattern; -/** Based on https://github.com/TeamMidnightDust/MidnightLib which is based on https://github.com/Minenash/TinyConfig - * Credits to TeamMidnightDust and Minenash */ - -@SuppressWarnings("unchecked") -public class Config { +@Environment(EnvType.CLIENT) +public class EntryInfoWidgetBuilder { private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)"); private static final Pattern DECIMAL_ONLY = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)"); - public final List entries = new ArrayList<>(); - public Path path; - public final String modid; - public final Class configClass; - - public Config(String modid, Class config) { - this.modid = modid; - configClass = config; - path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json"); - - for (Field field : config.getFields()) { - EntryInfo info = new EntryInfo(); - info.field = field; - if (field.isAnnotationPresent(Entry.class)) + public static void initConfig(Config config) { + for (EntryInfo info : config.entries) { + if (info.field.isAnnotationPresent(Entry.class) || info.field.isAnnotationPresent(GsonHidden.class)) try { - info.defaultValue = field.get(null); - } catch (IllegalAccessException ignored) {} - entries.add(info); + initEntry(config, info); + } catch (Exception ignored) { + } } - try { - 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; + private static void initEntry(Config config, EntryInfo info) { + if (!(info.field.isAnnotationPresent(io.gitlab.jfronny.libjf.config.api.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.api.Entry e = info.field.getAnnotation(Entry.class); info.width = e != null ? e.width() : 0; if (e == null) return; - if (type == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, e.min(), e.max(), true); - else if (type == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(),false); - else if (type == String.class) textField(info, String::length, null, Math.min(e.min(),0), Math.max(e.max(),1),true); + if (type == int.class) textField(config, info, Integer::parseInt, INTEGER_ONLY, e.min(), e.max(), true); + else if (type == double.class) textField(config, info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(),false); + else if (type == String.class) textField(config, info, String::length, null, Math.min(e.min(),0), Math.max(e.max(),1),true); else if (type == boolean.class) { - Function func = value -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED); + Function func = value -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED); info.widget = new AbstractMap.SimpleEntry>(button -> { info.value = !(Boolean) info.value; button.setMessage(func.apply(info.value)); }, func); } else if (type.isEnum()) { List values = Arrays.asList(info.field.getType().getEnumConstants()); - Function func = value -> new TranslatableText(modid + ".jfconfig." + "enum." + type.getSimpleName() + "." + info.value.toString()); - info.widget = new AbstractMap.SimpleEntry>( button -> { + Function func = value -> new TranslatableText(config.modid + ".jfconfig." + "enum." + type.getSimpleName() + "." + info.value.toString()); + info.widget = new AbstractMap.SimpleEntry>(button -> { int index = values.indexOf(info.value) + 1; info.value = values.get(index >= values.size()? 0 : index); button.setMessage(func.apply(info.value)); @@ -85,7 +70,7 @@ public class Config { } } - private void textField(EntryInfo info, Function f, Pattern pattern, double min, double max, boolean cast) { + private static void textField(Config config, EntryInfo info, Function f, Pattern pattern, double min, double max, boolean cast) { boolean isNumber = pattern != null; info.widget = (BiFunction>) (t, b) -> s -> { s = s.trim(); @@ -107,7 +92,7 @@ public class Config { info.tempValue = s; t.setEditableColor(inLimits? 0xFFFFFFFF : 0xFFFF7777); info.inLimits = inLimits; - b.active = entries.stream().allMatch(e -> e.inLimits); + b.active = config.entries.stream().allMatch(e -> e.inLimits); if (inLimits) info.value = isNumber? value : s; @@ -115,14 +100,4 @@ public class Config { return true; }; } - - public void write() { - 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()); - } catch (Exception e) { - e.printStackTrace(); - } - } } diff --git a/src/main/java/io/gitlab/jfronny/libjf/config/gui/MidnightConfigListWidget.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/MidnightConfigListWidget.java similarity index 96% rename from src/main/java/io/gitlab/jfronny/libjf/config/gui/MidnightConfigListWidget.java rename to libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/MidnightConfigListWidget.java index b4e9f89..f49d278 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/config/gui/MidnightConfigListWidget.java +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/MidnightConfigListWidget.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.libjf.config.gui; +package io.gitlab.jfronny.libjf.config.impl.gui; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; diff --git a/src/main/java/io/gitlab/jfronny/libjf/config/gui/TinyConfigScreen.java b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/TinyConfigScreen.java similarity index 93% rename from src/main/java/io/gitlab/jfronny/libjf/config/gui/TinyConfigScreen.java rename to libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/TinyConfigScreen.java index fcc4029..8be13c8 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/config/gui/TinyConfigScreen.java +++ b/libjf-config-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/gui/TinyConfigScreen.java @@ -1,14 +1,11 @@ -package io.gitlab.jfronny.libjf.config.gui; +package io.gitlab.jfronny.libjf.config.impl.gui; -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.EntryInfo; -import io.gitlab.jfronny.libjf.config.gui.ButtonEntry; -import io.gitlab.jfronny.libjf.config.gui.MidnightConfigListWidget; +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.config.impl.Config; +import io.gitlab.jfronny.libjf.config.api.Entry; +import io.gitlab.jfronny.libjf.config.impl.EntryInfo; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ScreenTexts; import net.minecraft.client.gui.widget.ButtonWidget; @@ -57,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) { diff --git a/libjf-config-v0/src/main/resources/fabric.mod.json b/libjf-config-v0/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..c4bb4f0 --- /dev/null +++ b/libjf-config-v0/src/main/resources/fabric.mod.json @@ -0,0 +1,41 @@ +{ + "schemaVersion": 1, + "id": "libjf-config-v0", + "name": "LibJF Config", + "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.impl.ModMenu" + ], + "client": [ + "io.gitlab.jfronny.libjf.config.impl.entry.JfConfigClient" + ], + "libjf:preEarly": [ + "io.gitlab.jfronny.libjf.config.impl.entry.JfConfigUnsafe" + ], + "preLaunch": [ + "io.gitlab.jfronny.libjf.config.impl.entry.JfConfigSafe" + ] + }, + "depends": { + "fabricloader": ">=0.12.0", + "minecraft": "*", + "libjf-base": "${version}", + "libjf-unsafe-v0": "${version}" + }, + "custom": { + "modmenu": { + "badges": ["library"], + "parent": "libjf" + } + } +} diff --git a/src/testmod/java/io/gitlab/jfronny/libjf/test/TestMod.java b/libjf-config-v0/src/testmod/java/io/gitlab/jfronny/libjf/config/test/TestConfig.java similarity index 51% rename from src/testmod/java/io/gitlab/jfronny/libjf/test/TestMod.java rename to libjf-config-v0/src/testmod/java/io/gitlab/jfronny/libjf/config/test/TestConfig.java index 93b8547..6fcfbab 100644 --- a/src/testmod/java/io/gitlab/jfronny/libjf/test/TestMod.java +++ b/libjf-config-v0/src/testmod/java/io/gitlab/jfronny/libjf/config/test/TestConfig.java @@ -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.api.JfConfig; +import io.gitlab.jfronny.libjf.config.api.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 diff --git a/libjf-config-v0/src/testmod/resources/assets/libjf-config-v0-testmod/lang/en_us.json b/libjf-config-v0/src/testmod/resources/assets/libjf-config-v0-testmod/lang/en_us.json new file mode 100644 index 0000000..b46a697 --- /dev/null +++ b/libjf-config-v0/src/testmod/resources/assets/libjf-config-v0-testmod/lang/en_us.json @@ -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" +} \ No newline at end of file diff --git a/libjf-config-v0/src/testmod/resources/fabric.mod.json b/libjf-config-v0/src/testmod/resources/fabric.mod.json new file mode 100644 index 0000000..a2624bd --- /dev/null +++ b/libjf-config-v0/src/testmod/resources/fabric.mod.json @@ -0,0 +1,11 @@ +{ + "schemaVersion": 1, + "id": "libjf-config-v0-testmod", + "version": "1.0", + "environment": "*", + "entrypoints": { + "libjf:config": [ + "io.gitlab.jfronny.libjf.config.test.TestConfig" + ] + } +} \ No newline at end of file diff --git a/libjf-data-manipulation-v0/build.gradle b/libjf-data-manipulation-v0/build.gradle new file mode 100644 index 0000000..4fee211 --- /dev/null +++ b/libjf-data-manipulation-v0/build.gradle @@ -0,0 +1,5 @@ +archivesBaseName = "libjf-data-manipulation-v0" + +dependencies { + moduleDependencies(project, ["libjf-base", "libjf-unsafe-v0"]) +} \ No newline at end of file diff --git a/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/api/RecipeUtil.java b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/api/RecipeUtil.java new file mode 100644 index 0000000..40f7c4b --- /dev/null +++ b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/api/RecipeUtil.java @@ -0,0 +1,35 @@ +package io.gitlab.jfronny.libjf.data.manipulation.api; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; + +import java.util.HashSet; +import java.util.Set; + +@SuppressWarnings("unused") +public class RecipeUtil { + private static final Set REMOVAL_BY_ID = new HashSet<>(); + private static final Set RECIPES_FOR_REMOVAL = new HashSet<>(); + + public static void removeRecipe(Identifier identifier) { + REMOVAL_BY_ID.add(identifier); + } + + public static void removeRecipeFor(Item product) { + RECIPES_FOR_REMOVAL.add(product.getDefaultStack()); + } + + public static boolean isIdBlocked(Identifier identifier) { + return REMOVAL_BY_ID.contains(identifier); + } + + public static boolean isOutputBlocked(ItemStack product) { + for (ItemStack stack : RECIPES_FOR_REMOVAL) { + if (product.isItemEqual(stack)) { + return true; + } + } + return false; + } +} 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 new file mode 100644 index 0000000..d210515 --- /dev/null +++ b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/api/UserResourceEvents.java @@ -0,0 +1,84 @@ +package io.gitlab.jfronny.libjf.data.manipulation.api; + +import io.gitlab.jfronny.libjf.data.manipulation.impl.ResourcePackHook; +import io.gitlab.jfronny.libjf.interfaces.ThrowingRunnable; +import io.gitlab.jfronny.libjf.interfaces.ThrowingSupplier; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.ResourceType; +import net.minecraft.util.Identifier; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.function.Predicate; + +public class UserResourceEvents { + public static TVal disable(ThrowingSupplier then) throws TEx { + try { + ResourcePackHook.setDisabled(true); + return then.get(); + } + finally { + ResourcePackHook.setDisabled(false); + } + } + + public static void disable(ThrowingRunnable then) throws TEx { + try { + ResourcePackHook.setDisabled(true); + then.run(); + } finally { + ResourcePackHook.setDisabled(false); + } + } + + public static final Event CONTAINS = EventFactory.createArrayBacked(Contains.class, + (listeners) -> (type, id, previous, pack) -> { + for (Contains listener : listeners) { + previous = listener.contains(type, id, previous, pack); + } + return previous; + }); + + public static final Event FIND_RESOURCE = EventFactory.createArrayBacked(FindResource.class, + (listeners) -> ((type, namespace, prefix, maxDepth, pathFilter, previous, pack) -> { + for (FindResource listener : listeners) { + previous = listener.findResources(type, namespace, prefix, maxDepth, pathFilter, previous, pack); + } + return previous; + })); + + public static final Event OPEN = EventFactory.createArrayBacked(Open.class, + (listeners) -> ((type, id, previous, pack) -> { + for (Open listener : listeners) { + previous = listener.open(type, id, previous, pack); + } + return previous; + })); + + public static final Event OPEN_ROOT = EventFactory.createArrayBacked(OpenRoot.class, + (listeners) -> ((fileName, previous, pack) -> { + for (OpenRoot listener : listeners) { + previous = listener.openRoot(fileName, previous, pack); + } + return previous; + })); + + public interface Contains { + boolean contains(ResourceType type, Identifier id, boolean previous, ResourcePack pack); + } + + public interface FindResource { + Collection findResources(ResourceType type, String namespace, String prefix, int maxDepth, Predicate pathFilter, Collection previous, ResourcePack pack); + } + + public interface Open { + InputStream open(ResourceType type, Identifier id, InputStream previous, ResourcePack pack) throws IOException; + } + + public interface OpenRoot { + InputStream openRoot(String fileName, InputStream previous, ResourcePack pack) throws IOException; + } +} diff --git a/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHook.java b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHook.java new file mode 100644 index 0000000..a6872c6 --- /dev/null +++ b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHook.java @@ -0,0 +1,66 @@ +package io.gitlab.jfronny.libjf.data.manipulation.impl; + +import io.gitlab.jfronny.libjf.ResourcePath; +import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents; +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.ResourceType; +import net.minecraft.util.Identifier; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.function.Predicate; + +@SuppressWarnings("unused") +public class ResourcePackHook { + private static boolean disabled = false; + + public static void setDisabled(boolean disabled) { + ResourcePackHook.disabled = disabled; + } + + public static boolean isDisabled() { + return disabled; + } + + public static boolean hookContains(boolean value, ResourcePack pack, ResourceType type, Identifier id) { + return disabled ? value : UserResourceEvents.CONTAINS.invoker().contains(type, id, value, pack); + } + public static InputStream hookOpen(InputStream value, ResourcePack pack, ResourceType type, Identifier id) throws IOException { + if (disabled) return value; + InputStream is = UserResourceEvents.OPEN.invoker().open(type, id, value, pack); + if (is == null) + throw new FileNotFoundException(new ResourcePath(type, id).getName() + "CN"); + return is; + } + public static InputStream hookOpenEx(IOException ex, ResourcePack pack, ResourceType type, Identifier id) throws IOException { + if (disabled) throw ex; + try { + return hookOpen(null, pack, type, id); + } + catch (Throwable t) { + throw ex; + } + } + public static Collection hookFindResources(Collection value, ResourcePack pack, ResourceType type, String namespace, String prefix, int maxDepth, Predicate pathFilter) { + return disabled ? value : UserResourceEvents.FIND_RESOURCE.invoker().findResources(type, namespace, prefix, maxDepth, pathFilter, value, pack); + } + public static InputStream hookOpenRoot(InputStream value, ResourcePack pack, String fileName) throws IOException { + if (disabled) return value; + InputStream is = value; + is = UserResourceEvents.OPEN_ROOT.invoker().openRoot(fileName, is, pack); + if (is == null) + throw new FileNotFoundException(fileName); + return is; + } + public static InputStream hookOpenRootEx(IOException ex, ResourcePack pack, String fileName) throws IOException { + if (disabled) throw ex; + try { + return hookOpenRoot(null, pack, fileName); + } + catch (Throwable t) { + throw ex; + } + } +} diff --git a/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHookPatch.java b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHookPatch.java new file mode 100644 index 0000000..ef28617 --- /dev/null +++ b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/impl/ResourcePackHookPatch.java @@ -0,0 +1,58 @@ +package io.gitlab.jfronny.libjf.data.manipulation.impl; + +import io.gitlab.jfronny.libjf.unsafe.asm.AsmConfig; +import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch; +import io.gitlab.jfronny.libjf.unsafe.asm.patch.PatchUtil; +import io.gitlab.jfronny.libjf.unsafe.asm.patch.modification.MethodModificationPatch; +import io.gitlab.jfronny.libjf.unsafe.asm.patch.targeting.InterfaceImplTargetPatch; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.MethodNode; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Set; + +public class ResourcePackHookPatch implements AsmConfig { + private static final String TARGET_CLASS_INTERMEDIARY = "net.minecraft.class_3262"; + private static final String HOOK_IMPLEMENTATION = Type.getInternalName(ResourcePackHook.class); + @Override + public Set skipClasses() { + return Set.of(PatchUtil.getRemapped(TARGET_CLASS_INTERMEDIARY), + "io.gitlab.jfronny.libjf.data.WrappedPack", //TODO remove for 1.18 + "io.gitlab.jfronny.libjf.data.wrappedPackImpl.WrappedResourcePack", + "io.gitlab.jfronny.libjf.data.wrappedPackImpl.SafeWrappedResourcePack"); + } + + @Override + public Set getPatches() { + // https://maven.fabricmc.net/docs/yarn-21w38a+build.9/net/minecraft/resource/ResourcePack.html + return Set.of(new InterfaceImplTargetPatch(TARGET_CLASS_INTERMEDIARY, new MethodModificationPatch(TARGET_CLASS_INTERMEDIARY, Set.of( + // open root + new MethodModificationPatch.MethodDescriptorPatch("method_14410", "(Ljava/lang/String;)Ljava/io/InputStream;", method -> { + catchEx(method, "hookOpenRootEx", new String[]{"java/lang/String"}); + hookReturn(method, "hookOpenRoot", "Ljava/io/InputStream;", new String[]{"java/lang/String"}); + }), + // open + new MethodModificationPatch.MethodDescriptorPatch("method_14405", "(Lnet/minecraft/class_3264;Lnet/minecraft/class_2960;)Ljava/io/InputStream;", method -> { + catchEx(method, "hookOpenEx", new String[]{"net/minecraft/class_3264", "net/minecraft/class_2960"}); + hookReturn(method, "hookOpen", "Ljava/io/InputStream;", new String[]{"net/minecraft/class_3264", "net/minecraft/class_2960"}); + }), + // find resource + new MethodModificationPatch.MethodDescriptorPatch("method_14408", "(Lnet/minecraft/class_3264;Ljava/lang/String;Ljava/lang/String;ILjava/util/function/Predicate;)Ljava/util/Collection;", method -> { + hookReturn(method, "hookFindResources", "Ljava/util/Collection;", new String[]{"net/minecraft/class_3264", "java/lang/String", "java/lang/String", "I", "java/util/function/Predicate"}); + }), + // contains + new MethodModificationPatch.MethodDescriptorPatch("method_14411", "(Lnet/minecraft/class_3264;Lnet/minecraft/class_2960;)Z", method -> { + hookReturn(method, "hookContains", "Z", new String[]{"net/minecraft/class_3264", "net/minecraft/class_2960"}); + }) + )))); + } + + private void hookReturn(MethodNode method, String targetMethod, String targetType, String[] extraParamTypes) { + PatchUtil.redirectReturn(method, TARGET_CLASS_INTERMEDIARY, HOOK_IMPLEMENTATION, targetMethod, targetType, extraParamTypes); + } + + private void catchEx(MethodNode method, String targetMethod, String[] extraParamTypes) { + PatchUtil.redirectExceptions(method, TARGET_CLASS_INTERMEDIARY, HOOK_IMPLEMENTATION, Type.getInternalName(IOException.class), Type.getInternalName(InputStream.class), targetMethod, extraParamTypes); + } +} diff --git a/src/main/java/io/gitlab/jfronny/libjf/mixin/RecipeManagerMixin.java b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/mixin/RecipeManagerMixin.java similarity index 56% rename from src/main/java/io/gitlab/jfronny/libjf/mixin/RecipeManagerMixin.java rename to libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/mixin/RecipeManagerMixin.java index 43f7ba3..492a8e6 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/mixin/RecipeManagerMixin.java +++ b/libjf-data-manipulation-v0/src/main/java/io/gitlab/jfronny/libjf/data/manipulation/mixin/RecipeManagerMixin.java @@ -1,10 +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 net.minecraft.item.ItemStack; +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.data.manipulation.api.RecipeUtil; import net.minecraft.recipe.Recipe; import net.minecraft.recipe.RecipeManager; import net.minecraft.util.Identifier; @@ -19,15 +18,15 @@ import java.util.Map; @Mixin(RecipeManager.class) public class RecipeManagerMixin { - @ModifyVariable(method = "apply", at = @At(value = "INVOKE_ASSIGN", target = "Ljava/util/Set;iterator()Ljava/util/Iterator;", ordinal = 0, remap = false)) + @ModifyVariable(method = "apply(Ljava/util/Map;Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/profiler/Profiler;)V", at = @At(value = "INVOKE_ASSIGN", target = "Ljava/util/Set;iterator()Ljava/util/Iterator;", ordinal = 0, remap = false)) private Iterator> filterIterator(Iterator> iterator) { ArrayList> replacement = new ArrayList<>(); while(iterator.hasNext()) { Map.Entry cur = iterator.next(); Identifier recipeId = cur.getKey(); - if (RecipeUtil.getIdentifiersForRemoval().contains(recipeId.toString())) { - Libjf.LOGGER.info("Blocking recipe by identifier: " + recipeId); + if (RecipeUtil.isIdBlocked(recipeId)) { + LibJf.LOGGER.info("Blocking recipe by identifier: " + recipeId); } else { replacement.add(cur); } @@ -36,16 +35,14 @@ public class RecipeManagerMixin { return replacement.iterator(); } - @Redirect(method = "apply", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableMap$Builder;put(Ljava/lang/Object;Ljava/lang/Object;)Lcom/google/common/collect/ImmutableMap$Builder;", remap = false)) + @Redirect(method = "apply(Ljava/util/Map;Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/profiler/Profiler;)V", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableMap$Builder;put(Ljava/lang/Object;Ljava/lang/Object;)Lcom/google/common/collect/ImmutableMap$Builder;", remap = false)) private ImmutableMap.Builder> onPutRecipe(ImmutableMap.Builder> builder, Object key, Object value) { Identifier id = (Identifier) key; Recipe recipe = (Recipe) value; - - for (ItemStack stack : RecipeUtil.getRecipesForRemoval()) { - if (recipe.getOutput().isItemEqual(stack)) { - Libjf.LOGGER.info("Blocked recipe by predicate: " + recipe.getId()); - return builder; - } + + if (RecipeUtil.isOutputBlocked(recipe.getOutput())) { + LibJf.LOGGER.info("Blocked recipe by predicate: " + recipe.getId()); + return builder; } return builder.put(id, recipe); diff --git a/libjf-data-manipulation-v0/src/main/resources/fabric.mod.json b/libjf-data-manipulation-v0/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..9782ad7 --- /dev/null +++ b/libjf-data-manipulation-v0/src/main/resources/fabric.mod.json @@ -0,0 +1,33 @@ +{ + "schemaVersion": 1, + "id": "libjf-data-manipulation-v0", + "name": "LibJF Data Manipulation", + "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"], + "entrypoints": { + "libjf:asm": [ + "io.gitlab.jfronny.libjf.data.manipulation.impl.ResourcePackHookPatch" + ] + }, + "depends": { + "fabricloader": ">=0.12.0", + "minecraft": "*", + "libjf-base": "${version}", + "libjf-unsafe-v0": "${version}" + }, + "custom": { + "modmenu": { + "parent": "libjf", + "badges": ["library"] + } + } +} diff --git a/libjf-data-manipulation-v0/src/main/resources/libjf-data-manipulation-v0.mixins.json b/libjf-data-manipulation-v0/src/main/resources/libjf-data-manipulation-v0.mixins.json new file mode 100644 index 0000000..713d453 --- /dev/null +++ b/libjf-data-manipulation-v0/src/main/resources/libjf-data-manipulation-v0.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.gitlab.jfronny.libjf.data.manipulation.mixin", + "compatibilityLevel": "JAVA_16", + "mixins": [ + "RecipeManagerMixin" + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libjf-data-manipulation-v0/src/testmod/java/io/gitlab/jfronny/libjf/data/manipulation/test/TestEntrypoint.java b/libjf-data-manipulation-v0/src/testmod/java/io/gitlab/jfronny/libjf/data/manipulation/test/TestEntrypoint.java new file mode 100644 index 0000000..11e994f --- /dev/null +++ b/libjf-data-manipulation-v0/src/testmod/java/io/gitlab/jfronny/libjf/data/manipulation/test/TestEntrypoint.java @@ -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.api.RecipeUtil; +import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents; +import net.fabricmc.api.ModInitializer; +import net.minecraft.item.Items; +import net.minecraft.resource.DirectoryResourcePack; + +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 instanceof DirectoryResourcePack) { + LibJf.LOGGER.info(pack.getName() + " opened " + type.name() + "/" + id.toString()); + } + return previous; + }); + UserResourceEvents.CONTAINS.register((type, id, previous, pack) -> { + if (pack instanceof DirectoryResourcePack) { + return false; + } + return previous; + }); + RecipeUtil.removeRecipeFor(Items.DIAMOND_SWORD); + } +} \ No newline at end of file diff --git a/libjf-data-manipulation-v0/src/testmod/resources/fabric.mod.json b/libjf-data-manipulation-v0/src/testmod/resources/fabric.mod.json new file mode 100644 index 0000000..8800c42 --- /dev/null +++ b/libjf-data-manipulation-v0/src/testmod/resources/fabric.mod.json @@ -0,0 +1,11 @@ +{ + "schemaVersion": 1, + "id": "libjf-data-manipulation-v0-testmod", + "version": "1.0", + "environment": "*", + "entrypoints": { + "main": [ + "io.gitlab.jfronny.libjf.data.manipulation.test.TestEntrypoint" + ] + } +} \ No newline at end of file diff --git a/libjf-data-v0/build.gradle b/libjf-data-v0/build.gradle new file mode 100644 index 0000000..0e43607 --- /dev/null +++ b/libjf-data-v0/build.gradle @@ -0,0 +1,5 @@ +archivesBaseName = "libjf-data-v0" + +dependencies { + moduleDependencies(project, ["libjf-base"]) +} \ No newline at end of file diff --git a/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/Tags.java b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/Tags.java new file mode 100644 index 0000000..e2cccdd --- /dev/null +++ b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/Tags.java @@ -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 SHULKER_ILLEGAL = TagFactory.ITEM.create(new Identifier(LibJf.MOD_ID, "shulker_boxes_illegal")); + public static final Tag OVERPOWERED = TagFactory.ITEM.create(new Identifier(LibJf.MOD_ID, "overpowered")); +} diff --git a/src/main/java/io/gitlab/jfronny/libjf/mixin/EntityMixin.java b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/EntityMixin.java similarity index 97% rename from src/main/java/io/gitlab/jfronny/libjf/mixin/EntityMixin.java rename to libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/EntityMixin.java index b4f82e7..4b79dbd 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/mixin/EntityMixin.java +++ b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/EntityMixin.java @@ -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; diff --git a/src/main/java/io/gitlab/jfronny/libjf/mixin/ShulkerBoxBlockEntityMixin.java b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/ShulkerBoxBlockEntityMixin.java similarity index 95% rename from src/main/java/io/gitlab/jfronny/libjf/mixin/ShulkerBoxBlockEntityMixin.java rename to libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/ShulkerBoxBlockEntityMixin.java index 6933be1..708c1cb 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/mixin/ShulkerBoxBlockEntityMixin.java +++ b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/ShulkerBoxBlockEntityMixin.java @@ -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; diff --git a/src/main/java/io/gitlab/jfronny/libjf/mixin/ShulkerBoxSlotMixin.java b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/ShulkerBoxSlotMixin.java similarity index 94% rename from src/main/java/io/gitlab/jfronny/libjf/mixin/ShulkerBoxSlotMixin.java rename to libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/ShulkerBoxSlotMixin.java index 6eafbfa..c1bd51a 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/mixin/ShulkerBoxSlotMixin.java +++ b/libjf-data-v0/src/main/java/io/gitlab/jfronny/libjf/data/mixin/ShulkerBoxSlotMixin.java @@ -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; diff --git a/src/main/resources/data/libjf/tags/items/overpowered.json b/libjf-data-v0/src/main/resources/data/libjf/tags/items/overpowered.json similarity index 100% rename from src/main/resources/data/libjf/tags/items/overpowered.json rename to libjf-data-v0/src/main/resources/data/libjf/tags/items/overpowered.json diff --git a/src/main/resources/data/libjf/tags/items/shulker_boxes_illegal.json b/libjf-data-v0/src/main/resources/data/libjf/tags/items/shulker_boxes_illegal.json similarity index 100% rename from src/main/resources/data/libjf/tags/items/shulker_boxes_illegal.json rename to libjf-data-v0/src/main/resources/data/libjf/tags/items/shulker_boxes_illegal.json diff --git a/libjf-data-v0/src/main/resources/fabric.mod.json b/libjf-data-v0/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..c73828e --- /dev/null +++ b/libjf-data-v0/src/main/resources/fabric.mod.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": 1, + "id": "libjf-data-v0", + "name": "LibJF Data", + "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"], + "depends": { + "fabricloader": ">=0.12.0", + "minecraft": "*", + "libjf-base": "${version}" + }, + "custom": { + "modmenu": { + "parent": "libjf", + "badges": ["library"] + } + } +} diff --git a/src/main/resources/libjf.mixins.json b/libjf-data-v0/src/main/resources/libjf-data-v0.mixins.json similarity index 68% rename from src/main/resources/libjf.mixins.json rename to libjf-data-v0/src/main/resources/libjf-data-v0.mixins.json index e028685..3416771 100644 --- a/src/main/resources/libjf.mixins.json +++ b/libjf-data-v0/src/main/resources/libjf-data-v0.mixins.json @@ -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" ], diff --git a/src/testmod/resources/data/libjf/tags/items/overpowered.json b/libjf-data-v0/src/testmod/resources/data/libjf/tags/items/overpowered.json similarity index 100% rename from src/testmod/resources/data/libjf/tags/items/overpowered.json rename to libjf-data-v0/src/testmod/resources/data/libjf/tags/items/overpowered.json diff --git a/libjf-data-v0/src/testmod/resources/data/libjf/tags/items/shulker_boxes_illegal.json b/libjf-data-v0/src/testmod/resources/data/libjf/tags/items/shulker_boxes_illegal.json new file mode 100644 index 0000000..fa884aa --- /dev/null +++ b/libjf-data-v0/src/testmod/resources/data/libjf/tags/items/shulker_boxes_illegal.json @@ -0,0 +1,9 @@ +{ + "replace": false, + "values": [ + "minecraft:netherite_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_boots" + ] +} diff --git a/libjf-data-v0/src/testmod/resources/fabric.mod.json b/libjf-data-v0/src/testmod/resources/fabric.mod.json new file mode 100644 index 0000000..fe2244b --- /dev/null +++ b/libjf-data-v0/src/testmod/resources/fabric.mod.json @@ -0,0 +1,6 @@ +{ + "schemaVersion": 1, + "id": "libjf-data-v0-testmod", + "version": "1.0", + "environment": "*" +} \ No newline at end of file diff --git a/libjf-devutil-v0/build.gradle b/libjf-devutil-v0/build.gradle new file mode 100644 index 0000000..aebe84c --- /dev/null +++ b/libjf-devutil-v0/build.gradle @@ -0,0 +1,5 @@ +archivesBaseName = "libjf-devutil-v0" + +dependencies { + moduleDependencies(project, ["libjf-base"]) +} \ No newline at end of file diff --git a/libjf-devutil-v0/src/main/java/io/gitlab/jfronny/libjf/devutil/DevUtilMain.java b/libjf-devutil-v0/src/main/java/io/gitlab/jfronny/libjf/devutil/DevUtilMain.java new file mode 100644 index 0000000..c2693ec --- /dev/null +++ b/libjf-devutil-v0/src/main/java/io/gitlab/jfronny/libjf/devutil/DevUtilMain.java @@ -0,0 +1,11 @@ +package io.gitlab.jfronny.libjf.devutil; + +import net.fabricmc.api.ModInitializer; +import net.minecraft.SharedConstants; + +public class DevUtilMain implements ModInitializer { + @Override + public void onInitialize() { + SharedConstants.isDevelopment = true; + } +} diff --git a/libjf-devutil-v0/src/main/java/io/gitlab/jfronny/libjf/devutil/NoOpUserApi.java b/libjf-devutil-v0/src/main/java/io/gitlab/jfronny/libjf/devutil/NoOpUserApi.java new file mode 100644 index 0000000..b84b0f1 --- /dev/null +++ b/libjf-devutil-v0/src/main/java/io/gitlab/jfronny/libjf/devutil/NoOpUserApi.java @@ -0,0 +1,111 @@ +package io.gitlab.jfronny.libjf.devutil; + +import com.mojang.authlib.minecraft.TelemetryEvent; +import com.mojang.authlib.minecraft.TelemetryPropertyContainer; +import com.mojang.authlib.minecraft.TelemetrySession; +import com.mojang.authlib.minecraft.UserApiService; + +import java.util.UUID; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +public class NoOpUserApi implements UserApiService { + @Override + public boolean serversAllowed() { + return true; + } + + @Override + public boolean realmsAllowed() { + return false; + } + + @Override + public boolean chatAllowed() { + return true; + } + + @Override + public boolean telemetryAllowed() { + return false; + } + + @Override + public boolean isBlockedPlayer(UUID playerID) { + return false; + } + + @Override + public void refreshBlockList() { + } + + @Override + public TelemetrySession newTelemetrySession(Executor executor) { + return new TelemetrySession() { + @Override + public boolean isEnabled() { + return false; + } + + @Override + public TelemetryPropertyContainer globalProperties() { + return new TelemetryPropertyContainer() { + @Override + public void addProperty(String id, String value) { + // ignored + } + + @Override + public void addProperty(String id, int value) { + // ignored + } + + @Override + public void addProperty(String id, boolean value) { + // ignored + } + + @Override + public void addNullProperty(String id) { + // ignored + } + }; + } + + @Override + public void eventSetupFunction(Consumer eventSetupFunction) { + // ignored + } + + @Override + public TelemetryEvent createNewEvent(String type) { + return new TelemetryEvent() { + @Override + public void send() { + // ignored + } + + @Override + public void addProperty(String id, String value) { + // ignored + } + + @Override + public void addProperty(String id, int value) { + // ignored + } + + @Override + public void addProperty(String id, boolean value) { + // ignored + } + + @Override + public void addNullProperty(String id) { + // ignored + } + }; + } + }; + } +} diff --git a/libjf-devutil-v0/src/main/java/io/gitlab/jfronny/libjf/devutil/mixin/MinecraftClientMixin.java b/libjf-devutil-v0/src/main/java/io/gitlab/jfronny/libjf/devutil/mixin/MinecraftClientMixin.java new file mode 100644 index 0000000..7a6a47f --- /dev/null +++ b/libjf-devutil-v0/src/main/java/io/gitlab/jfronny/libjf/devutil/mixin/MinecraftClientMixin.java @@ -0,0 +1,21 @@ +package io.gitlab.jfronny.libjf.devutil.mixin; + +import com.mojang.authlib.minecraft.UserApiService; +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; +import io.gitlab.jfronny.libjf.devutil.NoOpUserApi; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.RunArgs; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(MinecraftClient.class) +public class MinecraftClientMixin { + /** + * @author JFronny + * @reason The social interactions service will not work in dev envs and only produces log spam + */ + @Overwrite + private UserApiService createUserApiService(YggdrasilAuthenticationService yggdrasilAuthenticationService, RunArgs runArgs) { + return new NoOpUserApi(); + } +} diff --git a/libjf-devutil-v0/src/main/resources/fabric.mod.json b/libjf-devutil-v0/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..6d1ce47 --- /dev/null +++ b/libjf-devutil-v0/src/main/resources/fabric.mod.json @@ -0,0 +1,32 @@ +{ + "schemaVersion": 1, + "id": "libjf-devutil-v0", + "name": "LibJF Development Util", + "version": "${version}", + "authors": [ + "JFronny" + ], + "contact": { + "website": "https://jfronny.gitlab.io", + "repo": "https://gitlab.com/jfmods/libjf" + }, + "license": "MIT", + "environment": "*", + "entrypoints": { + "main": [ + "io.gitlab.jfronny.libjf.devutil.DevUtilMain" + ] + }, + "mixins": ["libjf-devutil-v0.mixins.json"], + "depends": { + "fabricloader": ">=0.12.0", + "minecraft": "*", + "libjf-base": "${version}" + }, + "custom": { + "modmenu": { + "parent": "libjf", + "badges": ["library"] + } + } +} diff --git a/libjf-devutil-v0/src/main/resources/libjf-devutil-v0.mixins.json b/libjf-devutil-v0/src/main/resources/libjf-devutil-v0.mixins.json new file mode 100644 index 0000000..134904b --- /dev/null +++ b/libjf-devutil-v0/src/main/resources/libjf-devutil-v0.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.gitlab.jfronny.libjf.devutil.mixin", + "compatibilityLevel": "JAVA_16", + "mixins": [ + "MinecraftClientMixin" + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libjf-unsafe-v0/build.gradle b/libjf-unsafe-v0/build.gradle new file mode 100644 index 0000000..d7fbf9b --- /dev/null +++ b/libjf-unsafe-v0/build.gradle @@ -0,0 +1,5 @@ +archivesBaseName = "libjf-unsafe-v0" + +dependencies { + moduleDependencies(project, ["libjf-base"]) +} \ No newline at end of file diff --git a/src/main/java/io/gitlab/jfronny/libjf/entry/DynamicEntry.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/DynamicEntry.java similarity index 87% rename from src/main/java/io/gitlab/jfronny/libjf/entry/DynamicEntry.java rename to libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/DynamicEntry.java index f6cd1f1..bba8d86 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/entry/DynamicEntry.java +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/DynamicEntry.java @@ -1,13 +1,13 @@ -package io.gitlab.jfronny.libjf.entry; +package io.gitlab.jfronny.libjf.unsafe; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -import net.fabricmc.loader.ModContainer; import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.metadata.EntrypointMetadata; +import net.fabricmc.loader.api.ModContainer; +import net.fabricmc.loader.impl.ModContainerImpl; +import net.fabricmc.loader.impl.metadata.EntrypointMetadata; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.function.Consumer; @@ -46,9 +46,8 @@ public class DynamicEntry { private static ReferenceArrayList getEntrypointTargets(final String entrypoint) { final ReferenceArrayList entrypoints = ReferenceArrayList.wrap(new EntrypointContainer[1], 0); - - for (final ModContainer mod : (Collection) (Object) FabricLoader.getInstance().getAllMods()) { - final List modEntrypoints = mod.getInfo().getEntrypoints(entrypoint); + for (final ModContainer mod : FabricLoader.getInstance().getAllMods()) { + final List modEntrypoints = ((ModContainerImpl)mod).getInfo().getEntrypoints(entrypoint); if (modEntrypoints != null) { for (final EntrypointMetadata metadata : modEntrypoints) { diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/JfLanguageAdapter.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/JfLanguageAdapter.java new file mode 100644 index 0000000..45cf318 --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/JfLanguageAdapter.java @@ -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 create(net.fabricmc.loader.api.ModContainer mod, String value, Class 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"); + } +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/MixinPlugin.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/MixinPlugin.java new file mode 100644 index 0000000..fb600eb --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/MixinPlugin.java @@ -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.AsmTransformer; +import io.gitlab.jfronny.libjf.unsafe.asm.BakedAsmConfig; +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.IMixinTransformer; +import sun.misc.Unsafe; + +import java.lang.reflect.Field; +import java.util.HashSet; +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.INSTANCE = (AsmTransformer) unsafe.allocateInstance(AsmTransformer.class); + AsmTransformer.INSTANCE.delegate = (IMixinTransformer) mixinTransformerField.get(delegate); + AsmTransformer.INSTANCE.asmConfigs = new HashSet<>(); + DynamicEntry.execute(LibJf.MOD_ID + ":asm", AsmConfig.class, s -> { + LibJf.LOGGER.info("Discovered LibJF asm plugin in " + s.modId()); + AsmTransformer.INSTANCE.asmConfigs.add(new BakedAsmConfig(s.instance())); + }); + + mixinTransformerField.set(delegate, AsmTransformer.INSTANCE); + } 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 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-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/UltraEarlyInit.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/UltraEarlyInit.java new file mode 100644 index 0000000..b3e6367 --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/UltraEarlyInit.java @@ -0,0 +1,5 @@ +package io.gitlab.jfronny.libjf.unsafe; + +public interface UltraEarlyInit { + void init(); +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/AsmConfig.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/AsmConfig.java new file mode 100644 index 0000000..486a19b --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/AsmConfig.java @@ -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 skipClasses(); + Set getPatches(); +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/AsmTransformer.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/AsmTransformer.java new file mode 100644 index 0000000..30bae38 --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/AsmTransformer.java @@ -0,0 +1,126 @@ +package io.gitlab.jfronny.libjf.unsafe.asm; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.MappingResolver; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.MixinEnvironment; +import org.spongepowered.asm.mixin.transformer.IMixinTransformer; +import org.spongepowered.asm.mixin.transformer.ext.IExtensionRegistry; +import org.spongepowered.asm.transformers.MixinClassWriter; + +import java.util.List; +import java.util.Set; + +public class AsmTransformer implements IMixinTransformer { + public static AsmTransformer INSTANCE; + public static final MappingResolver MAPPING_RESOLVER = FabricLoader.getInstance().getMappingResolver(); + public static final String INTERMEDIARY = "intermediary"; + public IMixinTransformer delegate; + public Set asmConfigs; + private AsmConfig currentConfig = null; + + @Override + public void audit(MixinEnvironment environment) { + delegate.audit(environment); + } + + @Override + public List reload(String mixinClass, ClassNode classNode) { + return delegate.reload(mixinClass, classNode); + } + + @Override + public boolean computeFramesForClass(MixinEnvironment environment, String name, ClassNode classNode) { + return delegate.computeFramesForClass(environment, name, classNode); + } + + @Override + public byte[] transformClassBytes(String name, String transformedName, byte[] classBytes) { + classBytes = delegate.transformClassBytes(name, transformedName, classBytes); + if (classBytes == null || name == null) + return classBytes; + if (isClassUnmoddable(name, null)) { + if (LibJf.DEV) LibJf.LOGGER.info("Skipping " + name); + return classBytes; + } + + ClassNode klazz = new ClassNode(); + ClassReader reader = new ClassReader(classBytes); + reader.accept(klazz, ClassReader.EXPAND_FRAMES); //ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG + + //if ((klazz.access & Opcodes.ACC_INTERFACE) != 0) { + // return classBytes; + //} + + for (AsmConfig config : asmConfigs) { + currentConfig = config; + if (!isClassUnmoddable(name, config)) { + for (Patch patch : config.getPatches()) { + patch.apply(klazz); + } + } + } + currentConfig = null; + + ClassWriter writer = new MixinClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + try { + klazz.accept(writer); + } + catch (NullPointerException t) { + LibJf.LOGGER.error("Could not transform " + transformedName, t); + return null; + } + classBytes = writer.toByteArray(); + //MixinEnvironment.getCurrentEnvironment(); + return classBytes; + } + + @Override + public byte[] transformClass(MixinEnvironment environment, String name, byte[] classBytes) { + LibJf.LOGGER.error("transformClass called"); + return delegate.transformClass(environment, name, classBytes); + } + + @Override + public boolean transformClass(MixinEnvironment environment, String name, ClassNode classNode) { + LibJf.LOGGER.error("transformClass called"); + return delegate.transformClass(environment, name, classNode); + } + + @Override + public byte[] generateClass(MixinEnvironment environment, String name) { + LibJf.LOGGER.error("generateClass called"); + return delegate.generateClass(environment, name); + } + + @Override + public boolean generateClass(MixinEnvironment environment, String name, ClassNode classNode) { + LibJf.LOGGER.error("generateClass called"); + return delegate.generateClass(environment, name, classNode); + } + + @Override + public IExtensionRegistry getExtensions() { + return delegate.getExtensions(); + } + + public static boolean isClassUnmoddable(String className, AsmConfig config) { + if (className.replace('/', '.').startsWith("org.objectweb.asm") + //|| className.startsWith("net.fabricmc.loader") + //|| className.startsWith("io.gitlab.jfronny.libjf.unsafe.asm") + ) + return true; + if (config == null) return false; + Set classes = config.skipClasses(); + if (classes == null) return false; + return classes.contains(MAPPING_RESOLVER.unmapClassName(INTERMEDIARY, className)); + } + + public AsmConfig getCurrentConfig() { + return currentConfig; + } +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/BakedAsmConfig.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/BakedAsmConfig.java new file mode 100644 index 0000000..e073a34 --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/BakedAsmConfig.java @@ -0,0 +1,24 @@ +package io.gitlab.jfronny.libjf.unsafe.asm; + +import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch; + +import java.util.Set; + +public class BakedAsmConfig implements AsmConfig { + private final Set skipClasses; + private final Set patches; + public BakedAsmConfig(AsmConfig config) { + skipClasses = config.skipClasses(); + patches = config.getPatches(); + } + + @Override + public Set skipClasses() { + return skipClasses; + } + + @Override + public Set getPatches() { + return patches; + } +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/MethodPatch.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/MethodPatch.java new file mode 100644 index 0000000..f37e773 --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/MethodPatch.java @@ -0,0 +1,7 @@ +package io.gitlab.jfronny.libjf.unsafe.asm.patch; + +import org.objectweb.asm.tree.MethodNode; + +public interface MethodPatch { + void apply(MethodNode method); +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/Patch.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/Patch.java new file mode 100644 index 0000000..7455067 --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/Patch.java @@ -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); +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/PatchUtil.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/PatchUtil.java new file mode 100644 index 0000000..6fab19e --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/PatchUtil.java @@ -0,0 +1,67 @@ +package io.gitlab.jfronny.libjf.unsafe.asm.patch; + +import io.gitlab.jfronny.libjf.unsafe.asm.AsmTransformer; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.*; + +public class PatchUtil { + public static String getRemappedInternal(String className) { + return getRemapped(className.replace('/', '.')).replace('.', '/'); + } + + public static String getRemapped(String className) { + return AsmTransformer.MAPPING_RESOLVER.mapClassName(AsmTransformer.INTERMEDIARY, className); + } + + public static void redirectReturn(MethodNode method, String targetClass, String hookClass, String targetMethod, String targetType, String[] extraParamTypes) { + for (AbstractInsnNode node : method.instructions) { + if (node.getOpcode() == Opcodes.ARETURN + || node.getOpcode() == Opcodes.IRETURN + || node.getOpcode() == Opcodes.DRETURN + || node.getOpcode() == Opcodes.FRETURN + || node.getOpcode() == Opcodes.LRETURN) { + method.instructions.insertBefore(node, PatchUtil.buildParamPassingInvoker(targetClass, hookClass, targetMethod, targetType, targetType, extraParamTypes)); + } + } + } + + public static void redirectExceptions(MethodNode method, String targetClass, String hookClass, String exceptionType, String returnTypeNormal, String targetMethod, String[] extraParamTypes) { + LabelNode start = new LabelNode(); + LabelNode end = new LabelNode(); + LabelNode handler = new LabelNode(); + method.instructions.insertBefore(method.instructions.getFirst(), start); + method.instructions.insertBefore(method.instructions.getLast(), end); + method.instructions.add(handler); + method.instructions.add(PatchUtil.buildParamPassingInvoker(targetClass, + hookClass, + targetMethod, + "L" + getRemappedInternal(exceptionType) + ";", + "L" + getRemappedInternal(returnTypeNormal) + ";", + extraParamTypes)); + method.instructions.add(new InsnNode(Opcodes.ARETURN)); + method.tryCatchBlocks.add(new TryCatchBlockNode(start, end, handler, exceptionType)); + } + + public static InsnList buildParamPassingInvoker(String targetClass, String hookClass, String targetMethod, String inType, String outType, String[] extraParamTypes) { + InsnList instructions = new InsnList(); + instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); + StringBuilder descriptor = new StringBuilder("(").append(inType); + descriptor.append('L').append(getRemappedInternal(targetClass)).append(';'); + for (int i = 0; i < extraParamTypes.length; i++) { + instructions.add(new VarInsnNode(switch (extraParamTypes[i]) { + case "I" -> Opcodes.ILOAD; + case "D" -> Opcodes.DLOAD; + case "F" -> Opcodes.FLOAD; + case "L" -> Opcodes.LLOAD; + default -> Opcodes.ALOAD; + }, i + 1)); + if (extraParamTypes[i].length() == 1) + descriptor.append(extraParamTypes[i]); + else + descriptor.append('L').append(PatchUtil.getRemappedInternal(extraParamTypes[i])).append(';'); + } + descriptor.append(")").append(outType); + instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, hookClass, targetMethod, descriptor.toString())); + return instructions; + } +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/method/MethodReplacementPatch.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/method/MethodReplacementPatch.java new file mode 100644 index 0000000..5284b8b --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/method/MethodReplacementPatch.java @@ -0,0 +1,23 @@ +package io.gitlab.jfronny.libjf.unsafe.asm.patch.method; + +import io.gitlab.jfronny.libjf.unsafe.asm.patch.MethodPatch; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; + +public class MethodReplacementPatch implements MethodPatch { + private final InsnList instructions; + public MethodReplacementPatch(InsnList instructions) { + this.instructions = instructions; + } + + @Override + public void apply(MethodNode method) { + method.instructions.clear(); + InsnList clone = new InsnList(); + for (AbstractInsnNode instruction : instructions) { + clone.add(instruction); + } + method.instructions.insert(clone); + } +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/modification/MethodModificationPatch.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/modification/MethodModificationPatch.java new file mode 100644 index 0000000..55a85c3 --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/modification/MethodModificationPatch.java @@ -0,0 +1,42 @@ +package io.gitlab.jfronny.libjf.unsafe.asm.patch.modification; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.unsafe.asm.AsmTransformer; +import io.gitlab.jfronny.libjf.unsafe.asm.patch.MethodPatch; +import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +public class MethodModificationPatch implements Patch { + private final Map patches = new LinkedHashMap<>(); + + public MethodModificationPatch(String targetMethodOwner, Set patches) { + for (MethodDescriptorPatch patch : patches) { + this.patches.put( + AsmTransformer.MAPPING_RESOLVER.mapMethodName(AsmTransformer.INTERMEDIARY, targetMethodOwner, patch.methodName, patch.methodDescriptor), + patch.patch + ); + } + for (String s : this.patches.keySet()) { + if (LibJf.DEV) LibJf.LOGGER.info("Registered patch for " + s); + } + } + + @Override + public void apply(ClassNode klazz) { + for (MethodNode method : klazz.methods) { + if (patches.containsKey(method.name)) { + if (LibJf.DEV) LibJf.LOGGER.info("Patching " + method.name); + patches.get(method.name).apply(method); + } + } + } + + public static record MethodDescriptorPatch(String methodName, String methodDescriptor, MethodPatch patch) { + + } +} diff --git a/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/targeting/InterfaceImplTargetPatch.java b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/targeting/InterfaceImplTargetPatch.java new file mode 100644 index 0000000..d964ec5 --- /dev/null +++ b/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/patch/targeting/InterfaceImplTargetPatch.java @@ -0,0 +1,107 @@ +package io.gitlab.jfronny.libjf.unsafe.asm.patch.targeting; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.unsafe.asm.AsmTransformer; +import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class InterfaceImplTargetPatch implements Patch { + public static final Map> INTERFACES = new HashMap<>(); + private final String targetInterface; + private final Patch methodPatch; + + public InterfaceImplTargetPatch(String targetInterfaceIntermediary, Patch methodPatch) { + this.targetInterface = AsmTransformer.MAPPING_RESOLVER.mapClassName(AsmTransformer.INTERMEDIARY, targetInterfaceIntermediary).replace('.', '/'); + this.methodPatch = methodPatch; + } + + @Override + public void apply(ClassNode klazz) { + scanInterfaces(klazz); + if (getUpper(klazz.name).contains(targetInterface)) { + if (LibJf.DEV) LibJf.LOGGER.info("Found " + klazz.name + " implementing " + targetInterface); + methodPatch.apply(klazz); + } + } + + private static void scanInterfaces(ClassNode klazz) { + if (INTERFACES.containsKey(klazz.name)) return; + INTERFACES.put(klazz.name, new HashSet<>()); + for (String anInterface : klazz.interfaces) { + INTERFACES.get(klazz.name).add(anInterface); + } + if (klazz.superName != null) { + INTERFACES.get(klazz.name).add(klazz.superName); + } + INTERFACES.put(klazz.name, Set.copyOf(INTERFACES.get(klazz.name))); + for (String s : INTERFACES.get(klazz.name)) { + String n = s.replace('/', '.'); + if (AsmTransformer.isClassUnmoddable(n, AsmTransformer.INSTANCE.getCurrentConfig())) + continue; + try { + InterfaceImplTargetPatch.class.getClassLoader().loadClass(n); + } catch (Throwable e) { + throw new RuntimeException("Could not load super class " + s + " of " + klazz.name, e); + } + } + } + + private static void scanInterfaces(Class klazz) { + String n = Type.getInternalName(klazz); + if (INTERFACES.containsKey(n)) return; + INTERFACES.put(n, new HashSet<>()); + for (Class anInterface : klazz.getInterfaces()) { + INTERFACES.get(n).add(Type.getInternalName(anInterface)); + } + Class superC = klazz.getSuperclass(); + if (superC != null) { + INTERFACES.get(n).add(Type.getInternalName(superC)); + } + INTERFACES.put(n, Set.copyOf(INTERFACES.get(n))); + for (String s : INTERFACES.get(n)) { + String nn = s.replace('/', '.'); + if (AsmTransformer.isClassUnmoddable(nn, AsmTransformer.INSTANCE.getCurrentConfig())) + continue; + try { + scanInterfaces(InterfaceImplTargetPatch.class.getClassLoader().loadClass(nn)); + } catch (Throwable e) { + throw new RuntimeException("Could not load super class " + s + " of " + n, e); + } + } + } + + public static Set getUpper(String className) { + Set s = INTERFACES.get(className); + if (s == null) { + if (!className.startsWith("java/") + && !className.startsWith("com/mojang/") + && !className.startsWith("net/minecraft/") + && !className.startsWith("jdk/") + && !className.startsWith("it/unimi/dsi/fastutil/") + && !className.startsWith("com/google/") + ) { + if (LibJf.DEV) LibJf.LOGGER.info("Non-default class not considered for interface scanning: " + className); + INTERFACES.put(className, Set.of()); + return Set.of(); + } + try { + scanInterfaces(Class.forName(className.replace('/', '.'))); + s = INTERFACES.get(className); + } catch (ClassNotFoundException e) { + LibJf.LOGGER.error("Could not get base for " + className, e); + return Set.of(); + } + } + s = new HashSet<>(s); + for (String s1 : s.toArray(new String[0])) { + s.addAll(getUpper(s1)); + } + return s; + } +} diff --git a/libjf-unsafe-v0/src/main/resources/fabric.mod.json b/libjf-unsafe-v0/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..738c0b0 --- /dev/null +++ b/libjf-unsafe-v0/src/main/resources/fabric.mod.json @@ -0,0 +1,30 @@ +{ + "schemaVersion": 1, + "id": "libjf-unsafe-v0", + "name": "LibJF Unsafe", + "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"], + "depends": { + "fabricloader": ">=0.12.0", + "minecraft": "*", + "libjf-base": "${version}" + }, + "custom": { + "modmenu": { + "parent": "libjf", + "badges": ["library"] + } + } +} diff --git a/libjf-unsafe-v0/src/main/resources/libjf-unsafe-v0.mixins.json b/libjf-unsafe-v0/src/main/resources/libjf-unsafe-v0.mixins.json new file mode 100644 index 0000000..12d8658 --- /dev/null +++ b/libjf-unsafe-v0/src/main/resources/libjf-unsafe-v0.mixins.json @@ -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 + } +} diff --git a/libjf-unsafe-v0/src/testmod/java/io/gitlab/jfronny/libjf/unsafe/test/AsmTest.java b/libjf-unsafe-v0/src/testmod/java/io/gitlab/jfronny/libjf/unsafe/test/AsmTest.java new file mode 100644 index 0000000..9121606 --- /dev/null +++ b/libjf-unsafe-v0/src/testmod/java/io/gitlab/jfronny/libjf/unsafe/test/AsmTest.java @@ -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 skipClasses() { + return null; + } + + @Override + public Set 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" + + "..:::::..:::......:::..:::::..:::::..:::::........:::......::::::..:::::"); + } +} diff --git a/libjf-unsafe-v0/src/testmod/java/io/gitlab/jfronny/libjf/unsafe/test/UnsafeEntryTest.java b/libjf-unsafe-v0/src/testmod/java/io/gitlab/jfronny/libjf/unsafe/test/UnsafeEntryTest.java new file mode 100644 index 0000000..ff8bcb8 --- /dev/null +++ b/libjf-unsafe-v0/src/testmod/java/io/gitlab/jfronny/libjf/unsafe/test/UnsafeEntryTest.java @@ -0,0 +1,19 @@ +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" + + " '' "); + LibJf.DEV = true; + } +} diff --git a/libjf-unsafe-v0/src/testmod/resources/fabric.mod.json b/libjf-unsafe-v0/src/testmod/resources/fabric.mod.json new file mode 100644 index 0000000..1d754b6 --- /dev/null +++ b/libjf-unsafe-v0/src/testmod/resources/fabric.mod.json @@ -0,0 +1,14 @@ +{ + "schemaVersion": 1, + "id": "libjf-unsafe-v0-testmod", + "version": "1.0", + "environment": "*", + "entrypoints": { + "libjf:asm": [ + "io.gitlab.jfronny.libjf.unsafe.test.AsmTest" + ], + "libjf:early": [ + "io.gitlab.jfronny.libjf.unsafe.test.UnsafeEntryTest" + ] + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index f91a4fe..9afced0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,3 +7,13 @@ pluginManagement { gradlePluginPortal() } } + +rootProject.name = "libjf" + +include 'libjf-base' + +include 'libjf-config-v0' +include 'libjf-data-v0' +include 'libjf-data-manipulation-v0' +//include 'libjf-devutil-v0' //TODO re-enable for 1.18 +include 'libjf-unsafe-v0' \ No newline at end of file diff --git a/src/main/java/io/gitlab/jfronny/libjf/Libjf.java b/src/main/java/io/gitlab/jfronny/libjf/Libjf.java index c14cdbb..3cf2670 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/Libjf.java +++ b/src/main/java/io/gitlab/jfronny/libjf/Libjf.java @@ -1,41 +1,27 @@ 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 io.gitlab.jfronny.libjf.config.impl.ConfigHolder; +import io.gitlab.jfronny.libjf.data.WrappedPack; +import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents; +import net.fabricmc.api.ModInitializer; -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 configs = new HashMap<>(); - - @Deprecated +//TODO remove for 1.18 +@Deprecated(forRemoval = true) +public class Libjf implements ModInitializer { + @Deprecated(forRemoval = true) public static void registerConfig(String modId, Class config) { - if (!isRegistered(config)) - configs.put(modId, new Config(modId, config)); + ConfigHolder.registerConfig(modId, config); } - public static Map 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; + + @Override + public void onInitialize() { + UserResourceEvents.CONTAINS.register((type, id, previous, pack) -> + io.gitlab.jfronny.libjf.data.UserResourceEvents.CONTAINS.invoker().contains(type, id, previous, WrappedPack.create(pack))); + UserResourceEvents.FIND_RESOURCE.register((type, namespace, prefix, maxDepth, pathFilter, previous, pack) -> + io.gitlab.jfronny.libjf.data.UserResourceEvents.FIND_RESOURCE.invoker().findResources(type, namespace, prefix, maxDepth, pathFilter, previous, WrappedPack.create(pack))); + UserResourceEvents.OPEN.register((type, id, previous, pack) -> + io.gitlab.jfronny.libjf.data.UserResourceEvents.OPEN.invoker().open(type, id, previous, WrappedPack.create(pack))); + UserResourceEvents.OPEN_ROOT.register((fileName, previous, pack) -> + io.gitlab.jfronny.libjf.data.UserResourceEvents.OPEN_ROOT.invoker().openRoot(fileName, previous, WrappedPack.create(pack))); } } diff --git a/src/main/java/io/gitlab/jfronny/libjf/config/JfConfig.java b/src/main/java/io/gitlab/jfronny/libjf/config/JfConfig.java index 4e8098a..f2e025f 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/config/JfConfig.java +++ b/src/main/java/io/gitlab/jfronny/libjf/config/JfConfig.java @@ -1,4 +1,5 @@ package io.gitlab.jfronny.libjf.config; -public interface JfConfig { +@Deprecated(forRemoval = true) +public interface JfConfig extends io.gitlab.jfronny.libjf.config.api.JfConfig { } diff --git a/src/main/java/io/gitlab/jfronny/libjf/data/RecipeUtil.java b/src/main/java/io/gitlab/jfronny/libjf/data/RecipeUtil.java index 942074b..8b7efac 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/data/RecipeUtil.java +++ b/src/main/java/io/gitlab/jfronny/libjf/data/RecipeUtil.java @@ -2,28 +2,23 @@ package io.gitlab.jfronny.libjf.data; import net.minecraft.item.ItemStack; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; import java.util.Set; +@Deprecated(forRemoval = true) public class RecipeUtil { - private final static Set removalsByIdentifier = new HashSet<>(); - private final static List recipesForRemoval = new ArrayList<>(); - public static void removeRecipe(String id) { - removalsByIdentifier.add(id); + RecipeUtil.removeRecipe(id); } public static void removeRecipeFor(ItemStack product) { - recipesForRemoval.add(product); + RecipeUtil.removeRecipeFor(product); } public static Iterable getRecipesForRemoval() { - return recipesForRemoval; + return RecipeUtil.getRecipesForRemoval(); } public static Set getIdentifiersForRemoval() { - return removalsByIdentifier; + return RecipeUtil.getIdentifiersForRemoval(); } } diff --git a/src/main/java/io/gitlab/jfronny/libjf/data/ResourcePath.java b/src/main/java/io/gitlab/jfronny/libjf/data/ResourcePath.java index bd6f957..e777aea 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/data/ResourcePath.java +++ b/src/main/java/io/gitlab/jfronny/libjf/data/ResourcePath.java @@ -3,42 +3,13 @@ package io.gitlab.jfronny.libjf.data; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; -public class ResourcePath implements AutoCloseable { - private final ResourceType type; - private final Identifier id; - +@Deprecated(forRemoval = true) +public class ResourcePath extends io.gitlab.jfronny.libjf.ResourcePath { public ResourcePath(ResourceType type, Identifier id) { - this.type = type; - this.id = id; + super(type, id); } public ResourcePath(String name) throws IllegalStateException { - String[] s1 = name.split("/", 3); - if (s1.length != 3) { - throw new IllegalStateException("Could not split path string into resource type and ID due to insufficient length: " + name); - } - type = switch (s1[0]) { - case "assets" -> ResourceType.CLIENT_RESOURCES; - case "data" -> ResourceType.SERVER_DATA; - default -> throw new IllegalStateException("Unexpected value for resource type: " + s1[0] + " in: " + name); - }; - id = new Identifier(s1[1], s1[2]); - } - - public Identifier getId() { - return id; - } - - public ResourceType getType() { - return type; - } - - public String getName() { - return String.format("%s/%s/%s", type.getDirectory(), id.getNamespace(), id.getPath()); - } - - @Override - public void close() throws Exception { - + super(name); } } diff --git a/src/main/java/io/gitlab/jfronny/libjf/data/Tags.java b/src/main/java/io/gitlab/jfronny/libjf/data/Tags.java deleted file mode 100644 index d085b2f..0000000 --- a/src/main/java/io/gitlab/jfronny/libjf/data/Tags.java +++ /dev/null @@ -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 SHULKER_ILLEGAL = TagFactory.ITEM.create(new Identifier(Libjf.MOD_ID, "shulker_boxes_illegal")); - public static Tag OVERPOWERED = TagFactory.ITEM.create(new Identifier(Libjf.MOD_ID, "overpowered")); -} diff --git a/src/main/java/io/gitlab/jfronny/libjf/data/UserResourceEvents.java b/src/main/java/io/gitlab/jfronny/libjf/data/UserResourceEvents.java index c6c6f4d..f6a2dc8 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/data/UserResourceEvents.java +++ b/src/main/java/io/gitlab/jfronny/libjf/data/UserResourceEvents.java @@ -10,6 +10,7 @@ import java.io.InputStream; import java.util.Collection; import java.util.function.Predicate; +@Deprecated(forRemoval = true) public class UserResourceEvents { public static final Event CONTAINS = EventFactory.createArrayBacked(Contains.class, (listeners) -> (type, id, previous, pack) -> { diff --git a/src/main/java/io/gitlab/jfronny/libjf/data/WrappedPack.java b/src/main/java/io/gitlab/jfronny/libjf/data/WrappedPack.java index 50622b2..dbaa2cd 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/data/WrappedPack.java +++ b/src/main/java/io/gitlab/jfronny/libjf/data/WrappedPack.java @@ -3,7 +3,7 @@ package io.gitlab.jfronny.libjf.data; import io.gitlab.jfronny.libjf.data.wrappedPackImpl.WrappedResourcePack; import net.minecraft.resource.ResourcePack; -//This is a class for binary compatibility with mods using libjf +@Deprecated(forRemoval = true) public abstract class WrappedPack implements ResourcePack { public abstract ResourcePack getUnderlying(); diff --git a/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/EventCallImpl.java b/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/EventCallImpl.java deleted file mode 100644 index 871be77..0000000 --- a/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/EventCallImpl.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.gitlab.jfronny.libjf.data.wrappedPackImpl; - -import io.gitlab.jfronny.libjf.data.ResourcePath; -import io.gitlab.jfronny.libjf.data.UserResourceEvents; -import io.gitlab.jfronny.libjf.data.WrappedPack; -import net.minecraft.resource.ResourceType; -import net.minecraft.util.Identifier; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collection; -import java.util.function.Predicate; - -public class EventCallImpl { - public static InputStream hookOpenRoot(WrappedPack pack, String fileName) throws IOException { - InputStream is = null; - IOException ex = null; - try { - is = pack.getUnderlying().openRoot(fileName); - } - catch (IOException ex1) { - ex = ex1; - } - is = UserResourceEvents.OPEN_ROOT.invoker().openRoot(fileName, is, pack); - if (is == null) - throw ex == null ? new FileNotFoundException(fileName) : ex; - return is; - } - - public static InputStream hookOpen(WrappedPack pack, ResourceType type, Identifier id) throws IOException { - InputStream is = UserResourceEvents.OPEN.invoker().open(type, id, pack.getUnderlying().contains(type, id) ? pack.getUnderlying().open(type, id) : null, pack); - if (is == null) - throw new FileNotFoundException(new ResourcePath(type, id).getName()); - return is; - } - - public static Collection hookFindResources(WrappedPack pack, ResourceType type, String namespace, String prefix, int maxDepth, Predicate pathFilter) { - return UserResourceEvents.FIND_RESOURCE.invoker().findResources(type, namespace, prefix, maxDepth, pathFilter, pack.getUnderlying().findResources(type, namespace, prefix, maxDepth, pathFilter), pack); - } - - public static boolean hookContains(WrappedPack pack, ResourceType type, Identifier id) { - return UserResourceEvents.CONTAINS.invoker().contains(type, id, pack.getUnderlying().contains(type, id), pack); - } -} diff --git a/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/SafeWrappedResourcePack.java b/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/SafeWrappedResourcePack.java new file mode 100644 index 0000000..2877ff2 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/SafeWrappedResourcePack.java @@ -0,0 +1,64 @@ +package io.gitlab.jfronny.libjf.data.wrappedPackImpl; + +import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents; +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.ResourceType; +import net.minecraft.resource.metadata.ResourceMetadataReader; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.Set; +import java.util.function.Predicate; + +@Deprecated(forRemoval = true) +public class SafeWrappedResourcePack implements ResourcePack { + ResourcePack pack; + public SafeWrappedResourcePack(ResourcePack pack) { + this.pack = pack; + } + + @Nullable + @Override + public InputStream openRoot(String fileName) throws IOException { + return UserResourceEvents.disable(() -> pack.openRoot(fileName)); + } + + @Override + public InputStream open(ResourceType type, Identifier id) throws IOException { + return UserResourceEvents.disable(() -> pack.open(type, id)); + } + + @Override + public Collection findResources(ResourceType type, String namespace, String prefix, int maxDepth, Predicate pathFilter) { + return UserResourceEvents.disable(() -> pack.findResources(type, namespace, prefix, maxDepth, pathFilter)); + } + + @Override + public boolean contains(ResourceType type, Identifier id) { + return UserResourceEvents.disable(() -> pack.contains(type, id)); + } + + @Override + public Set getNamespaces(ResourceType type) { + return UserResourceEvents.disable(() -> pack.getNamespaces(type)); + } + + @Nullable + @Override + public T parseMetadata(ResourceMetadataReader metaReader) throws IOException { + return UserResourceEvents.disable(() -> pack.parseMetadata(metaReader)); + } + + @Override + public String getName() { + return UserResourceEvents.disable(() -> pack.getName()); + } + + @Override + public void close() { + UserResourceEvents.disable(() -> pack.close()); + } +} diff --git a/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/WrappedResourcePack.java b/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/WrappedResourcePack.java index 11055fd..005092f 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/WrappedResourcePack.java +++ b/src/main/java/io/gitlab/jfronny/libjf/data/wrappedPackImpl/WrappedResourcePack.java @@ -13,31 +13,39 @@ import java.util.Collection; import java.util.Set; import java.util.function.Predicate; +@Deprecated(forRemoval = true) public class WrappedResourcePack extends WrappedPack { ResourcePack pack; + SafeWrappedResourcePack safeWrappedResourcePack; public WrappedResourcePack(ResourcePack pack) { this.pack = pack; + safeWrappedResourcePack = new SafeWrappedResourcePack(pack); + } + + @Override + public ResourcePack getUnderlying() { + return safeWrappedResourcePack; } @Nullable @Override public InputStream openRoot(String fileName) throws IOException { - return EventCallImpl.hookOpenRoot(this, fileName); + return pack.openRoot(fileName); } @Override public InputStream open(ResourceType type, Identifier id) throws IOException { - return EventCallImpl.hookOpen(this, type, id); + return pack.open(type, id); } @Override public Collection findResources(ResourceType type, String namespace, String prefix, int maxDepth, Predicate pathFilter) { - return EventCallImpl.hookFindResources(this, type, namespace, prefix, maxDepth, pathFilter); + return pack.findResources(type, namespace, prefix, maxDepth, pathFilter); } @Override public boolean contains(ResourceType type, Identifier id) { - return EventCallImpl.hookContains(this, type, id); + return pack.contains(type, id); } @Override @@ -60,8 +68,4 @@ public class WrappedResourcePack extends WrappedPack { public void close() { pack.close(); } - - public ResourcePack getUnderlying() { - return pack; - } } diff --git a/src/main/java/io/gitlab/jfronny/libjf/entry/JfLanguageAdapter.java b/src/main/java/io/gitlab/jfronny/libjf/entry/JfLanguageAdapter.java deleted file mode 100644 index 059b909..0000000 --- a/src/main/java/io/gitlab/jfronny/libjf/entry/JfLanguageAdapter.java +++ /dev/null @@ -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 create(net.fabricmc.loader.api.ModContainer mod, String value, Class 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()); - } -} diff --git a/src/main/java/io/gitlab/jfronny/libjf/entry/LibjfClient.java b/src/main/java/io/gitlab/jfronny/libjf/entry/LibjfClient.java deleted file mode 100644 index b76789d..0000000 --- a/src/main/java/io/gitlab/jfronny/libjf/entry/LibjfClient.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.gitlab.jfronny.libjf.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.EntryInfo; -import io.gitlab.jfronny.libjf.gson.GsonHidden; -import net.fabricmc.api.ClientModInitializer; - -public class LibjfClient implements ClientModInitializer { - @Override - public void onInitializeClient() { - for (Config config : Libjf.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 { - config.initClient(info); - } catch (Exception ignored) { - } - } - } - } -} diff --git a/src/main/java/io/gitlab/jfronny/libjf/entry/UltraEarlyInit.java b/src/main/java/io/gitlab/jfronny/libjf/entry/UltraEarlyInit.java index 959ab65..c015d88 100644 --- a/src/main/java/io/gitlab/jfronny/libjf/entry/UltraEarlyInit.java +++ b/src/main/java/io/gitlab/jfronny/libjf/entry/UltraEarlyInit.java @@ -1,5 +1,4 @@ package io.gitlab.jfronny.libjf.entry; -public interface UltraEarlyInit { - void init(); +public interface UltraEarlyInit extends io.gitlab.jfronny.libjf.unsafe.UltraEarlyInit { } diff --git a/src/main/java/io/gitlab/jfronny/libjf/mixin/ReloadableResourceManagerImplMixin.java b/src/main/java/io/gitlab/jfronny/libjf/mixin/ReloadableResourceManagerImplMixin.java deleted file mode 100644 index 2422390..0000000 --- a/src/main/java/io/gitlab/jfronny/libjf/mixin/ReloadableResourceManagerImplMixin.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.gitlab.jfronny.libjf.mixin; - -import io.gitlab.jfronny.libjf.data.WrappedPack; -import net.fabricmc.fabric.impl.resource.loader.FabricModResourcePack; -import net.fabricmc.fabric.impl.resource.loader.ModNioResourcePack; -import net.minecraft.resource.ReloadableResourceManagerImpl; -import net.minecraft.resource.ResourcePack; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; - -@Mixin(ReloadableResourceManagerImpl.class) -public class ReloadableResourceManagerImplMixin { - @ModifyVariable(method = "addPack(Lnet/minecraft/resource/ResourcePack;)V", at = @At("HEAD"), argsOnly = true, ordinal = 0) - private ResourcePack modifyPack(ResourcePack pack) { - if (pack instanceof WrappedPack || pack instanceof ModNioResourcePack || pack instanceof FabricModResourcePack) { //TODO use ASM for this to allow mod resource packs - return pack; - } - return WrappedPack.create(pack); - } -} diff --git a/src/main/resources/assets/libjf/icon.png b/src/main/resources/assets/libjf/icon.png new file mode 100644 index 0000000..f1536ba Binary files /dev/null and b/src/main/resources/assets/libjf/icon.png differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 9b01788..5bd37d7 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -15,22 +15,14 @@ "icon": "assets/libjf/icon.png", "environment": "*", "entrypoints": { - "client": [ - "io.gitlab.jfronny.libjf.entry.LibjfClient" - ], - "modmenu": [ - "io.gitlab.jfronny.libjf.config.ModMenu" - ] + "main": ["io.gitlab.jfronny.libjf.Libjf"] }, - "languageAdapters": { - "libjf": "io.gitlab.jfronny.libjf.entry.JfLanguageAdapter" - }, - "mixins": [ - "libjf.mixins.json" - ], "depends": { - "fabricloader": ">=0.11.3", - "minecraft": "*" + "fabricloader": ">=0.12.0", + "minecraft": "*", + "libjf-config-v0": "${version}", + "libjf-data-v0": "${version}", + "libjf-base": "${version}" }, "custom": { "modmenu": { diff --git a/src/testmod/java/io/gitlab/jfronny/libjf/test/Entrypoint.java b/src/testmod/java/io/gitlab/jfronny/libjf/test/Entrypoint.java deleted file mode 100644 index a51b32c..0000000 --- a/src/testmod/java/io/gitlab/jfronny/libjf/test/Entrypoint.java +++ /dev/null @@ -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; - }); - } -} diff --git a/src/testmod/resources/assets/libjf-testmod/lang/en_us.json b/src/testmod/resources/assets/libjf-testmod/lang/en_us.json deleted file mode 100644 index 0ccf914..0000000 --- a/src/testmod/resources/assets/libjf-testmod/lang/en_us.json +++ /dev/null @@ -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" -} \ No newline at end of file diff --git a/src/testmod/resources/fabric.mod.json b/src/testmod/resources/fabric.mod.json deleted file mode 100644 index e45be75..0000000 --- a/src/testmod/resources/fabric.mod.json +++ /dev/null @@ -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" - ] - } -} \ No newline at end of file