fix bugs, expand transformation capabilities, allow specifying intermediary mappings on the classpath
All checks were successful
Publish to snapshot maven / build (push) Successful in 27s

This commit is contained in:
moehreag 2024-08-09 22:23:16 +02:00
parent 0715c7620d
commit cbc44f5147
7 changed files with 63 additions and 18 deletions

View file

@ -7,7 +7,7 @@ plugins {
} }
group = "dev.frogmc" group = "dev.frogmc"
version = "0.0.1-alpha.18" version = "0.0.1-alpha.19"
repositories { repositories {
maven { maven {

View file

@ -10,11 +10,13 @@ import com.llamalad7.mixinextras.MixinExtrasBootstrap;
import dev.frogmc.frogloader.api.env.Env; import dev.frogmc.frogloader.api.env.Env;
import dev.frogmc.frogloader.impl.mixin.FrogMixinService; import dev.frogmc.frogloader.impl.mixin.FrogMixinService;
import lombok.Getter; import lombok.Getter;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.launch.MixinBootstrap; import org.spongepowered.asm.launch.MixinBootstrap;
import org.spongepowered.asm.service.IPropertyKey; import org.spongepowered.asm.service.IPropertyKey;
public class FrogLauncher { public class FrogLauncher {
public static final int ASM_VERSION = Opcodes.ASM9;
@Getter @Getter
private static FrogLauncher instance; private static FrogLauncher instance;
@Getter @Getter

View file

@ -9,6 +9,7 @@ import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
import dev.frogmc.frogloader.impl.launch.transformer.AsmTransformer;
import dev.frogmc.frogloader.impl.mixin.FrogMixinService; import dev.frogmc.frogloader.impl.mixin.FrogMixinService;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.MixinEnvironment;
@ -44,7 +45,7 @@ public class MixinClassLoader extends URLClassLoader {
if (in == null) if (in == null)
return null; return null;
return FrogMixinService.getTransformer().transformClass(MixinEnvironment.getCurrentEnvironment(), name, AccessWidener.processClass(in.readAllBytes(), binName)); return FrogMixinService.getTransformer().transformClass(MixinEnvironment.getCurrentEnvironment(), name, AsmTransformer.transform(in.readAllBytes(), binName));
} }
} }

View file

@ -1,4 +1,4 @@
package dev.frogmc.frogloader.impl.launch; package dev.frogmc.frogloader.impl.launch.transformer;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
@ -6,8 +6,12 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.ConcurrentSkipListSet;
import dev.frogmc.frogloader.impl.launch.FrogLauncher;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.objectweb.asm.*; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class AccessWidener { public class AccessWidener {
private static final AccessWidener INSTANCE = new AccessWidener(); private static final AccessWidener INSTANCE = new AccessWidener();
@ -26,8 +30,8 @@ public class AccessWidener {
get().loadFromData(data); get().loadFromData(data);
} }
public static byte[] processClass(byte[] classBytes, String className) { public static ClassVisitor processClass(ClassVisitor cv, String className) {
return get().process(classBytes, className); return get().process(cv, className);
} }
private void loadFromData(Data data) { private void loadFromData(Data data) {
@ -38,14 +42,12 @@ public class AccessWidener {
classNames.addAll(data.classNames); classNames.addAll(data.classNames);
} }
private byte[] process(byte[] classBytes, String className) { private ClassVisitor process(ClassVisitor visitor, String className) {
if (!classNames.contains(className)) { if (!classNames.contains(className)) {
return classBytes; return visitor;
} }
ClassReader reader = new ClassReader(classBytes); return new ClassVisitor(FrogLauncher.ASM_VERSION, visitor) {
ClassWriter writer = new ClassWriter(0);
ClassVisitor mapper = new ClassVisitor(Opcodes.ASM9, writer) {
@Override @Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
Entry e = classMap.get(className); Entry e = classMap.get(className);
@ -106,9 +108,6 @@ public class AccessWidener {
super.visitInnerClass(name, outerName, innerName, access); super.visitInnerClass(name, outerName, innerName, access);
} }
}; };
reader.accept(mapper, 0);
return writer.toByteArray();
} }
@AllArgsConstructor @AllArgsConstructor

View file

@ -0,0 +1,27 @@
package dev.frogmc.frogloader.impl.launch.transformer;
import java.util.List;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
public interface AsmTransformer {
List<AsmTransformer> TRANSFORMERS = List.of(
AccessWidener::processClass
);
ClassVisitor transform(ClassVisitor cv, String name);
static byte[] transform(byte[] clazz, String name) {
ClassReader reader = new ClassReader(clazz);
ClassWriter writer = new ClassWriter(0);
ClassVisitor cv = writer;
for (AsmTransformer fcv : TRANSFORMERS) {
cv = fcv.transform(cv, name);
}
reader.accept(cv, 0);
return writer.toByteArray();
}
}

View file

@ -11,9 +11,10 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.ConcurrentSkipListSet;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream;
import dev.frogmc.frogloader.api.mod.ModProperties; import dev.frogmc.frogloader.api.mod.ModProperties;
import dev.frogmc.frogloader.impl.launch.AccessWidener; import dev.frogmc.frogloader.impl.launch.transformer.AccessWidener;
import dev.frogmc.frogloader.impl.mod.BuiltinExtensions; import dev.frogmc.frogloader.impl.mod.BuiltinExtensions;
public class AWProcessor { public class AWProcessor {
@ -29,8 +30,12 @@ public class AWProcessor {
Map<String, Map<String, AccessWidener.Entry>> mutations = new ConcurrentHashMap<>(); Map<String, Map<String, AccessWidener.Entry>> mutations = new ConcurrentHashMap<>();
Set<String> classNames = new ConcurrentSkipListSet<>(); Set<String> classNames = new ConcurrentSkipListSet<>();
mods.stream().map(ModProperties::extensions).map(e -> (String) e.get(AW_EXTENSION_NAME)) mods.stream().map(ModProperties::extensions).map(e -> e.get(AW_EXTENSION_NAME)).flatMap(o -> {
.filter(Objects::nonNull).map(s -> "/" + s).map(AWProcessor.class::getResourceAsStream).filter(Objects::nonNull) if (o instanceof Collection<?> c) {
return c.stream().map(Object::toString);
}
return Stream.of(o.toString());
}).filter(Objects::nonNull).map(s -> "/" + s).map(AWProcessor.class::getResourceAsStream).filter(Objects::nonNull)
.map(InputStreamReader::new).map(BufferedReader::new).filter(r -> { .map(InputStreamReader::new).map(BufferedReader::new).filter(r -> {
try { try {
return HEADER.test(r.readLine()); return HEADER.test(r.readLine());

View file

@ -1,13 +1,17 @@
package dev.frogmc.frogloader.impl.plugin.game.minecraft; package dev.frogmc.frogloader.impl.plugin.game.minecraft;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.net.URL;
import java.nio.file.*; import java.nio.file.*;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import dev.frogmc.frogloader.api.FrogLoader; import dev.frogmc.frogloader.api.FrogLoader;
@ -128,7 +132,14 @@ public class MinecraftGamePlugin implements GamePlugin {
MappingBundle mappings; MappingBundle mappings;
String mappingPath = System.getProperty(SystemProperties.INTERMEDIARY_MAPPINGS); String mappingPath = System.getProperty(SystemProperties.INTERMEDIARY_MAPPINGS);
if (mappingPath != null) { if (mappingPath != null) {
mappings = TinyV2Parser.parse(Files.readString(Paths.get(mappingPath))); URL resource = this.getClass().getResource("");
String data;
if (resource != null) {
data = new BufferedReader(new InputStreamReader(resource.openStream())).lines().collect(Collectors.joining());
} else {
data = Files.readString(Paths.get(mappingPath));
}
mappings = TinyV2Parser.parse(data);
} else { } else {
mappings = MojmapProvider.get(version, remappedGamePath.resolveSibling("client-" + version + ".txt")).orElseGet(() -> { mappings = MojmapProvider.get(version, remappedGamePath.resolveSibling("client-" + version + ".txt")).orElseGet(() -> {
LOGGER.warn("Failed to retrieve/parse mojmap for {}! If it isn't available you will need to specify intermediary mappings yourself!", version); LOGGER.warn("Failed to retrieve/parse mojmap for {}! If it isn't available you will need to specify intermediary mappings yourself!", version);