add missing branch

This commit is contained in:
moehreag 2024-05-29 11:48:47 +02:00
parent ac09413c61
commit 7f22499f32
3 changed files with 3 additions and 210 deletions

View file

@ -104,6 +104,8 @@ public class ModDependencyResolver {
if (!(provides.containsKey(s) && value.range.versionMatches(provides.get(s)))) { // The dependency also isn't fulfilled by any provided mods if (!(provides.containsKey(s) && value.range.versionMatches(provides.get(s)))) { // The dependency also isn't fulfilled by any provided mods
if (value.origin.extensions().getOrDefault(BuiltinExtensions.LOADING_TYPE, "required").equals("required")) { if (value.origin.extensions().getOrDefault(BuiltinExtensions.LOADING_TYPE, "required").equals("required")) {
throw new UnfulfilledDependencyException(value.origin, s, value.range); throw new UnfulfilledDependencyException(value.origin, s, value.range);
} else {
continue;
} }
} }
} }

View file

@ -1,210 +0,0 @@
package org.ecorous.esnesnon.nonsense.loader.impl.plugin.game.minecraft;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import lombok.AllArgsConstructor;
import org.ecorous.esnesnon.nonsense.loader.api.mod.ModProperties;
import org.ecorous.esnesnon.nonsense.loader.impl.mod.BuiltinExtensions;
import org.objectweb.asm.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Minimal implementation of accesswideners.
*/
class AWProcessor {
private static final String AW_EXTENSION_NAME = BuiltinExtensions.ACCESSWIDENER;
private static final Predicate<String> HEADER = Pattern.compile("accessWidener\\s+v[12]\\s+.*").asMatchPredicate();
private static final String SEPARATOR = "[\\t ]+";
private static final Logger LOGGER = LoggerFactory.getLogger("AccessWidener");
static void apply(Collection<ModProperties> mods, Path input, Path output) throws IOException {
long startTime = System.currentTimeMillis();
Map<String, Entry> classMap = new ConcurrentHashMap<>();
Map<String, Map<String, Entry>> methods = new ConcurrentHashMap<>();
Map<String, Map<String, Entry>> fields = new ConcurrentHashMap<>();
Map<String, Map<String, 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)
.map(InputStreamReader::new).map(BufferedReader::new).flatMap(BufferedReader::lines)
.map(l -> l.contains("#") ? l.split("#")[0] : l).filter(l -> !l.isBlank())
.filter(l -> !HEADER.test(l)).distinct()
.map(l -> l.replace("transitive-", "")) // ignore all transitive declarations (just make them normal) as they're only relevant for dev envs
.map(l -> l.split(SEPARATOR)).filter(l -> l.length > 0).map(Entry::new).forEach(e -> {
classNames.add(e.className);
if ("class".equals(e.targetType)) {
if (e.type == AccessType.MUTABLE) {
throw new IllegalArgumentException("aw format error: classes can not have a 'mutable' modifier (at: " + e + ")");
}
if (!classMap.containsKey(e.className)) {
classMap.put(e.className, e);
} else {
var other = classMap.get(e.className);
if (e.isAccessGreaterThan(other)) {
classMap.put(e.className, e);
}
}
} else if ("method".equals(e.targetType)) {
if (e.type == AccessType.MUTABLE) {
throw new IllegalArgumentException("aw format error: methods can not have a 'mutable' modifier (at: " + e + ")");
}
var map = methods.computeIfAbsent(e.className, s -> new ConcurrentHashMap<>());
var id = e.name + e.descriptor;
if (!map.containsKey(id)) {
map.put(id, e);
} else {
var other = map.get(id);
if (e.isAccessGreaterThan(other)) {
classMap.put(id, e);
}
}
} else if ("field".equals(e.targetType)) {
if (e.type == AccessType.EXTENDABLE) {
throw new IllegalArgumentException("aw format error: fields can not have a 'extendable' modifier (at: " + e + ")");
}
var map = fields.computeIfAbsent(e.className, s -> new ConcurrentHashMap<>());
var id = e.name + e.descriptor;
if (e.type == AccessType.MUTABLE) {
mutations.computeIfAbsent(e.className, s -> new ConcurrentHashMap<>()).putIfAbsent(id, e);
return;
}
if (!map.containsKey(id)) {
map.put(id, e);
} else {
var other = map.get(id);
if (e.isAccessGreaterThan(other)) {
classMap.put(id, e);
}
}
}
});
Files.deleteIfExists(output);
Files.copy(input, output);
if (!classNames.isEmpty()) {
try (FileSystem out = FileSystems.newFileSystem(output)) {
for (String name : classNames) {
processFile(name, out.getPath("/" + name + ".class"), classMap, fields, methods, mutations);
}
}
}
LOGGER.info(String.format("Applied AccessWideners in %.2fs", (System.currentTimeMillis() - startTime) / 1000f));
}
private static void processFile(String className, Path file, Map<String, Entry> classMap, Map<String, Map<String, Entry>> fields, Map<String, Map<String, Entry>> methods, Map<String, Map<String, Entry>> mutations) throws IOException {
ClassReader reader = new ClassReader(Files.newInputStream(file));
ClassWriter writer = new ClassWriter(0);
ClassVisitor mapper = new ClassVisitor(Opcodes.ASM9, writer) {
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
Entry e = classMap.get(className);
if (e != null) {
access &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC);
access |= e.type.access;
}
if (fields.containsKey(className) || methods.containsKey(className) || mutations.containsKey(className)) { // make all classes with modifications public as well
access &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC);
access |= Opcodes.ACC_PUBLIC;
}
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
Map<String, Entry> map = fields.get(className);
if (map != null) {
Entry e = map.get(name + descriptor);
if (e != null) {
access &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC); // remove all access modifiers
access |= e.type.access; // re-add the new one
}
}
if ((map = mutations.get(className)) != null) {
var e = map.get(name + descriptor);
if (e != null) {
access &= ~Opcodes.ACC_FINAL; // always AccessType.MUTABLE
}
}
return super.visitField(access, name, descriptor, signature, value);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
Map<String, Entry> map = methods.get(className);
if (map != null) {
Entry e = map.get(name + descriptor);
if (e != null) {
access &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC);
access |= e.type.access;
}
}
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
};
reader.accept(mapper, 0);
Files.write(file, writer.toByteArray());
}
private record Entry(AccessType type, String targetType, String className, String name, String descriptor) {
public Entry(String[] line) {
this(AccessType.of(line[0]), line[1], line[2], line[3], line[4]);
}
public boolean isAccessGreaterThan(Entry other) {
return Access.of(type().access).index < Access.of(other.type.access).index;
}
}
@AllArgsConstructor
private enum AccessType {
ACCESSIBLE("accessible", Opcodes.ACC_PUBLIC),
EXTENDABLE("extendable", Opcodes.ACC_PROTECTED),
MUTABLE("mutable", ~Opcodes.ACC_FINAL);
private final String id;
private final int access;
public static AccessType of(String name) {
return Arrays.stream(values()).filter(a -> a.id.equals(name)).findFirst().orElseThrow(() -> new IllegalStateException("Unknown access type: " + name));
}
}
@AllArgsConstructor
private enum Access {
PUBLIC(1), PROTECTED(2), PACKAGE_PRIVATE(3), PRIVATE(4);
private final int index;
public static Access of(int access) {
if ((access & Opcodes.ACC_PUBLIC) != 0) {
return PUBLIC;
}
if ((access & Opcodes.ACC_PROTECTED) != 0) {
return PROTECTED;
}
if ((access & Opcodes.ACC_PRIVATE) != 0) {
return PRIVATE;
}
return PACKAGE_PRIVATE;
}
}
}

