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
All checks were successful
Publish to snapshot maven / build (push) Successful in 27s
This commit is contained in:
parent
0715c7620d
commit
cbc44f5147
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue