Compare commits
13 commits
owlsys/tin
...
main
Author | SHA1 | Date | |
---|---|---|---|
moehreag | f5f4cb1d4f | ||
moehreag | e08ed69730 | ||
TheKodeToad | 5ce38092c6 | ||
moehreag | bc47d9cc1a | ||
moehreag | f74fbc5248 | ||
moehreag | d68f4abea0 | ||
moehreag | 1fff5c75f6 | ||
moehreag | 811b4e3611 | ||
moehreag | f90baaef1b | ||
moehreag | 2d524c0eea | ||
moehreag | 69b62e7d0e | ||
moehreag | 25fefae245 | ||
Ecorous | 068928ad3d |
|
@ -8,14 +8,14 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "dev.frogmc"
|
group = "dev.frogmc"
|
||||||
version = "0.0.1-alpha.6"
|
version = "0.0.1-alpha.18"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.electronwill.night-config:json:3.8.0")
|
implementation("com.electronwill.night-config:json:3.8.1")
|
||||||
implementation("org.ow2.asm:asm:9.7")
|
implementation("org.ow2.asm:asm:9.7")
|
||||||
implementation("org.ow2.asm:asm-commons:9.7")
|
implementation("org.ow2.asm:asm-commons:9.7")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
package dev.frogmc.thyroxine;
|
package dev.frogmc.thyroxine;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import com.electronwill.nightconfig.json.JsonParser;
|
import com.electronwill.nightconfig.json.JsonParser;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
public final class Constants {
|
public final class Constants {
|
||||||
|
public static final String USER_AGENT = "FrogMC Thyroxine/" +
|
||||||
|
Objects.requireNonNullElse(Constants.class.getPackage().getImplementationVersion(), "development") +
|
||||||
|
" <frogmc.dev>";
|
||||||
public static final String VERSION_MANIFEST = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json";
|
public static final String VERSION_MANIFEST = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json";
|
||||||
public static final JsonParser JSON_PARSER = new JsonParser();
|
public static final JsonParser JSON_PARSER = new JsonParser();
|
||||||
|
public static final int ASM_VERSION = Opcodes.ASM9;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package dev.frogmc.thyroxine;
|
package dev.frogmc.thyroxine;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.http.HttpClient;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.net.http.HttpRequest;
|
||||||
import java.util.HashMap;
|
import java.net.http.HttpResponse;
|
||||||
import java.util.Map;
|
import java.net.http.HttpClient.Redirect;
|
||||||
import java.util.Optional;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
@ -17,21 +16,29 @@ import static dev.frogmc.thyroxine.Constants.JSON_PARSER;
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class HttpHelper {
|
public class HttpHelper {
|
||||||
|
|
||||||
private static final Map<String, String> requestCache = new HashMap<>();
|
public static UnmodifiableConfig getJson(String url) throws IOException {
|
||||||
|
return JSON_PARSER.parse(getString(url)).unmodifiable();
|
||||||
public static Optional<UnmodifiableConfig> getJson(String url) {
|
|
||||||
return getString(url).map(s -> JSON_PARSER.parse(s).unmodifiable());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<String> getString(String url) {
|
public static String getString(String url) throws IOException {
|
||||||
return Optional.ofNullable(requestCache.computeIfAbsent(url, s -> {
|
return request(url, HttpResponse.BodyHandlers.ofString()).body();
|
||||||
try (InputStream in = URI.create(url).parseServerAuthority().toURL().openStream()) {
|
}
|
||||||
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException | URISyntaxException e) {
|
public static void download(String url, Path file) throws IOException {
|
||||||
e.printStackTrace();
|
request(url, HttpResponse.BodyHandlers.ofFile(file));
|
||||||
// TODO
|
}
|
||||||
}
|
|
||||||
return null;
|
private static <T> HttpResponse<T> request(String url, HttpResponse.BodyHandler<T> handler) throws IOException {
|
||||||
}));
|
try (HttpClient client = HttpClient.newBuilder().followRedirects(Redirect.NORMAL).build()) {
|
||||||
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
|
.header("User-Agent", Constants.USER_AGENT)
|
||||||
|
.header("Accept", "*/*")
|
||||||
|
.GET()
|
||||||
|
.uri(URI.create(url))
|
||||||
|
.build();
|
||||||
|
return client.send(request, handler);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
8
src/main/java/dev/frogmc/thyroxine/RemappingStep.java
Normal file
8
src/main/java/dev/frogmc/thyroxine/RemappingStep.java
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package dev.frogmc.thyroxine;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassVisitor;
|
||||||
|
import org.objectweb.asm.commons.Remapper;
|
||||||
|
|
||||||
|
public interface RemappingStep {
|
||||||
|
ClassVisitor run(ClassVisitor previous, Remapper remapper);
|
||||||
|
}
|
|
@ -9,27 +9,34 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import dev.frogmc.thyroxine.api.Mapper;
|
||||||
import dev.frogmc.thyroxine.api.ParameterClassRemapper;
|
import dev.frogmc.thyroxine.api.ParameterClassRemapper;
|
||||||
import dev.frogmc.thyroxine.api.data.MappingBundle;
|
import dev.frogmc.thyroxine.api.data.MappingBundle;
|
||||||
|
import dev.frogmc.thyroxine.api.data.MappingData;
|
||||||
|
import dev.frogmc.thyroxine.parser.ProguardParser;
|
||||||
|
import dev.frogmc.thyroxine.parser.tiny.TinyV1Parser;
|
||||||
|
import dev.frogmc.thyroxine.parser.tiny.TinyV2Parser;
|
||||||
import dev.frogmc.thyroxine.provider.MojmapProvider;
|
import dev.frogmc.thyroxine.provider.MojmapProvider;
|
||||||
import dev.frogmc.thyroxine.provider.ParchmentProvider;
|
import dev.frogmc.thyroxine.provider.ParchmentProvider;
|
||||||
import dev.frogmc.thyroxine.api.Mapper;
|
|
||||||
import dev.frogmc.thyroxine.api.data.MappingData;
|
|
||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.commons.ClassRemapper;
|
import org.objectweb.asm.commons.ClassRemapper;
|
||||||
|
import org.objectweb.asm.commons.Remapper;
|
||||||
|
|
||||||
public class Thyroxine {
|
public class Thyroxine {
|
||||||
|
|
||||||
|
private static boolean SYSOUT = false;
|
||||||
|
|
||||||
public static void run(String minecraftVersion, Path inputJar, Path outputJar, boolean skipMetaInf, boolean renameParameters) throws IOException, InterruptedException {
|
public static void run(String minecraftVersion, Path inputJar, Path outputJar, boolean skipMetaInf, boolean renameParameters) throws IOException, InterruptedException {
|
||||||
|
Path out = outputJar.toAbsolutePath();
|
||||||
MappingBundle data = MojmapProvider.get(minecraftVersion,
|
MappingBundle data = MojmapProvider.get(minecraftVersion,
|
||||||
outputJar.resolveSibling("client-" + minecraftVersion + ".txt")).orElseThrow().reverse();
|
out.resolveSibling("client-" + minecraftVersion + ".txt"),
|
||||||
|
out.resolveSibling("server-" + minecraftVersion + ".txt")).reverse();
|
||||||
|
|
||||||
MappingBundle parchment = null;
|
MappingBundle parchment = null;
|
||||||
if (renameParameters) {
|
if (renameParameters) {
|
||||||
parchment = ParchmentProvider.getParchment(minecraftVersion, outputJar.getParent());
|
parchment = ParchmentProvider.getParchment(minecraftVersion, out.getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
MappingBundle result;
|
MappingBundle result;
|
||||||
|
@ -39,21 +46,33 @@ public class Thyroxine {
|
||||||
result = data;
|
result = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
remap(result, inputJar, outputJar, skipMetaInf, renameParameters, "official", "named");
|
SYSOUT = true;
|
||||||
|
remap(result, inputJar, out, skipMetaInf, renameParameters, "official", "named");
|
||||||
|
SYSOUT = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void remap(MappingData data, Path inputJar, Path outputJar, boolean skipMetaInf) throws IOException, InterruptedException {
|
public static void remap(MappingData data, Path inputJar, Path outputJar, boolean skipMetaInf, Path... context) throws IOException, InterruptedException {
|
||||||
remap(data, inputJar, outputJar, skipMetaInf, true);
|
remap(data, inputJar, outputJar, skipMetaInf, true, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void remap(MappingBundle bundle, Path inputJar, Path outputJar, boolean skipMetaInf, boolean renameParameters, String srcNamespace, String dstNamespace) throws IOException, InterruptedException {
|
public static void remap(MappingBundle bundle, Path inputJar, Path outputJar, boolean skipMetaInf, boolean renameParameters, String srcNamespace, String dstNamespace, Path... context) throws IOException, InterruptedException {
|
||||||
remap(bundle.forNamespaces(srcNamespace, dstNamespace), inputJar, outputJar, skipMetaInf, renameParameters);
|
remap(bundle.forNamespaces(srcNamespace, dstNamespace), inputJar, outputJar, skipMetaInf, renameParameters, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void remap(MappingData data, Path inputJar, Path outputJar, boolean skipMetaInf, boolean renameParameters) throws IOException, InterruptedException {
|
public static void remap(MappingData data, Path inputJar, Path outputJar, boolean skipMetaInf, boolean renameParameters, Path... context) throws IOException, InterruptedException {
|
||||||
|
List<RemappingStep> steps = List.of(
|
||||||
|
ClassRemapper::new,
|
||||||
|
(cv, mapper) -> renameParameters ? new ParameterClassRemapper(cv, mapper, data) : cv
|
||||||
|
);
|
||||||
|
remap(data, inputJar, outputJar, skipMetaInf, steps, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void remap(MappingData data, Path inputJar, Path outputJar, boolean skipMetaInf, List<RemappingStep> steps, Path... context) throws IOException, InterruptedException {
|
||||||
Files.deleteIfExists(outputJar);
|
Files.deleteIfExists(outputJar);
|
||||||
|
|
||||||
System.out.println("Remapping...");
|
if (SYSOUT) {
|
||||||
|
System.out.println("Remapping...");
|
||||||
|
}
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
@ -61,10 +80,15 @@ public class Thyroxine {
|
||||||
FileSystem inFs = FileSystems.newFileSystem(inputJar);
|
FileSystem inFs = FileSystems.newFileSystem(inputJar);
|
||||||
FileSystem outFs = FileSystems.newFileSystem(outputJar, Map.of("create", "true"))) {
|
FileSystem outFs = FileSystems.newFileSystem(outputJar, Map.of("create", "true"))) {
|
||||||
List<Callable<Void>> tasks = new ArrayList<>();
|
List<Callable<Void>> tasks = new ArrayList<>();
|
||||||
|
Map<Path, FileSystem> contexts = new HashMap<>(context.length + 1);
|
||||||
|
contexts.put(inputJar, inFs);
|
||||||
|
for (Path p : context) {
|
||||||
|
if (!contexts.containsKey(p)) {
|
||||||
|
contexts.put(p, FileSystems.newFileSystem(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, List<String>> lazyParents = new ConcurrentHashMap<>();
|
Remapper mapper = createMapper(data, contexts.values());
|
||||||
Mapper mapper = new Mapper(data, className -> lazyParents.computeIfAbsent(className, ignored ->
|
|
||||||
Thyroxine.computeInheritances(className, inFs)));
|
|
||||||
|
|
||||||
Files.walkFileTree(inFs.getPath("/"), new SimpleFileVisitor<>() {
|
Files.walkFileTree(inFs.getPath("/"), new SimpleFileVisitor<>() {
|
||||||
|
|
||||||
|
@ -88,12 +112,9 @@ public class Thyroxine {
|
||||||
byte[] bytes = Files.readAllBytes(path);
|
byte[] bytes = Files.readAllBytes(path);
|
||||||
ClassReader reader = new ClassReader(bytes);
|
ClassReader reader = new ClassReader(bytes);
|
||||||
ClassWriter writer = new ClassWriter(0);
|
ClassWriter writer = new ClassWriter(0);
|
||||||
ClassVisitor remapper = new ClassRemapper(writer, mapper);
|
ClassVisitor visitor = writer;
|
||||||
ClassVisitor visitor;
|
for (RemappingStep pass : steps) {
|
||||||
if (renameParameters) {
|
visitor = pass.run(visitor, mapper);
|
||||||
visitor = new ParameterClassRemapper(remapper, mapper, data);
|
|
||||||
} else {
|
|
||||||
visitor = remapper;
|
|
||||||
}
|
}
|
||||||
reader.accept(visitor, 0);
|
reader.accept(visitor, 0);
|
||||||
|
|
||||||
|
@ -119,7 +140,32 @@ public class Thyroxine {
|
||||||
|
|
||||||
exec.invokeAll(tasks);
|
exec.invokeAll(tasks);
|
||||||
|
|
||||||
System.out.printf("Finished remapping (%.2fs)%n", (System.currentTimeMillis() - startTime) / 1000F);
|
for (FileSystem fs : contexts.values()) {
|
||||||
|
fs.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYSOUT) {
|
||||||
|
System.out.printf("Finished remapping (%.2fs)%n", (System.currentTimeMillis() - startTime) / 1000F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Remapper createMapper(MappingData data, Collection<FileSystem> contexts) {
|
||||||
|
Map<String, List<String>> lazyParents = new ConcurrentHashMap<>();
|
||||||
|
MappingData reverseData = data.reverse();
|
||||||
|
return new Mapper(data, className -> lazyParents.computeIfAbsent(className, ignored ->
|
||||||
|
computeInheritances(className, reverseData, contexts)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MappingBundle parse(Path mappings) throws IOException {
|
||||||
|
String data = Files.readString(mappings);
|
||||||
|
String header = data.split("\n", 2)[0];
|
||||||
|
if (header.matches("tiny\t+v2\t+.*")) {
|
||||||
|
return TinyV2Parser.parse(data);
|
||||||
|
} else if (TinyV1Parser.HEADER.matcher(header).matches()) {
|
||||||
|
return TinyV1Parser.parse(data);
|
||||||
|
} else {
|
||||||
|
return new MappingBundle(ProguardParser.read(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +183,6 @@ public class Thyroxine {
|
||||||
boolean remapParams = args.length > 3 && hasArg(args, "--remap-parameters");
|
boolean remapParams = args.length > 3 && hasArg(args, "--remap-parameters");
|
||||||
|
|
||||||
run(minecraftVersion, Paths.get(minecraftJar), Paths.get(outJar), removeMetaInf, remapParams);
|
run(minecraftVersion, Paths.get(minecraftJar), Paths.get(outJar), removeMetaInf, remapParams);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hasArg(String[] arguments, String arg) {
|
private static boolean hasArg(String[] arguments, String arg) {
|
||||||
|
@ -149,23 +194,32 @@ public class Thyroxine {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> computeInheritances(String className, FileSystem inFs){
|
private static List<String> computeInheritances(String className, MappingData reverse, Collection<FileSystem> jars) {
|
||||||
try {
|
try {
|
||||||
Path path = inFs.getPath("/" + className + ".class");
|
if (reverse.classes().containsKey(className)) {
|
||||||
if (!Files.isRegularFile(path))
|
className = reverse.classes().get(className);
|
||||||
return List.of();
|
}
|
||||||
|
|
||||||
byte[] bytes = Files.readAllBytes(path);
|
|
||||||
ClassReader reader = new ClassReader(bytes);
|
|
||||||
List<String> superTypes = new ArrayList<>();
|
List<String> superTypes = new ArrayList<>();
|
||||||
reader.accept(new ClassVisitor(Opcodes.ASM9) {
|
for (FileSystem fs : jars) {
|
||||||
@Override
|
Path path = fs.getPath("/" + className + ".class");
|
||||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
if (!Files.isRegularFile(path)) {
|
||||||
superTypes.add(superName);
|
continue;
|
||||||
superTypes.addAll(Arrays.asList(interfaces));
|
|
||||||
}
|
}
|
||||||
}, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
|
||||||
|
|
||||||
|
byte[] bytes = Files.readAllBytes(path);
|
||||||
|
ClassReader reader = new ClassReader(bytes);
|
||||||
|
reader.accept(new ClassVisitor(Constants.ASM_VERSION) {
|
||||||
|
@Override
|
||||||
|
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||||
|
if (interfaces != null) {
|
||||||
|
superTypes.addAll(Arrays.asList(interfaces));
|
||||||
|
}
|
||||||
|
if (!"java/lang/Object".equals(superName)) {
|
||||||
|
superTypes.add(superName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||||
|
}
|
||||||
return superTypes;
|
return superTypes;
|
||||||
} catch (IOException error) {
|
} catch (IOException error) {
|
||||||
throw new Error(error); // not our problem :^) for now
|
throw new Error(error); // not our problem :^) for now
|
||||||
|
|
|
@ -60,9 +60,4 @@ public class Mapper extends Remapper {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String mapMethodDesc(String methodDescriptor) {
|
|
||||||
return super.mapMethodDesc(methodDescriptor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,22 +3,30 @@ package dev.frogmc.thyroxine.api;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import dev.frogmc.thyroxine.Constants;
|
||||||
import dev.frogmc.thyroxine.api.data.MappingData;
|
import dev.frogmc.thyroxine.api.data.MappingData;
|
||||||
import dev.frogmc.thyroxine.api.data.Member;
|
import dev.frogmc.thyroxine.api.data.Member;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.commons.ClassRemapper;
|
|
||||||
import org.objectweb.asm.commons.Remapper;
|
import org.objectweb.asm.commons.Remapper;
|
||||||
|
|
||||||
public class ParameterClassRemapper extends ClassRemapper {
|
public class ParameterClassRemapper extends ClassVisitor {
|
||||||
private final MappingData data;
|
private final MappingData data;
|
||||||
|
private final Remapper remapper;
|
||||||
|
|
||||||
|
private String className;
|
||||||
public ParameterClassRemapper(ClassVisitor classVisitor, Remapper remapper, MappingData data) {
|
public ParameterClassRemapper(ClassVisitor classVisitor, Remapper remapper, MappingData data) {
|
||||||
super(Opcodes.ASM9, classVisitor, remapper);
|
super(Constants.ASM_VERSION, classVisitor);
|
||||||
|
this.remapper = remapper;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||||
|
this.className = name;
|
||||||
|
super.visit(version, access, name, signature, superName, interfaces);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||||
String remappedDescriptor = remapper.mapMethodDesc(descriptor);
|
String remappedDescriptor = remapper.mapMethodDesc(descriptor);
|
||||||
|
@ -27,6 +35,6 @@ public class ParameterClassRemapper extends ClassRemapper {
|
||||||
|
|
||||||
Member member = new Member(remapper.map(className), remapper.mapMethodName(className, name, descriptor), remappedDescriptor);
|
Member member = new Member(remapper.map(className), remapper.mapMethodName(className, name, descriptor), remappedDescriptor);
|
||||||
Map<Integer, String> parameters = data != null ? data.parameters().getOrDefault(member, Collections.emptyMap()) : Collections.emptyMap();
|
Map<Integer, String> parameters = data != null ? data.parameters().getOrDefault(member, Collections.emptyMap()) : Collections.emptyMap();
|
||||||
return methodVisitor == null ? null : new ParameterMethodRemapper(methodVisitor, remapper, parameters);
|
return new ParameterMethodRemapper(methodVisitor, remapper, parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
package dev.frogmc.thyroxine.api;
|
package dev.frogmc.thyroxine.api;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashSet;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import dev.frogmc.thyroxine.Constants;
|
||||||
import org.objectweb.asm.Label;
|
import org.objectweb.asm.Label;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
import org.objectweb.asm.commons.MethodRemapper;
|
|
||||||
import org.objectweb.asm.commons.Remapper;
|
import org.objectweb.asm.commons.Remapper;
|
||||||
|
|
||||||
public class ParameterMethodRemapper extends MethodRemapper {
|
public class ParameterMethodRemapper extends MethodVisitor {
|
||||||
|
private final Remapper remapper;
|
||||||
private final Map<Integer, String> parameters;
|
private final Map<Integer, String> parameters;
|
||||||
private final Set<String> usedLocalNames = new HashSet<>();
|
private final Set<String> usedLocalNames = new HashSet<>();
|
||||||
|
|
||||||
public ParameterMethodRemapper(MethodVisitor methodVisitor, Remapper remapper, Map<Integer, String> parameters) {
|
public ParameterMethodRemapper(MethodVisitor methodVisitor, Remapper remapper, Map<Integer, String> parameters) {
|
||||||
super(Opcodes.ASM9, methodVisitor, remapper);
|
super(Constants.ASM_VERSION, methodVisitor);
|
||||||
|
this.remapper = remapper;
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,14 @@ public record MappingBundle(List<MappingData> data, List<DocumentationData> docu
|
||||||
String w = res;
|
String w = res;
|
||||||
res = d.classes().get(res);
|
res = d.classes().get(res);
|
||||||
if (res == null) {
|
if (res == null) {
|
||||||
|
int dollar = w.indexOf("$");
|
||||||
|
if (dollar != -1) {
|
||||||
|
String prefix = d.classes().get(w.substring(0, dollar));
|
||||||
|
if (prefix != null) {
|
||||||
|
res = prefix + w.substring(dollar);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!allowIncomplete) {
|
if (!allowIncomplete) {
|
||||||
/*
|
/*
|
||||||
* The mapping set is incomplete at this point.
|
* The mapping set is incomplete at this point.
|
||||||
|
|
|
@ -9,7 +9,7 @@ import dev.frogmc.thyroxine.api.data.Member;
|
||||||
|
|
||||||
public class TinyV1Parser {
|
public class TinyV1Parser {
|
||||||
|
|
||||||
private static final Pattern HEADER = Pattern.compile("v(?<majorVer>[12]+)\\s\\w*\\s?(?<srcns>\\S+)\\s(?<dstns>\\S+)");
|
public static final Pattern HEADER = Pattern.compile("v(?<majorVer>[12]+)\\s\\w*\\s?(?<srcns>\\S+)\\s(?<dstns>\\S+)");
|
||||||
|
|
||||||
public static MappingBundle parse(String mappings) {
|
public static MappingBundle parse(String mappings) {
|
||||||
String[] lines = mappings.split("\n");
|
String[] lines = mappings.split("\n");
|
||||||
|
|
|
@ -43,9 +43,9 @@ public class TinyV2Parser {
|
||||||
|
|
||||||
if ("c".equals(line[0])) {
|
if ("c".equals(line[0])) {
|
||||||
if (1+ns >= line.length) {
|
if (1+ns >= line.length) {
|
||||||
do {
|
while (lines[i + 1].startsWith("\t")) {
|
||||||
i++;
|
i++;
|
||||||
} while (lines[i].startsWith("\t"));
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
currentClass = line[ns];
|
currentClass = line[ns];
|
||||||
|
|
|
@ -1,65 +1,64 @@
|
||||||
package dev.frogmc.thyroxine.provider;
|
package dev.frogmc.thyroxine.provider;
|
||||||
|
|
||||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
|
||||||
import dev.frogmc.thyroxine.Constants;
|
|
||||||
import dev.frogmc.thyroxine.HttpHelper;
|
|
||||||
import dev.frogmc.thyroxine.api.data.MappingBundle;
|
|
||||||
import dev.frogmc.thyroxine.parser.ProguardParser;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||||
|
import dev.frogmc.thyroxine.Constants;
|
||||||
|
import dev.frogmc.thyroxine.HttpHelper;
|
||||||
|
import dev.frogmc.thyroxine.api.data.MappingBundle;
|
||||||
|
import dev.frogmc.thyroxine.api.data.MappingData;
|
||||||
|
import dev.frogmc.thyroxine.parser.ProguardParser;
|
||||||
|
|
||||||
public class MojmapProvider {
|
public class MojmapProvider {
|
||||||
|
|
||||||
public static Optional<MappingBundle> get(String gameVersion, Path cacheFile) {
|
public static MappingBundle get(String gameVersion, Path clientCacheFile, Path serverCacheFile) throws IOException {
|
||||||
return getMappings(gameVersion, cacheFile).map(ProguardParser::read).map(MappingBundle::new);
|
MappingData client = ProguardParser.read(getMappings(gameVersion, "client", clientCacheFile));
|
||||||
|
MappingData server = ProguardParser.read(getMappings(gameVersion, "server", serverCacheFile));
|
||||||
|
client.classes().putAll(server.classes());
|
||||||
|
client.fields().putAll(server.fields());
|
||||||
|
client.methods().putAll(server.methods());
|
||||||
|
client.parameters().putAll(server.parameters());
|
||||||
|
return new MappingBundle(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
public static MappingBundle get(String gameVersion, String env, Path cacheFile) throws IOException {
|
||||||
private static Optional<String> getMappings(String gameVersion, Path cacheFile) {
|
return new MappingBundle(ProguardParser.read(getMappings(gameVersion, env, cacheFile)));
|
||||||
if (Files.exists(cacheFile)){
|
}
|
||||||
try {
|
|
||||||
return Optional.of(Files.readString(cacheFile, StandardCharsets.UTF_8));
|
@SuppressWarnings("unchecked")
|
||||||
} catch (IOException e) {
|
private static String getMappings(String gameVersion, String env, Path cacheFile) throws IOException {
|
||||||
// TODO
|
if (Files.exists(cacheFile)) {
|
||||||
e.printStackTrace();
|
return Files.readString(cacheFile, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
UnmodifiableConfig manifest = HttpHelper.getJson(Constants.VERSION_MANIFEST);
|
||||||
|
String versionName;
|
||||||
|
if (gameVersion.startsWith("latest-")) {
|
||||||
|
versionName = (String) ((Map<?, ?>) manifest.get("latest")).get(gameVersion.split("-")[1]);
|
||||||
|
} else {
|
||||||
|
versionName = gameVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Loading version: " + versionName);
|
||||||
|
|
||||||
|
for (UnmodifiableConfig version : (List<UnmodifiableConfig>) manifest.get("versions")) {
|
||||||
|
if (version.get("id").equals(versionName)) {
|
||||||
|
|
||||||
|
UnmodifiableConfig versionManifest = HttpHelper.getJson(version.get("url"));
|
||||||
|
String mappingsUrl = ((UnmodifiableConfig) ((UnmodifiableConfig) versionManifest
|
||||||
|
.get("downloads")).get(env+"_mappings")).get("url");
|
||||||
|
|
||||||
|
String s = HttpHelper.getString(mappingsUrl);
|
||||||
|
Files.createDirectories(cacheFile.getParent());
|
||||||
|
Files.writeString(cacheFile, s);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return HttpHelper.getJson(Constants.VERSION_MANIFEST).flatMap(manifest -> {
|
throw new IllegalArgumentException("Could not find mojmap for the specified version: " + gameVersion + "/"+env+"!");
|
||||||
String versionName;
|
}
|
||||||
if (gameVersion.startsWith("latest-")) {
|
|
||||||
versionName = (String) ((Map<?, ?>) manifest.get("latest")).get(gameVersion.split("-")[1]);
|
|
||||||
} else {
|
|
||||||
versionName = gameVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("Loading version: " + versionName);
|
|
||||||
|
|
||||||
for (UnmodifiableConfig version : (List<UnmodifiableConfig>) manifest.get("versions")) {
|
|
||||||
if (version.get("id").equals(versionName)) {
|
|
||||||
|
|
||||||
UnmodifiableConfig versionManifest = HttpHelper.getJson(version.get("url")).orElseThrow();
|
|
||||||
String mappingsUrl = ((UnmodifiableConfig) ((UnmodifiableConfig) versionManifest
|
|
||||||
.get("downloads")).get("client_mappings")).get("url");
|
|
||||||
|
|
||||||
return HttpHelper.getString(mappingsUrl).map(s -> {
|
|
||||||
try {
|
|
||||||
Files.writeString(cacheFile, s);
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,9 @@ package dev.frogmc.thyroxine.provider;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.FileSystem;
|
import java.nio.file.FileSystem;
|
||||||
import java.nio.file.FileSystems;
|
import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -18,6 +15,7 @@ import java.util.*;
|
||||||
|
|
||||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||||
import dev.frogmc.thyroxine.Constants;
|
import dev.frogmc.thyroxine.Constants;
|
||||||
|
import dev.frogmc.thyroxine.HttpHelper;
|
||||||
import dev.frogmc.thyroxine.api.data.DocumentationData;
|
import dev.frogmc.thyroxine.api.data.DocumentationData;
|
||||||
import dev.frogmc.thyroxine.api.data.MappingBundle;
|
import dev.frogmc.thyroxine.api.data.MappingBundle;
|
||||||
import dev.frogmc.thyroxine.api.data.MappingData;
|
import dev.frogmc.thyroxine.api.data.MappingData;
|
||||||
|
@ -36,9 +34,9 @@ public class ParchmentProvider {
|
||||||
private static String findParchmentVersion(String gameVersion) throws IOException {
|
private static String findParchmentVersion(String gameVersion) throws IOException {
|
||||||
String url = getParchmentUrl(gameVersion) + "/maven-metadata.xml";
|
String url = getParchmentUrl(gameVersion) + "/maven-metadata.xml";
|
||||||
try (InputStream
|
try (InputStream
|
||||||
stream = URI.create(url).toURL().openStream()) {
|
stream = URI.create(url).toURL().openStream()) {
|
||||||
Document document = DocumentBuilderFactory.newInstance()
|
Document document = DocumentBuilderFactory.newInstance()
|
||||||
.newDocumentBuilder().parse(stream);
|
.newDocumentBuilder().parse(stream);
|
||||||
return document.getElementsByTagName("release").item(0).getTextContent();
|
return document.getElementsByTagName("release").item(0).getTextContent();
|
||||||
} catch (IOException | SAXException | ParserConfigurationException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
|
@ -61,12 +59,12 @@ public class ParchmentProvider {
|
||||||
|
|
||||||
var url = "%s/%s/parchment-%s-%s.zip".formatted(getParchmentUrl(gameVersion), parchmentVer, gameVersion, parchmentVer);
|
var url = "%s/%s/parchment-%s-%s.zip".formatted(getParchmentUrl(gameVersion), parchmentVer, gameVersion, parchmentVer);
|
||||||
if (forceDownload || Files.notExists(cachePath)) {
|
if (forceDownload || Files.notExists(cachePath)) {
|
||||||
Files.copy(URI.create(url).toURL().openStream(), cachePath);
|
HttpHelper.download(url, cachePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
try (InputStream input = URI.create(url+".sha512").toURL().openStream()) {
|
try {
|
||||||
var hash = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).readLine();
|
var hash = HttpHelper.getString(url + ".sha512").split("\n", 2)[0];
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-512");
|
MessageDigest digest = MessageDigest.getInstance("SHA-512");
|
||||||
byte[] out = digest.digest(Files.readAllBytes(cachePath));
|
byte[] out = digest.digest(Files.readAllBytes(cachePath));
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
@ -75,10 +73,10 @@ public class ParchmentProvider {
|
||||||
}
|
}
|
||||||
String local = sb.toString();
|
String local = sb.toString();
|
||||||
if (!hash.equals(local)) {
|
if (!hash.equals(local)) {
|
||||||
System.out.println("Hashes do not match for "+cachePath+": "+local+" != "+hash+"; redownloading!");
|
System.out.println("Hashes do not match for " + cachePath + ": " + local + " != " + hash + "; redownloading!");
|
||||||
return getParchment(gameVersion, parchmentVer, cacheDir, true);
|
return getParchment(gameVersion, parchmentVer, cacheDir, true);
|
||||||
}
|
}
|
||||||
} catch (NoSuchAlgorithmException e){
|
} catch (NoSuchAlgorithmException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +90,7 @@ public class ParchmentProvider {
|
||||||
List<DocumentationData.Package> packages = new ArrayList<>();
|
List<DocumentationData.Package> packages = new ArrayList<>();
|
||||||
packagesList.forEach(config ->
|
packagesList.forEach(config ->
|
||||||
packages.add(new DocumentationData.Package(config.get("name"), new ArrayList<>(Objects.requireNonNullElse(c.get("javadoc"),
|
packages.add(new DocumentationData.Package(config.get("name"), new ArrayList<>(Objects.requireNonNullElse(c.get("javadoc"),
|
||||||
Collections.emptyList())))));
|
Collections.emptyList())))));
|
||||||
|
|
||||||
List<DocumentationData.Class> classes = new ArrayList<>();
|
List<DocumentationData.Class> classes = new ArrayList<>();
|
||||||
List<UnmodifiableConfig> classesList = Objects.requireNonNullElse(c.get("classes"), Collections.emptyList());
|
List<UnmodifiableConfig> classesList = Objects.requireNonNullElse(c.get("classes"), Collections.emptyList());
|
||||||
|
|
Loading…
Reference in a new issue