diff --git a/.gitignore b/.gitignore index 54eb00e..568f14b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ #gradle **/build **/.gradle +/coremods-test/logs/ diff --git a/build.gradle b/build.gradle index 0a5e4b8..7715ee3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,16 @@ import net.minecraftforge.gradleutils.PomUtils plugins { - id 'net.minecraftforge.licenser' version '1.0.1' id 'idea' id 'eclipse' id 'java-library' id 'maven-publish' - id 'net.minecraftforge.gradleutils' version '[2.1.3,2.3.0)' + alias libs.plugins.license + //alias libs.plugins.versions + alias libs.plugins.gradleutils } -group 'net.minecraftforge' +group = 'net.minecraftforge' version = gradleutils.tagOffsetVersion println "Version: $version" @@ -25,7 +26,7 @@ repositories { } changelog { - fromTag "1.0.0" + from '1.0.0' } license { @@ -34,25 +35,14 @@ license { } dependencies { - // TODO: Cleanup tests - testImplementation('org.junit.jupiter:junit-jupiter-api:5.7.+') - testImplementation('org.powermock:powermock-core:2.0.+') - testImplementation('org.hamcrest:hamcrest-core:2.2') - testImplementation('org.apache.logging.log4j:log4j-core:2.19.0') - testImplementation(libs.modlauncher) - testImplementation(libs.forgespi) - testImplementation(libs.unsafe) - testCompileOnly('org.jetbrains:annotations:21.0.1') - testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.7.+') - testRuntimeOnly(project(':coremods-test-jar')) - compileOnly(libs.modlauncher) compileOnly(libs.securemodules) compileOnly(libs.log4j.api) - api(libs.bundles.asm) + compileOnly(libs.nulls) compileOnly(libs.forgespi) + + api(libs.bundles.asm) implementation(libs.nashorn) - compileOnly(libs.nulls) } tasks.named('jar', Jar) { diff --git a/coremods-test-jar/build.gradle b/coremods-test-jar/build.gradle index 33ca303..7abb5e0 100644 --- a/coremods-test-jar/build.gradle +++ b/coremods-test-jar/build.gradle @@ -1,8 +1,9 @@ plugins { - id 'net.minecraftforge.licenser' version '1.0.1' id 'eclipse' id 'java-library' - id 'net.minecraftforge.gradleutils' version '[2.1.3,2.3.0)' + alias libs.plugins.license + //alias libs.plugins.versions + alias libs.plugins.gradleutils } repositories { diff --git a/coremods-test-jar/src/main/java/module-info.java b/coremods-test-jar/src/main/java/module-info.java new file mode 100644 index 0000000..1451a42 --- /dev/null +++ b/coremods-test-jar/src/main/java/module-info.java @@ -0,0 +1,8 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ + +open module net.minecraftforge.coremod.testjar { + exports net.minecraftforge.coremod.testjar; +} diff --git a/coremods-test-jar/src/main/java/net/minecraftforge/coremod/testjar/Counter.java b/coremods-test-jar/src/main/java/net/minecraftforge/coremod/testjar/Counter.java new file mode 100644 index 0000000..023d09f --- /dev/null +++ b/coremods-test-jar/src/main/java/net/minecraftforge/coremod/testjar/Counter.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.coremod.testjar; + +import java.util.ArrayList; +import java.util.List; + +public class Counter { + private final List counts = new ArrayList<>(); + + public Counter() { + push(); + } + + public int[] getCounts() { + return counts.stream().mapToInt(Integer::intValue).toArray(); + } + + public void push() { + counts.add(0); + } + + public void increment() { + counts.set(counts.size() - 1, counts.get(counts.size() - 1) + 1); + } +} diff --git a/coremods-test-jar/src/main/java/net/minecraftforge/coremod/testjar/TestClass.java b/coremods-test-jar/src/main/java/net/minecraftforge/coremod/testjar/TestClass.java new file mode 100644 index 0000000..43fc06a --- /dev/null +++ b/coremods-test-jar/src/main/java/net/minecraftforge/coremod/testjar/TestClass.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.coremod.testjar; + +public class TestClass { + public static boolean False() { + return false; + } + + public static int[] testCounter() { + var counts = new Counter(); + counts.push(); + return counts.getCounts(); + } + + public static String testString() { + return "raw"; + } +} diff --git a/coremods-test-jar/src/main/java/net/minecraftforge/coremod/testjar/TestMarker.java b/coremods-test-jar/src/main/java/net/minecraftforge/coremod/testjar/TestMarker.java new file mode 100644 index 0000000..d4fb988 --- /dev/null +++ b/coremods-test-jar/src/main/java/net/minecraftforge/coremod/testjar/TestMarker.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.coremod.testjar; + +// Marker class to let the arms length find the test resources +public class TestMarker { +} diff --git a/coremods-test-jar/src/main/java/net/minecraftforge/coremods/testjar/RedirectClass.java b/coremods-test-jar/src/main/java/net/minecraftforge/coremods/testjar/RedirectClass.java deleted file mode 100644 index 1947f2e..0000000 --- a/coremods-test-jar/src/main/java/net/minecraftforge/coremods/testjar/RedirectClass.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.coremods.testjar; - -public class RedirectClass { - private static int beforeCallCount = 0; - private static int afterCallCount = 0; - - public static boolean newMethod() { - return false; - } - - public static void afterMethod() { - afterCallCount++; - } - - public static void beforeMethod() { - beforeCallCount++; - } - - public static int getBeforeCallCount() { - return beforeCallCount; - } - - public static int getAfterCallCount() { - return afterCallCount; - } -} diff --git a/coremods-test-jar/src/main/java/net/minecraftforge/coremods/testjar/TestClass.java b/coremods-test-jar/src/main/java/net/minecraftforge/coremods/testjar/TestClass.java deleted file mode 100644 index 83bafd6..0000000 --- a/coremods-test-jar/src/main/java/net/minecraftforge/coremods/testjar/TestClass.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.coremods.testjar; - -public class TestClass { - public static void cheese() { - System.out.println("hello"); - } - - public static boolean testMethod() { - return true; - } - - public static void main(String... args) { - cheese(); - } - - public static boolean testInsert() { - testMethod1(); - boolean result = testMethod2(); - testMethod1(); - return result; - } - - public static long testMethod1() { - return (long) (Math.random() * 3290L); - } - - public static boolean testMethod2() { - return true; - } -} diff --git a/coremods-test-jar/src/main/java/net/minecraftforge/coremods/testjar/TestTarget.java b/coremods-test-jar/src/main/java/net/minecraftforge/coremods/testjar/TestTarget.java deleted file mode 100644 index 931c246..0000000 --- a/coremods-test-jar/src/main/java/net/minecraftforge/coremods/testjar/TestTarget.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.coremods.testjar; - -public class TestTarget { - public static void testCallout() { - System.out.println("Hello from callout"); - } -} diff --git a/coremods-test/build.gradle b/coremods-test/build.gradle index d80dfed..50e0d17 100644 --- a/coremods-test/build.gradle +++ b/coremods-test/build.gradle @@ -1,9 +1,10 @@ plugins { - id 'net.minecraftforge.licenser' version '1.0.1' id 'eclipse' id 'java-library' - id 'org.gradlex.extra-java-module-info' version '1.9' - id 'net.minecraftforge.gradleutils' version '[2.1.3,2.3.0)' + alias libs.plugins.license + alias libs.plugins.modules + //alias libs.plugins.versions + alias libs.plugins.gradleutils } repositories { @@ -23,17 +24,25 @@ license { test { useJUnitPlatform() - reports.html.destination = rootProject.file("build/reports/") - reports.junitXml.destination = rootProject.file("build/test-results/") + reports.html.outputLocation = rootProject.file("build/reports/") + reports.junitXml.outputLocation = rootProject.file("build/test-results/") } test { - exclude '**/*' + //exclude '**/*' useJUnitPlatform() } compileTestJava { - exclude '**/*' + //exclude '**/*' +} + +sourceSets { + test { + resources { + srcDir 'src/test/javascript/' + } + } } dependencies { @@ -42,6 +51,7 @@ dependencies { testImplementation(libs.junit.api) testImplementation(libs.log4j.api) testImplementation(libs.modlauncher) + testImplementation(libs.securemodules) testImplementation(libs.forgespi) testImplementation(libs.unsafe) testRuntimeOnly(libs.bundles.junit.runtime) @@ -66,28 +76,30 @@ if (project.hasProperty('javaVendor') && project.hasProperty('javaVersion')) { } dependencies { - groovyScript 'org.apache.ivy:ivy:2.4.0' - groovyScript 'org.codehaus.groovy:groovy-all:3.0.19' + groovyScript libs.ivy + groovyScript libs.groovy } tasks.register('collectTests', JavaExec) { classpath = configurations.groovyScript - main = 'groovy.ui.GroovyMain' + mainClass = 'groovy.ui.GroovyMain' args '.github/workflows/aggregate-junit-tests.groovy' workingDir rootProject.projectDir } - VALID_VMS.each { javaVendor, javaVersions -> - javaVersions.each { javaVersion -> - def task = tasks.register("test${javaVendor}${javaVersion}", Test) { + ((Map>) VALID_VMS).forEach { javaVendor, javaVersions -> + for (Integer javaVersion in javaVersions) { + var task = tasks.register("test${javaVendor}${javaVersion}", Test) { + testClassesDirs = testing.suites.test.sources.output.classesDirs + classpath = testing.suites.test.sources.runtimeClasspath useJUnitPlatform() - javaLauncher.set(javaToolchains.launcherFor { - it.vendor.set(JvmVendorSpec."${javaVendor.toUpperCase(Locale.ROOT)}" as JvmVendorSpec) - it.languageVersion.set(JavaLanguageVersion.of(javaVersion)) - it.implementation.set(JvmImplementation.VENDOR_SPECIFIC) - }) - reports.html.destination = rootProject.file("build/test_artifacts/test-reports-${javaVendor}-${javaVersion}/") - reports.junitXml.destination = rootProject.file("build/test_artifacts/test-results-${javaVendor}-${javaVersion}/") + javaLauncher = javaToolchains.launcherFor { + vendor = JvmVendorSpec."${javaVendor.toUpperCase(Locale.ROOT)}" as JvmVendorSpec + languageVersion = JavaLanguageVersion.of(javaVersion) + implementation = JvmImplementation.VENDOR_SPECIFIC + } + reports.html.outputLocation = rootProject.file("build/test_artifacts/test-reports-${javaVendor}-${javaVersion}/") + reports.junitXml.outputLocation = rootProject.file("build/test_artifacts/test-results-${javaVendor}-${javaVersion}/") } test.dependsOn(task) collectTests.mustRunAfter(task) diff --git a/coremods-test/src/test/java/module-info.java b/coremods-test/src/test/java/module-info.java index 558b200..8e47ba0 100644 --- a/coremods-test/src/test/java/module-info.java +++ b/coremods-test/src/test/java/module-info.java @@ -2,15 +2,17 @@ * Copyright (c) Forge Development LLC * SPDX-License-Identifier: LGPL-2.1-only */ -module net.minecraftforge.coremods.test { +open module net.minecraftforge.coremods.test { requires cpw.mods.modlauncher; requires net.minecraftforge.forgespi; requires net.minecraftforge.coremod; requires org.junit.jupiter.api; requires org.apache.logging.log4j; requires org.objectweb.asm.tree; - requires org.jetbrains.annotations; + requires static org.jetbrains.annotations; requires net.minecraftforge.unsafe; + requires static net.minecraftforge.coremod.testjar; + requires cpw.mods.securejarhandler; provides cpw.mods.modlauncher.api.ITransformationService with net.minecraftforge.coremod.test.TestTransformerService; diff --git a/coremods-test/src/test/java/net/minecraftforge/coremod/test/ArmsLengthHandler.java b/coremods-test/src/test/java/net/minecraftforge/coremod/test/ArmsLengthHandler.java deleted file mode 100644 index 63f4a76..0000000 --- a/coremods-test/src/test/java/net/minecraftforge/coremod/test/ArmsLengthHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ -package net.minecraftforge.coremod.test; - -import org.apache.logging.log4j.LogManager; - -import java.util.concurrent.Callable; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -public class ArmsLengthHandler implements Callable { - @Override - public Void call() throws Exception { - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - LogManager.getLogger().info("CCL is {}", contextClassLoader); - final Class testClass = Class.forName("net.minecraftforge.coremods.testjar.TestClass", true, contextClassLoader); - assertFalse((boolean)testClass.getMethod("testMethod").invoke(null)); - - boolean result = (boolean)testClass.getMethod("testInsert").invoke(null); - assertFalse(result); - final Class redirectClass = Class.forName("net.minecraftforge.coremods.testjar.RedirectClass", true, contextClassLoader); - assertEquals(1, (int) redirectClass.getMethod("getAfterCallCount").invoke(null)); - assertEquals(1, (int) redirectClass.getMethod("getBeforeCallCount").invoke(null)); - return null; - } -} diff --git a/coremods-test/src/test/java/net/minecraftforge/coremod/test/CoreModTest.java b/coremods-test/src/test/java/net/minecraftforge/coremod/test/CoreModTest.java deleted file mode 100644 index ee3b420..0000000 --- a/coremods-test/src/test/java/net/minecraftforge/coremod/test/CoreModTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ -package net.minecraftforge.coremod.test; - -import net.minecraftforge.coremod.CoreModEngine; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.stream.Collectors; - -import net.minecraftforge.forgespi.coremod.ICoreModFile; -import net.minecraftforge.unsafe.UnsafeHacks; -import org.junit.jupiter.api.Test; -import org.objectweb.asm.tree.ClassNode; - -import cpw.mods.modlauncher.api.ITransformer; - -public class CoreModTest { - - @SuppressWarnings("unchecked") - @Test - void testJSLoading() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - final CoreModEngine coreModEngine = new CoreModEngine(); - var loadCoreMod = coreModEngine.getClass().getMethod("loadCoreMod", ICoreModFile.class); - UnsafeHacks.setAccessible(loadCoreMod); - loadCoreMod.invoke(coreModEngine, new JSFileLoader("src/test/javascript/testcoremod.js")); - loadCoreMod.invoke(coreModEngine, new JSFileLoader("src/test/javascript/testcore2mod.js")); - loadCoreMod.invoke(coreModEngine, new JSFileLoader("src/test/javascript/testdata.js")); - final List> iTransformers = coreModEngine.initializeCoreMods(); - iTransformers.forEach(t -> { - System.out.printf("targ: %s\n", t.targets().stream().map(ITransformer.Target::getClassName).collect(Collectors.joining(","))); - ClassNode cn = new ClassNode(); - cn.name = "HelloWorld"; - ClassNode newcn = ((ITransformer)t).transform(cn, null); - System.out.println(newcn.methods.stream().map(m->m.name).collect(Collectors.joining(","))); - }); - } -} diff --git a/coremods-test/src/test/java/net/minecraftforge/coremod/test/CoreModTests.java b/coremods-test/src/test/java/net/minecraftforge/coremod/test/CoreModTests.java new file mode 100644 index 0000000..8268a62 --- /dev/null +++ b/coremods-test/src/test/java/net/minecraftforge/coremod/test/CoreModTests.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ +package net.minecraftforge.coremod.test; + +import org.junit.jupiter.api.Test; + +import net.minecraftforge.coremod.testjar.TestClass; + +import static org.junit.jupiter.api.Assertions.*; + +public class CoreModTests extends TestLaunchTransformerBase { + + @Test + public void testModifyMethod() throws Exception { + loadCoremod("test_method_manual.js"); + + if (!isTransformed()) return; + + // Manually iterates the instructions and replace CONST_0 with CONST_1 + assertTrue(TestClass.False(), "Transformer failed"); + } + + @Test + public void testInsertRemove() throws Exception { + loadCoremod("test_insert_remove.js"); + + if (!isTransformed()) return; + + // Replaces the push() with increment(), which will make the return {1} + assertArrayEquals(new int[]{1}, TestClass.testCounter(), "Transformer failed"); + } + + @Test + public void testInsertBefore() throws Exception { + loadCoremod("test_insert_before.js"); + + if (!isTransformed()) return; + + // Inserts increment() before the push() call, which will make the return {1, 0} + assertArrayEquals(new int[]{1, 0}, TestClass.testCounter(), "Transformer failed"); + } + + @Test + public void testInsertAfter() throws Exception { + loadCoremod("test_insert_after.js"); + + if (!isTransformed()) return; + + // Inserts increment() after the push() call, which will make the return {0, 1} + assertArrayEquals(new int[]{0, 1}, TestClass.testCounter(), "Transformer failed"); + } + + @Test + public void testLoadData() throws Exception { + loadCoremod("test_load_data.js"); + + if (!isTransformed()) return; + + // Loads a json file containing a string + assertEquals("transformed", TestClass.testString(), "Transformer failed"); + } + + @Test + public void testLoadFile() throws Exception { + loadCoremod("test_load_file.js"); + + if (!isTransformed()) return; + + // Loads a javascript file and uses a function from it + assertEquals("transformed", TestClass.testString(), "Transformer failed"); + } +} diff --git a/coremods-test/src/test/java/net/minecraftforge/coremod/test/JSFileLoader.java b/coremods-test/src/test/java/net/minecraftforge/coremod/test/JSFileLoader.java index 0af01aa..de96f77 100644 --- a/coremods-test/src/test/java/net/minecraftforge/coremod/test/JSFileLoader.java +++ b/coremods-test/src/test/java/net/minecraftforge/coremod/test/JSFileLoader.java @@ -8,7 +8,7 @@ import java.io.IOException; import java.io.Reader; -import java.nio.file.FileSystems; +import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; @@ -16,7 +16,7 @@ class JSFileLoader implements ICoreModFile { private final Path path; JSFileLoader(final String path) { - this.path = FileSystems.getDefault().getPath(path); + this.path = getPathFromResource(path); } @Override @@ -42,4 +42,22 @@ public Reader getAdditionalFile(final String fileName) throws IOException { public String getOwnerId() { return "dummy"; } + + protected static Path getPathFromResource(String resource) { + var cl = JSFileLoader.class.getClassLoader(); + var url = cl.getResource(resource); + if (url == null) + throw new IllegalStateException("Could not find " + resource + " in classloader " + cl); + + try { + return Path.of(url.toURI()); + } catch (URISyntaxException e) { + return sneak(e); + } + } + + @SuppressWarnings("unchecked") + private static R sneak(Throwable e) throws E { + throw (E)e; + } } diff --git a/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestLaunchTransformer.java b/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestLaunchTransformer.java deleted file mode 100644 index 5b42445..0000000 --- a/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestLaunchTransformer.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ -package net.minecraftforge.coremod.test; - -import cpw.mods.modlauncher.Launcher; -import cpw.mods.modlauncher.TransformingClassLoader; -import cpw.mods.modlauncher.api.ITransformer; -import net.minecraftforge.coremod.CoreModEngine; - -import net.minecraftforge.forgespi.coremod.ICoreModFile; -import net.minecraftforge.unsafe.UnsafeHacks; -import org.junit.jupiter.api.Test; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.concurrent.Callable; - -public class TestLaunchTransformer { - private static CoreModEngine cme = new CoreModEngine(); - public static List> getTransformers() { - return cme.initializeCoreMods(); - } - - @Test - public void testCoreModLoading() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - System.setProperty("test.harness", "out/production/classes,out/test/classes,out/testJars/classes,build/classes/java/main,build/classes/java/test,build/classes/java/testJars"); - System.setProperty("test.harness.callable", "net.minecraftforge.coremod.test.TestLaunchTransformer$Callback"); - - var loadCoreMod = cme.getClass().getMethod("loadCoreMod", ICoreModFile.class); - UnsafeHacks.setAccessible(loadCoreMod); - loadCoreMod.invoke(cme, new JSFileLoader("src/test/javascript/testcoremod.js")); - loadCoreMod.invoke(cme, new JSFileLoader("src/test/javascript/testcore2mod.js")); - loadCoreMod.invoke(cme, new JSFileLoader("src/test/javascript/testmethodcoremod.js")); - loadCoreMod.invoke(cme, new JSFileLoader("src/test/javascript/testmethodcoreinsert.js")); - - Launcher.main("--version", "1.0", "--launchTarget", "testharness"); - } - - public static class Callback { - @SuppressWarnings("unchecked") - public static Callable supplier() { - final TransformingClassLoader contextClassLoader = (TransformingClassLoader) Thread.currentThread().getContextClassLoader(); - try { - final Class clazz = Class.forName("net.minecraftforge.coremod.test.ArmsLengthHandler", true, contextClassLoader); - return (Callable) clazz.newInstance(); - } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { - throw new RuntimeException(e); - } - } - } -} diff --git a/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestLaunchTransformerBase.java b/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestLaunchTransformerBase.java new file mode 100644 index 0000000..7b5228a --- /dev/null +++ b/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestLaunchTransformerBase.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ +package net.minecraftforge.coremod.test; + +import cpw.mods.modlauncher.Launcher; +import cpw.mods.modlauncher.api.ITransformer; +import cpw.mods.modlauncher.api.ServiceRunner; +import net.minecraftforge.coremod.CoreModEngine; +import net.minecraftforge.coremod.testjar.TestMarker; +import net.minecraftforge.forgespi.coremod.ICoreModFile; +import net.minecraftforge.securemodules.SecureModuleClassLoader; +import net.minecraftforge.unsafe.UnsafeHacks; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInfo; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.nio.file.Path; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +public class TestLaunchTransformerBase { + private static final String CLASS_NAME = "test.class"; + private static final String METHOD_NAME = "test.method"; + private static final String TRANSFORMED = "test.transformed"; + + private static CoreModEngine cme; + public static List> getTransformers() { + return cme.initializeCoreMods(); + } + + protected static BiConsumer LOAD_CORE_MOD = getLoadCoreMod(); + protected static Runnable RELAUNCH = getRelaunch(); + + @BeforeEach + public void setup(TestInfo testInfo) { + System.setProperty(CLASS_NAME, testInfo.getTestClass().get().getName()); + System.setProperty(METHOD_NAME, testInfo.getTestMethod().get().getName()); + cme = new CoreModEngine(); + } + + @AfterEach + public void teardown() { + System.clearProperty(CLASS_NAME); + System.clearProperty(METHOD_NAME); + cme = null; + } + + protected static BiConsumer getLoadCoreMod() { + try { + var loadCoreMod = CoreModEngine.class.getDeclaredMethod("loadCoreMod", ICoreModFile.class); + UnsafeHacks.setAccessible(loadCoreMod); + return (engine, name) -> { + try { + loadCoreMod.invoke(engine, new JSFileLoader(name)); + } catch (Throwable e) { + sneak(e); + } + }; + } catch (Throwable e) { + return sneak(e); + } + } + + protected static Runnable getRelaunch() { + try { + // Bypass some logging, if log4j.xml doesn't override, cuz it feels like being stupid. + var ctr = Launcher.class.getDeclaredConstructor(); + UnsafeHacks.setAccessible(ctr); + var run = Launcher.class.getDeclaredMethod("run", String[].class); + UnsafeHacks.setAccessible(run); + return () -> { + try { + run.invoke(ctr.newInstance(), (Object)new String[] {"--version", "1.0", "--launchTarget", "testharness"}); + } catch (Throwable e) { + sneak(e); + } + }; + } catch (Throwable e) { + return sneak(e); + } + } + + protected void loadCoremod(String name) { + if (!getTransformed()) + LOAD_CORE_MOD.accept(cme, name); + } + + private static final String getPath(Class clz) { + try { + return Path.of(clz.getProtectionDomain().getCodeSource().getLocation().toURI()).toAbsolutePath().toString(); + } catch (Throwable e) { + return sneak(e); + } + } + + protected boolean isTransformed() { + if (getTransformed()) + return true; + + var jars = List.of( + getPath(TestTransformerService.class), + getPath(TestMarker.class) + ); + + System.setProperty("test.harness.game", jars.stream().collect(Collectors.joining(","))); + System.setProperty("test.harness.callable", Callback.class.getName()); + + try { + System.setProperty(TRANSFORMED, "true"); + System.out.println(System.getProperty(CLASS_NAME) + "." + System.getProperty(METHOD_NAME)); + RELAUNCH.run(); + } catch (Throwable e) { + sneak(e); + } finally { + System.clearProperty(TRANSFORMED); + } + + return false; + } + + @SuppressWarnings("unchecked") + protected Class getTransformedClass(String name) { + var ccl = Thread.currentThread().getContextClassLoader(); + Assertions.assertInstanceOf(SecureModuleClassLoader.class, ccl, "ContextClassLoader is not TransformingClassLoader"); + try { + return (Class) Class.forName(name, false, ccl); + } catch (Throwable e) { + return sneak(e); + } + } + + private boolean getTransformed() { + return System.getProperty(TRANSFORMED) != null; + } + + public static final class Callback { + public static ServiceRunner supplier() { + return () -> { + try { + var ccl = Thread.currentThread().getContextClassLoader(); + var cls = Class.forName(System.getProperty(CLASS_NAME), true, ccl); + var inst = cls.getDeclaredConstructor().newInstance(); + var handle = MethodHandles.lookup().findVirtual(cls, System.getProperty(METHOD_NAME), MethodType.methodType(void.class)); + handle.invoke(inst); + } catch (Throwable e) { + sneak(e); + } + }; + } + } + + @SuppressWarnings("unchecked") + private static R sneak(Throwable e) throws E { + throw (E)e; + } +} diff --git a/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestTransformerService.java b/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestTransformerService.java index e00a824..d6f36cc 100644 --- a/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestTransformerService.java +++ b/coremods-test/src/test/java/net/minecraftforge/coremod/test/TestTransformerService.java @@ -4,19 +4,19 @@ */ package net.minecraftforge.coremod.test; +import cpw.mods.jarhandling.SecureJar; import cpw.mods.modlauncher.api.IEnvironment; +import cpw.mods.modlauncher.api.IModuleLayerManager; import cpw.mods.modlauncher.api.ITransformationService; import cpw.mods.modlauncher.api.ITransformer; import cpw.mods.modlauncher.api.IncompatibleEnvironmentException; import org.jetbrains.annotations.NotNull; - +import java.nio.file.FileSystems; +import java.util.Arrays; import java.util.List; import java.util.Set; public class TestTransformerService implements ITransformationService { - - private List> transformers; - @NotNull @Override public String name() { @@ -27,21 +27,48 @@ public String name() { public void initialize(final IEnvironment environment) { } - @Override - public List beginScanning(final IEnvironment environment) { - return List.of(); - } - @Override public void onLoad(final IEnvironment env, final Set otherServices) throws IncompatibleEnvironmentException { - } @SuppressWarnings({ "rawtypes", "unchecked" }) @NotNull @Override public List transformers() { - transformers = TestLaunchTransformer.getTransformers(); - return (List)transformers; + return (List)TestLaunchTransformerBase.getTransformers(); + } + + @SuppressWarnings("resource") + @Override + public List beginScanning(IEnvironment environment) { + if (System.getProperty("test.harness.plugin")!=null) { + return List.of(new Resource(IModuleLayerManager.Layer.PLUGIN, + Arrays.stream(System.getProperty("test.harness.plugin").split(",")) + .map(FileSystems.getDefault()::getPath) + .map(SecureJar::from) + .toList())); + } else if (System.getProperty("test.harness.service")!=null) { + return List.of(new Resource(IModuleLayerManager.Layer.SERVICE, + Arrays.stream(System.getProperty("test.harness.service").split(",")) + .map(FileSystems.getDefault()::getPath) + .map(SecureJar::from) + .toList())); + } else { + return List.of(); + } + } + + @SuppressWarnings("resource") + @Override + public List completeScan(IModuleLayerManager layerManager) { + if (System.getProperty("test.harness.game")!=null) { + return List.of(new Resource(IModuleLayerManager.Layer.GAME, + Arrays.stream(System.getProperty("test.harness.game").split(",")) + .map(FileSystems.getDefault()::getPath) + .map(SecureJar::from) + .toList())); + } else { + return List.of(); + } } } diff --git a/coremods-test/src/test/javascript/test_insert_after.js b/coremods-test/src/test/javascript/test_insert_after.js new file mode 100644 index 0000000..0f98241 --- /dev/null +++ b/coremods-test/src/test/javascript/test_insert_after.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ +function initializeCoreMod() { + return { + 'coremodmethod': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.coremod.testjar.TestClass', + 'methodName': 'testCounter', + 'methodDesc': '()[I' + }, + 'transformer': function(method) { + var Counter = "net/minecraftforge/coremod/testjar/Counter"; + var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); + var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); + var Opcodes = Java.type('org.objectweb.asm.Opcodes'); + + var lst = ASMAPI.listOf( + new VarInsnNode(Opcodes.ALOAD, 0), + ASMAPI.buildMethodCall(Counter, "increment", "()V", ASMAPI.MethodType.VIRTUAL) + ); + + if (ASMAPI.insertInsnList(method, ASMAPI.MethodType.VIRTUAL, Counter, "push", "()V", lst, ASMAPI.InsertMode.INSERT_AFTER) === false) { + throw "MethodInsnNode for push not found!"; + } + + print("Inserted increment after push"); + + return method; + } + } + } +} \ No newline at end of file diff --git a/coremods-test/src/test/javascript/test_insert_before.js b/coremods-test/src/test/javascript/test_insert_before.js new file mode 100644 index 0000000..d8e545f --- /dev/null +++ b/coremods-test/src/test/javascript/test_insert_before.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ +function initializeCoreMod() { + return { + 'coremodmethod': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.coremod.testjar.TestClass', + 'methodName': 'testCounter', + 'methodDesc': '()[I' + }, + 'transformer': function(method) { + var Counter = "net/minecraftforge/coremod/testjar/Counter"; + var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); + var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); + var Opcodes = Java.type('org.objectweb.asm.Opcodes'); + + var lst = ASMAPI.listOf( + ASMAPI.buildMethodCall(Counter, "increment", "()V", ASMAPI.MethodType.VIRTUAL), + new VarInsnNode(Opcodes.ALOAD, 0) + ); + + if (ASMAPI.insertInsnList(method, ASMAPI.MethodType.VIRTUAL, Counter, "push", "()V", lst, ASMAPI.InsertMode.INSERT_BEFORE) === false) { + throw "MethodInsnNode for push not found!"; + } + + print("Inserted increment before push"); + + return method; + } + } + } +} \ No newline at end of file diff --git a/coremods-test/src/test/javascript/test_insert_remove.js b/coremods-test/src/test/javascript/test_insert_remove.js new file mode 100644 index 0000000..20e5609 --- /dev/null +++ b/coremods-test/src/test/javascript/test_insert_remove.js @@ -0,0 +1,33 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ +function initializeCoreMod() { + return { + 'coremodmethod': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.coremod.testjar.TestClass', + 'methodName': 'testCounter', + 'methodDesc': '()[I' + }, + 'transformer': function(method) { + var Counter = "net/minecraftforge/coremod/testjar/Counter"; + var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); + var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); + var Opcodes = Java.type('org.objectweb.asm.Opcodes'); + + var lst = ASMAPI.listOf( + ASMAPI.buildMethodCall(Counter, "increment", "()V", ASMAPI.MethodType.VIRTUAL) + ); + + if (ASMAPI.insertInsnList(method, ASMAPI.MethodType.VIRTUAL, Counter, "push", "()V", lst, ASMAPI.InsertMode.REMOVE_ORIGINAL) === false) { + throw "MethodInsnNode for push not found!"; + } + print("Replaced push with increment"); + + return method; + } + } + } +} \ No newline at end of file diff --git a/coremods-test/src/test/javascript/test_load_data.js b/coremods-test/src/test/javascript/test_load_data.js new file mode 100644 index 0000000..767359b --- /dev/null +++ b/coremods-test/src/test/javascript/test_load_data.js @@ -0,0 +1,39 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ +function initializeCoreMod() { + var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); + // Why is this arbitrarily limited to being loaded at start? + var data = ASMAPI.loadData('test_load_data.json') + if (data == null) + throw "Could not load data"; + + return { + 'coremodmethod': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.coremod.testjar.TestClass', + 'methodName': 'testString', + 'methodDesc': '()Ljava/lang/String;' + }, + 'transformer': function(method) { + var Opcodes = Java.type('org.objectweb.asm.Opcodes'); + var LdcInsnNode = Java.type('org.objectweb.asm.tree.LdcInsnNode'); + + var arrayLength = method.instructions.size(); + for (var i = 0; i < arrayLength; ++i) { + var instruction = method.instructions.get(i); + if (instruction.getOpcode() == Opcodes.LDC) { + var newInstruction = new LdcInsnNode(data.value); + method.instructions.insertBefore(instruction, newInstruction); + method.instructions.remove(instruction); + print("Manually replaced string with " + data.value); + break; + } + } + return method; + } + } + } +} \ No newline at end of file diff --git a/coremods-test/src/test/javascript/test_load_data.json b/coremods-test/src/test/javascript/test_load_data.json new file mode 100644 index 0000000..8d6e0e1 --- /dev/null +++ b/coremods-test/src/test/javascript/test_load_data.json @@ -0,0 +1,3 @@ +{ + "value": "transformed" +} \ No newline at end of file diff --git a/coremods-test/src/test/javascript/test_load_file.js b/coremods-test/src/test/javascript/test_load_file.js new file mode 100644 index 0000000..c829a29 --- /dev/null +++ b/coremods-test/src/test/javascript/test_load_file.js @@ -0,0 +1,38 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ +function initializeCoreMod() { + var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); + // Why is this arbitrarily limited to being loaded at start? + if (!ASMAPI.loadFile('test_load_file_extra.js')) + throw "Could not load extra script"; + + return { + 'coremodmethod': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraftforge.coremod.testjar.TestClass', + 'methodName': 'testString', + 'methodDesc': '()Ljava/lang/String;' + }, + 'transformer': function(method) { + var Opcodes = Java.type('org.objectweb.asm.Opcodes'); + var LdcInsnNode = Java.type('org.objectweb.asm.tree.LdcInsnNode'); + + var arrayLength = method.instructions.size(); + for (var i = 0; i < arrayLength; ++i) { + var instruction = method.instructions.get(i); + if (instruction.getOpcode() == Opcodes.LDC) { + var newInstruction = new LdcInsnNode(extraFunction()); + method.instructions.insertBefore(instruction, newInstruction); + method.instructions.remove(instruction); + print("Manually replaced string with " + extraFunction()); + break; + } + } + return method; + } + } + } +} \ No newline at end of file diff --git a/coremods-test/src/test/javascript/testcoremod2.js b/coremods-test/src/test/javascript/test_load_file_extra.js similarity index 56% rename from coremods-test/src/test/javascript/testcoremod2.js rename to coremods-test/src/test/javascript/test_load_file_extra.js index 55edd91..564dc7f 100644 --- a/coremods-test/src/test/javascript/testcoremod2.js +++ b/coremods-test/src/test/javascript/test_load_file_extra.js @@ -2,6 +2,6 @@ * Copyright (c) Forge Development LLC * SPDX-License-Identifier: LGPL-2.1-only */ -function moreFunctions() { - print("Poopy from more functions!"); +function extraFunction() { + return "transformed"; } \ No newline at end of file diff --git a/coremods-test/src/test/javascript/testmethodcoremod.js b/coremods-test/src/test/javascript/test_method_manual.js similarity index 84% rename from coremods-test/src/test/javascript/testmethodcoremod.js rename to coremods-test/src/test/javascript/test_method_manual.js index 5b9ead2..a9a379e 100644 --- a/coremods-test/src/test/javascript/testmethodcoremod.js +++ b/coremods-test/src/test/javascript/test_method_manual.js @@ -7,8 +7,8 @@ function initializeCoreMod() { 'coremodmethod': { 'target': { 'type': 'METHOD', - 'class': 'net.minecraftforge.coremods.testjar.TestClass', - 'methodName': 'testMethod', + 'class': 'net.minecraftforge.coremod.testjar.TestClass', + 'methodName': 'False', 'methodDesc': '()Z' }, 'transformer': function(method) { @@ -16,12 +16,12 @@ function initializeCoreMod() { var arrayLength = method.instructions.size(); for (var i = 0; i < arrayLength; ++i) { var instruction = method.instructions.get(i); - if (instruction.getOpcode() == Opcodes.ICONST_1) { + if (instruction.getOpcode() == Opcodes.ICONST_0) { var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode'); - var newInstruction = new InsnNode(Opcodes.ICONST_0); + var newInstruction = new InsnNode(Opcodes.ICONST_1); method.instructions.insertBefore(instruction, newInstruction); method.instructions.remove(instruction); - print("Transformed!"); + print("Manually replaced false with true"); break; } } diff --git a/coremods-test/src/test/javascript/testcore2mod.js b/coremods-test/src/test/javascript/testcore2mod.js deleted file mode 100644 index c4c2074..0000000 --- a/coremods-test/src/test/javascript/testcore2mod.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ -var core2fn = function() { - print("Core2 function!"); -} -function initializeCoreMod() { - print("Core2!"); - return { - 'coremodtwo': { - 'target': { - 'type': 'CLASS', - 'names': function(listofclasses) { return [ 'cpw.mods.testtarget.Test2', 'cpw.mods.testtarget.Test3' ] } - }, - 'transformer': function(classNode) { - print("Cheese", classNode); - return classNode; - } - } - } -} \ No newline at end of file diff --git a/coremods-test/src/test/javascript/testcoremod.js b/coremods-test/src/test/javascript/testcoremod.js deleted file mode 100644 index 2607cbb..0000000 --- a/coremods-test/src/test/javascript/testcoremod.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ -function initializeCoreMod() { - print("Hello"); - Java.type('net.minecraftforge.coremod.api.ASMAPI').loadFile('testcoremod2.js') - Java.type('net.minecraftforge.coremod.api.ASMAPI').log("INFO", "HI!") - moreFunctions() - return { - 'coremodone': { - 'target': { - 'type': 'CLASS', - 'name': 'cpw.mods.testtarget.Test' - }, - 'transformer': function(classNode) { - print("Cheese ", classNode.name); - var tmp=Java.type('net.minecraftforge.coremod.api.ASMAPI').getMethodNode() - var opcodes = Java.type('org.objectweb.asm.Opcodes') - tmp.name = 'dummyMethod'; - tmp.visitVarInsn(opcodes.ALOAD, 0); - tmp.visitMethodInsn(opcodes.INVOKESTATIC, "net/minecraftforge/fml/FMLTransformers", "hackName", "()Ljava/lang/String;", false); - tmp.visitFieldInsn(opcodes.PUTFIELD, "net/minecraft/client/gui/GuiMainMenu", "field_73975_c", "Ljava/lang/String;"); - classNode.methods.add(tmp); - return classNode; - } - } - } -} diff --git a/coremods-test/src/test/javascript/testdata.js b/coremods-test/src/test/javascript/testdata.js deleted file mode 100644 index 2c991ab..0000000 --- a/coremods-test/src/test/javascript/testdata.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ -function initializeCoreMod() { - var data = Java.type('net.minecraftforge.coremod.api.ASMAPI').loadData('testdata.json') - print('Loaded JSON: ' + JSON.stringify(data)) - return {} -} diff --git a/coremods-test/src/test/javascript/testdata.json b/coremods-test/src/test/javascript/testdata.json deleted file mode 100644 index 9791d4d..0000000 --- a/coremods-test/src/test/javascript/testdata.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "foo": "bar", - "a": "b" -} \ No newline at end of file diff --git a/coremods-test/src/test/javascript/testmethodcoreinsert.js b/coremods-test/src/test/javascript/testmethodcoreinsert.js deleted file mode 100644 index 3639cb1..0000000 --- a/coremods-test/src/test/javascript/testmethodcoreinsert.js +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-2.1-only - */ -function initializeCoreMod() { - return { - 'coremodmethod': { - 'target': { - 'type': 'METHOD', - 'class': 'net.minecraftforge.coremods.testjar.TestClass', - 'methodName': 'testInsert', - 'methodDesc': '()Z' - }, - 'transformer': function(method) { - var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); - var newList1 = ASMAPI.listOf(ASMAPI.buildMethodCall("cpw/mods/RedirectClass", "newMethod", "()Z", ASMAPI.MethodType.STATIC)); - if (ASMAPI.insertInsnList(method, ASMAPI.MethodType.STATIC, "cpw/mods/TestClass", "testMethod2", "()Z", newList1, ASMAPI.InsertMode.REMOVE_ORIGINAL) === false) { - throw "MethodInsnNode for testMethod2 not found!"; - } - - var newList2 = ASMAPI.listOf(ASMAPI.buildMethodCall("cpw/mods/RedirectClass", "afterMethod", "()V", ASMAPI.MethodType.STATIC)); - if (ASMAPI.insertInsnList(method, ASMAPI.MethodType.STATIC, "cpw/mods/TestClass", "testMethod1", "()J", newList2, ASMAPI.InsertMode.INSERT_AFTER) === false) { - throw "MethodInsnNode for insert after on testMethod1 not found!"; - } - - var newList3 = ASMAPI.listOf(ASMAPI.buildMethodCall("cpw/mods/RedirectClass", "beforeMethod", "()V", ASMAPI.MethodType.STATIC)); - if (ASMAPI.insertInsnList(method, ASMAPI.MethodType.STATIC, "cpw/mods/TestClass", "testMethod1", "()J", newList3, ASMAPI.InsertMode.INSERT_BEFORE) === false) { - throw "MethodInsnNode for insert before on testMethod1 not found!"; - } - - print("Redirects added!") - return method; - } - } - } -} \ No newline at end of file diff --git a/coremods-test/src/test/resources/log4j2.xml b/coremods-test/src/test/resources/log4j2.xml new file mode 100644 index 0000000..7eec6f7 --- /dev/null +++ b/coremods-test/src/test/resources/log4j2.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/gradle.properties b/gradle.properties index aec0a55..415d879 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,4 @@ org.gradle.caching=true org.gradle.parallel=true +org.gradle.configuration-cache=true +org.gradle.configureondemand=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135..a4b76b9 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 df97d72..cea7a79 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4..f5feea6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..9d21a21 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/settings.gradle b/settings.gradle index 24c5796..6ebc662 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,17 +12,22 @@ plugins { dependencyResolutionManagement { versionCatalogs { libs { + plugin('license', 'net.minecraftforge.licenser').version('1.0.1') + plugin('gradleutils', 'net.minecraftforge.gradleutils').version('[2.3,2.4)') + plugin('modules', 'org.gradlex.extra-java-module-info').version('1.9') + plugin('versions', 'com.github.ben-manes.versions').version('0.51.0') + version('asm', '9.7.1') library('asm', 'org.ow2.asm', 'asm' ).versionRef('asm') library('asm-tree', 'org.ow2.asm', 'asm-tree' ).versionRef('asm') library('asm-commons', 'org.ow2.asm', 'asm-commons').versionRef('asm') bundle('asm', ['asm', 'asm-tree', 'asm-commons']) - version('junit', '5.10.0') - library('junit-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit') - library('junit-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit') - library('junit-platform-launcher', 'org.junit.platform:junit-platform-launcher:1.10.0') - bundle('junit-runtime', ['junit-engine', 'junit-platform-launcher']) + version('junit', '5.11.4') + library('junit-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit') + library('junit-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit') + library('junit-platform-launcher', 'org.junit.platform:junit-platform-launcher:1.11.4') + bundle('junit-runtime', ['junit-engine', 'junit-platform-launcher']) library('unsafe', 'net.minecraftforge:unsafe:0.9.2') library('securemodules', 'net.minecraftforge:securemodules:2.2.20') // Needs unsafe @@ -33,10 +38,14 @@ dependencyResolutionManagement { library('forgespi', 'net.minecraftforge:forgespi:7.1.0') library('modlauncher', 'net.minecraftforge:modlauncher:10.1.1') // Needs securemodules - library('nulls', 'org.jetbrains:annotations:23.0.0') + library('nulls', 'org.jetbrains:annotations:26.0.1') library('nashorn', 'org.openjdk.nashorn:nashorn-core:15.4') // Needed by coremods, because the JRE no longer ships JS - version('log4j', '2.19.0') + // Used by our test aggrigator scripts + library('ivy', 'org.apache.ivy:ivy:2.5.3') + library('groovy', 'org.codehaus.groovy:groovy-all:3.0.23') + + version('log4j', '2.17.0') // Needs to be kept in step with modlauncher because of its config.. TODO: Figure out why? library('log4j-api', 'org.apache.logging.log4j', 'log4j-api' ).versionRef('log4j') library('log4j-core', 'org.apache.logging.log4j', 'log4j-core').versionRef('log4j') } diff --git a/src/main/java/net/minecraftforge/coremod/CoreMod.java b/src/main/java/net/minecraftforge/coremod/CoreMod.java index 8ff0a08..5a9086c 100644 --- a/src/main/java/net/minecraftforge/coremod/CoreMod.java +++ b/src/main/java/net/minecraftforge/coremod/CoreMod.java @@ -41,6 +41,7 @@ public class CoreMod { * * @see ASMAPI#log(String, String, Object...) */ + @SuppressWarnings("exports") public static final Marker COREMODLOG = MarkerManager.getMarker("COREMODLOG").addParents(MarkerManager.getMarker("COREMOD")); private final ICoreModFile file; @@ -139,6 +140,7 @@ public Exception getError() { * * @return The coremod file */ + @SuppressWarnings("exports") public ICoreModFile getFile() { return this.file; } diff --git a/src/main/java/net/minecraftforge/coremod/CoreModEngine.java b/src/main/java/net/minecraftforge/coremod/CoreModEngine.java index 710ab5c..1fd0109 100644 --- a/src/main/java/net/minecraftforge/coremod/CoreModEngine.java +++ b/src/main/java/net/minecraftforge/coremod/CoreModEngine.java @@ -72,13 +72,18 @@ public class CoreModEngine { * @see net.minecraftforge.coremod.api.ASMAPI#findFirstInstructionBefore(org.objectweb.asm.tree.MethodNode, int, * int) */ - public static final boolean DO_NOT_FIX_INSNBEFORE; + public static final boolean DO_NOT_FIX_INSNBEFORE = shouldntFixInsnBefore(); + + private static final boolean shouldntFixInsnBefore() { + if (Launcher.INSTANCE == null) + return false; - static { var blackboardVar = Launcher.INSTANCE.blackboard().get(TypesafeMap.Key.getOrCreate(Launcher.INSTANCE.blackboard(), "coremods.use_old_findFirstInstructionBefore", Boolean.class)); - if (DO_NOT_FIX_INSNBEFORE = blackboardVar.isPresent() && blackboardVar.get()) { + if (blackboardVar.isPresent() && blackboardVar.get()) { LOGGER.debug("CoreMods will preserve legacy behavior of ASMAPI.findFirstInstructionBefore for backwards-compatibility"); + return true; } + return false; } void loadCoreMod(ICoreModFile coremod) { diff --git a/src/main/java/net/minecraftforge/coremod/CoreModProvider.java b/src/main/java/net/minecraftforge/coremod/CoreModProvider.java index f28b06e..a71e201 100644 --- a/src/main/java/net/minecraftforge/coremod/CoreModProvider.java +++ b/src/main/java/net/minecraftforge/coremod/CoreModProvider.java @@ -16,6 +16,7 @@ public class CoreModProvider implements ICoreModProvider { private final CoreModEngine engine = new CoreModEngine(); + @SuppressWarnings("exports") @Override public void addCoreMod(final ICoreModFile file) { this.engine.loadCoreMod(file); diff --git a/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java b/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java index 4899cfe..b046368 100644 --- a/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java +++ b/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java @@ -31,7 +31,7 @@ * to prevent boilerplate code, excessive imports, unnecessary loops, and to provide a more user-friendly API for * coremod developers. */ -@SuppressWarnings("unused") // annoying IDE warnings +@SuppressWarnings({"unused", "exports"}) // annoying IDE warnings public class ASMAPI { /* BUILDING INSTRUCTION LISTS */