Skip to content

Commit

Permalink
Fix fabric runtime remapper and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lukebemish committed Jan 15, 2024
1 parent ccc84ba commit f4b9dec
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class VisitingOpenProcessor extends ClassVisitor implements OpenProcessor

public static void main(String[] args) {
if ((~args.length & 1) != 1) {
System.err.println("Usage: java dev.lukebemish.opensesame.compile.asm.Processor <input> <output> <input> <output> ...");
System.err.println("Usage: java dev.lukebemish.opensesame.compile.asm.VisitingOpenProcessor <input> <output> <input> <output> ...");
System.exit(1);
}
for (int i = 0; i < args.length; i += 2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,17 @@
import net.fabricmc.loader.api.FabricLoader;
import org.jetbrains.annotations.Nullable;

import java.lang.invoke.MethodType;

@AutoService(RuntimeRemapper.class)
public class FabricRuntimeRemapper implements RuntimeRemapper {
private static final String TARGET_NAMESPACE = "intermediary";
private static final String SOURCE_NAMESPACE = "intermediary";
@Override
public @Nullable String remapMethodName(Class<?> parent, String name, Class<?>[] args, Class<?> returnType) {
try {
var originalClassName = FabricLoader.getInstance().getMappingResolver().unmapClassName(TARGET_NAMESPACE, parent.getName());
StringBuilder methodDesc = new StringBuilder("(");
for (var arg : args) {
methodDesc.append(classToDesc(arg));
}
methodDesc.append(")");
methodDesc.append(classToDesc(returnType));
var newName = FabricLoader.getInstance().getMappingResolver().mapMethodName(TARGET_NAMESPACE, originalClassName, name, methodDesc.toString());
var originalClassName = FabricLoader.getInstance().getMappingResolver().unmapClassName(SOURCE_NAMESPACE, parent.getName());
var methodDesc = MethodType.methodType(returnType, args).descriptorString();
var newName = FabricLoader.getInstance().getMappingResolver().mapMethodName(SOURCE_NAMESPACE, originalClassName, name, methodDesc);
if (!newName.equals(name))
return newName;
} catch (Exception ignored) {}
Expand All @@ -28,9 +25,9 @@ public class FabricRuntimeRemapper implements RuntimeRemapper {
@Override
public @Nullable String remapFieldName(Class<?> parent, String name, Class<?> type) {
try {
var originalClassName = FabricLoader.getInstance().getMappingResolver().unmapClassName(TARGET_NAMESPACE, parent.getName());
var originalClassName = FabricLoader.getInstance().getMappingResolver().unmapClassName(SOURCE_NAMESPACE, parent.getName());
var fieldDesc = classToDesc(type);
var newName = FabricLoader.getInstance().getMappingResolver().mapFieldName(TARGET_NAMESPACE, originalClassName, name, fieldDesc);
var newName = FabricLoader.getInstance().getMappingResolver().mapFieldName(SOURCE_NAMESPACE, originalClassName, name, fieldDesc);
if (!newName.equals(name))
return newName;
} catch (Exception ignored) {}
Expand All @@ -40,7 +37,7 @@ public class FabricRuntimeRemapper implements RuntimeRemapper {
@Override
public @Nullable String remapClassName(String className) {
try {
var newName = FabricLoader.getInstance().getMappingResolver().mapClassName(TARGET_NAMESPACE, className);
var newName = FabricLoader.getInstance().getMappingResolver().mapClassName(SOURCE_NAMESPACE, className);
if (!newName.equals(className))
return newName;
return null;
Expand All @@ -50,17 +47,6 @@ public class FabricRuntimeRemapper implements RuntimeRemapper {
}

private String classToDesc(Class<?> type) {
if (type.isArray()) {
return "[" + classToDesc(type.getComponentType());
} else if (type.isPrimitive()) {
return type.getName();
} else {
try {
var name = FabricLoader.getInstance().getMappingResolver().unmapClassName(TARGET_NAMESPACE, type.getName());
return "L"+name.replace('.', '/')+";";
} catch (Exception e) {
return "L"+type.getName().replace('.', '/')+";";
}
}
return type.descriptorString();
}
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ nexuspublish = "1.3.0"
gradlepublish = "1.1.0"

fabric_loom = "1.5.5"
fabric_loader = "0.14.9"
fabric_loader = "0.15.4"

tinyremapper = "0.10.0"

Expand Down
19 changes: 7 additions & 12 deletions testplugin/loom/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ group='dev.lukebemish.opensesame'

java.toolchain.languageVersion.set(JavaLanguageVersion.of(17))

loom {
runs.removeAll()
}

configurations {
testSource {
canBeResolved = true
Expand Down Expand Up @@ -35,23 +39,14 @@ dependencies {
implementation 'dev.lukebemish.opensesame:opensesame-core'
implementation libs.asm.core
implementation libs.junit.api
modImplementation libs.fabric.loader
}

tasks.named('compileJava', JavaCompile).configure {
dependsOn(configurations.testSource)
source(configurations.testSource)
}

def unpackedDir = layout.buildDirectory.dir('unpacked')

tasks.register('unpackRemappedJar', Copy).configure {
dependsOn tasks.remapJar
from zipTree(tasks.remapJar.archiveFile)
into unpackedDir
}

artifacts {
add('testClasses', unpackedDir) {
builtBy tasks.unpackRemappedJar
}
}
testClasses tasks.remapJar
}
48 changes: 34 additions & 14 deletions testplugin/loom/exec/build.gradle
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import net.fabricmc.loom.task.RemapJarTask

plugins {
id 'java'
id 'fabric-loom'
}

loom {
knownIndyBsms.add 'dev/lukebemish/opensesame/runtime/OpeningMetafactory'
runs.removeAll()
}

group='dev.lukebemish.opensesame'

java.toolchain.languageVersion.set(JavaLanguageVersion.of(17))

configurations {
testModuleClasspath {
canBeResolved = true
}
testClasses {
canBeResolved = true
}
Expand All @@ -22,35 +26,51 @@ repositories {

dependencies {
minecraft 'com.mojang:minecraft:1.20.4'
mappings loom.layered {}
mappings loom.officialMojangMappings()

implementation 'dev.lukebemish.opensesame:testtargets'
testModuleClasspath 'dev.lukebemish.opensesame:testtargets'
testClasses project(path: ':loom', configuration: 'testClasses')

implementation 'dev.lukebemish.opensesame:testtargets'
implementation 'dev.lukebemish.opensesame:opensesame-core'
implementation libs.asm.core
implementation libs.junit.api

testRuntimeOnly libs.junit.engine
modImplementation libs.fabric.loader
testRuntimeOnly 'dev.lukebemish.opensesame:opensesame-fabric'
}

tasks.register('remapTestClasses', RemapJarTask).configure {
dependsOn configurations.testClasses
input.set configurations.testClasses.singleFile
targetNamespace.set 'named'
sourceNamespace.set 'intermediary'
archiveClassifier.set 'remapped'
}

tasks.register('unpackRemappedJar', Copy).configure {
dependsOn tasks.remapTestClasses
from zipTree(tasks.remapTestClasses.archiveFile)
into layout.buildDirectory.dir('unpacked')
}

test {
useJUnitPlatform()
useJUnitPlatform {
excludeTags 'modules'
}

testLogging {
showStandardStreams = true
exceptionFormat = 'full'
events = ['passed', 'failed', 'skipped']
}

testClassesDirs = files(
configurations.testClasses,
configurations.testModuleClasspath
testClassesDirs += files(
tasks.unpackRemappedJar.outputs
)

classpath = files(
configurations.testRuntimeClasspath,
configurations.testClasses,
configurations.testModuleClasspath
classpath += files(
tasks.unpackRemappedJar.outputs
)

outputs.upToDateWhen {false}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package dev.lukebemish.opensesame.test.java.loom;

import net.fabricmc.api.EnvType;
import net.fabricmc.loader.impl.launch.FabricLauncherBase;

import java.io.InputStream;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.jar.Manifest;

class FakeKnot extends FabricLauncherBase {
private static volatile boolean INITIALIZED = false;
synchronized static void init() {
if (!INITIALIZED){
INITIALIZED = true;
new FakeKnot();
}
}

@Override
public void addToClassPath(Path path, String... allowedPrefixes) {}

@Override
public void setAllowedPrefixes(Path path, String... prefixes) {}

@Override
public void setValidParentClassPath(Collection<Path> paths) {}

@Override
public EnvType getEnvironmentType() {
return EnvType.SERVER;
}

@Override
public boolean isClassLoaded(String name) {
return false;
}

@Override
public Class<?> loadIntoTarget(String name) throws ClassNotFoundException {
throw new ClassNotFoundException("FakeKnot is not Knot");
}

@Override
public InputStream getResourceAsStream(String name) {
return null;
}

@Override
public ClassLoader getTargetClassLoader() {
return null;
}

@Override
public byte[] getClassByteArray(String name, boolean runTransformers) {
return new byte[0];
}

@Override
public Manifest getManifest(Path originPath) {
return null;
}

@Override
public boolean isDevelopment() {
return true;
}

@Override
public String getEntrypoint() {
return null;
}

@Override
public String getTargetNamespace() {
return "named";
}

@Override
public List<Path> getClassPath() {
return List.of();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

import dev.lukebemish.opensesame.annotations.Open;
import net.minecraft.resources.ResourceLocation;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class TestOpenLoom {
@BeforeAll
static void init() {
FakeKnot.init();
}

@Open(
name = "decompose",
targetClass = ResourceLocation.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,36 +85,6 @@ void testPackagePrivateClass() {
assertEquals("privateInstance", packagePrivateInstance(instance));
}

@Open(
name = "hiddenByModules",
targetName = "dev.lukebemish.opensesame.test.target.hidden.Hidden",
type = Open.Type.STATIC,
unsafe = true
)
private static String hiddenByModules() {
throw new RuntimeException();
}

@Open(
name = "hiddenByModulesPrivate",
targetName = "dev.lukebemish.opensesame.test.target.hidden.Hidden",
type = Open.Type.STATIC,
unsafe = true
)
private static String hiddenByModulesPrivate() {
throw new RuntimeException();
}

@Test
void testModuleBreaking() {
assertEquals("hiddenByModules", hiddenByModules());
assertEquals("hiddenByModulesPrivate", hiddenByModulesPrivate());
assertThrows(IllegalAccessException.class, () -> {
Class<?> hidden = Class.forName("dev.lukebemish.opensesame.test.target.hidden.Hidden");
hidden.getDeclaredMethod("hiddenByModules").invoke(null);
});
}

@Open(
targetName = "dev.lukebemish.opensesame.test.target.Public$Private",
type = Open.Type.ARRAY
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package dev.lukebemish.opensesame.test.java.Open;

import dev.lukebemish.opensesame.annotations.Open;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

@Tag("modules")
public class TestModules {
@Open(
name = "hiddenByModules",
targetName = "dev.lukebemish.opensesame.test.target.hidden.Hidden",
type = Open.Type.STATIC,
unsafe = true
)
private static String hiddenByModules() {
throw new RuntimeException();
}

@Open(
name = "hiddenByModulesPrivate",
targetName = "dev.lukebemish.opensesame.test.target.hidden.Hidden",
type = Open.Type.STATIC,
unsafe = true
)
private static String hiddenByModulesPrivate() {
throw new RuntimeException();
}

@Test
void testModuleBreaking() {
assertEquals("hiddenByModules", hiddenByModules());
assertEquals("hiddenByModulesPrivate", hiddenByModulesPrivate());
assertThrows(IllegalAccessException.class, () -> {
Class<?> hidden = Class.forName("dev.lukebemish.opensesame.test.target.hidden.Hidden");
hidden.getDeclaredMethod("hiddenByModules").invoke(null);
});
}
}

0 comments on commit f4b9dec

Please sign in to comment.