View file

@ -17,6 +17,7 @@ import org.ecorous.esnesnon.nonsense.loader.api.mod.ModExtensions;
import org.ecorous.esnesnon.nonsense.loader.api.mod.ModProperties; import org.ecorous.esnesnon.nonsense.loader.api.mod.ModProperties;
import org.ecorous.esnesnon.nonsense.loader.impl.Discovery; import org.ecorous.esnesnon.nonsense.loader.impl.Discovery;
import org.ecorous.esnesnon.nonsense.loader.impl.LoaderImpl; import org.ecorous.esnesnon.nonsense.loader.impl.LoaderImpl;
import org.ecorous.esnesnon.nonsense.loader.impl.mixin.AWProcessor;
import org.ecorous.esnesnon.nonsense.loader.impl.mod.BuiltinExtensions; import org.ecorous.esnesnon.nonsense.loader.impl.mod.BuiltinExtensions;
import org.ecorous.esnesnon.nonsense.loader.impl.mod.ModPropertiesImpl; import org.ecorous.esnesnon.nonsense.loader.impl.mod.ModPropertiesImpl;
import org.ecorous.esnesnon.nonsense.loader.impl.mod.ModPropertiesReader; import org.ecorous.esnesnon.nonsense.loader.impl.mod.ModPropertiesReader;