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"
version = "0.0.1-alpha.18"
version = "0.0.1-alpha.19"
repositories {
maven {

View file

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

View file

@ -9,6 +9,7 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import dev.frogmc.frogloader.impl.launch.transformer.AsmTransformer;
import dev.frogmc.frogloader.impl.mixin.FrogMixinService;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.MixinEnvironment;
@ -44,7 +45,7 @@ public class MixinClassLoader extends URLClassLoader {
if (in == 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.Map;
@ -6,8 +6,12 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import dev.frogmc.frogloader.impl.launch.FrogLauncher;
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 {
private static final AccessWidener INSTANCE = new AccessWidener();
@ -26,8 +30,8 @@ public class AccessWidener {
get().loadFromData(data);
}
public static byte[] processClass(byte[] classBytes, String className) {
return get().process(classBytes, className);
public static ClassVisitor processClass(ClassVisitor cv, String className) {
return get().process(cv, className);
}
private void loadFromData(Data data) {
@ -38,14 +42,12 @@ public class AccessWidener {
classNames.addAll(data.classNames);
}
private byte[] process(byte[] classBytes, String className) {
private ClassVisitor process(ClassVisitor visitor, String className) {
if (!classNames.contains(className)) {
return classBytes;
return visitor;
}
ClassReader reader = new ClassReader(classBytes);
ClassWriter writer = new ClassWriter(0);
ClassVisitor mapper = new ClassVisitor(Opcodes.ASM9, writer) {
return new ClassVisitor(FrogLauncher.ASM_VERSION, visitor) {
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
Entry e = classMap.get(className);
@ -106,9 +108,6 @@ public class AccessWidener {
super.visitInnerClass(name, outerName, innerName, access);
}
};
reader.accept(mapper, 0);
return writer.toByteArray();
}
@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.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
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;
public class AWProcessor {
@ -29,8 +30,12 @@ public class AWProcessor {
Map<String, Map<String, AccessWidener.Entry>> mutations = new ConcurrentHashMap<>();
Set<String> classNames = new ConcurrentSkipListSet<>();
mods.stream().map(ModProperties::extensions).map(e -> (String) e.get(AW_EXTENSION_NAME))
.filter(Objects::nonNull).map(s -> "/" + s).map(AWProcessor.class::getResourceAsStream).filter(Objects::nonNull)
mods.stream().map(ModProperties::extensions).map(e -> e.get(AW_EXTENSION_NAME)).flatMap(o -> {
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 -> {
try {
return HEADER.test(r.readLine());

View file

@ -1,13 +1,17 @@
package dev.frogmc.frogloader.impl.plugin.game.minecraft;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.URL;
import java.nio.file.*;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import com.google.gson.JsonObject;
import dev.frogmc.frogloader.api.FrogLoader;
@ -128,7 +132,14 @@ public class MinecraftGamePlugin implements GamePlugin {
MappingBundle mappings;
String mappingPath = System.getProperty(SystemProperties.INTERMEDIARY_MAPPINGS);
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 {
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);