diff --git a/build.gradle.kts b/build.gradle.kts index eb08441ce6..6ff7af9af3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -95,7 +95,7 @@ dependencies { jij(libs.orbit) jij(libs.starscript) jij(libs.discord.ipc) - jij(libs.reflections) + jij(libs.classgraph) jij(libs.netty.handler.proxy) { isTransitive = false } jij(libs.netty.codec.socks) { isTransitive = false } jij(libs.waybackauthlib) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cfe6103256..b2b123b24f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,8 +26,8 @@ orbit = "0.2.4" starscript = "0.2.5" # DiscordRPC (https://github.com/MeteorDevelopment/java-discord-rpc) discordipc = "1.1" -# Reflections (https://github.com/ronmamo/reflections) -reflections = "0.10.2" +# Classgraph (https://github.com/classgraph/classgraph) +classgraph = "4.8.184" # Netty (https://github.com/netty/netty) netty = "4.1.118.Final" # ViaFabricPlus (https://github.com/ViaVersion/ViaFabricPlus) @@ -54,7 +54,7 @@ viafabricplus-api = { module = "com.viaversion:viafabricplus-api", version.ref = orbit = { module = "meteordevelopment:orbit", version.ref = "orbit" } starscript = { module = "org.meteordev:starscript", version.ref = "starscript" } discord-ipc = { module = "meteordevelopment:discord-ipc", version.ref = "discordipc" } -reflections = { module = "org.reflections:reflections", version.ref = "reflections" } +classgraph = { module = "io.github.classgraph:classgraph", version.ref = "classgraph" } netty-handler-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" } netty-codec-socks = { module = "io.netty:netty-codec-socks", version.ref = "netty" } waybackauthlib = { module = "de.florianmichael:WaybackAuthLib", version.ref = "waybackauthlib" } diff --git a/src/main/java/meteordevelopment/meteorclient/addons/GithubRepo.java b/src/main/java/meteordevelopment/meteorclient/addons/GithubRepo.java index 0ee4158f9f..57a4036b0d 100644 --- a/src/main/java/meteordevelopment/meteorclient/addons/GithubRepo.java +++ b/src/main/java/meteordevelopment/meteorclient/addons/GithubRepo.java @@ -6,8 +6,7 @@ package meteordevelopment.meteorclient.addons; import meteordevelopment.meteorclient.utils.network.Http; - -import javax.annotation.Nullable; +import org.jetbrains.annotations.Nullable; public record GithubRepo(String owner, String name, String branch, @Nullable String accessToken) { public GithubRepo(String owner, String name, @Nullable String accessToken) { diff --git a/src/main/java/meteordevelopment/meteorclient/systems/friends/Friend.java b/src/main/java/meteordevelopment/meteorclient/systems/friends/Friend.java index 125479962d..9a2f1b3b13 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/friends/Friend.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/friends/Friend.java @@ -15,8 +15,8 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.net.http.HttpResponse; import java.util.Objects; import java.util.UUID; @@ -38,6 +38,7 @@ public Friend(String name, @Nullable UUID id) { public Friend(PlayerEntity player) { this(player.getName().getString(), player.getUuid()); } + public Friend(String name) { this(name, null); } diff --git a/src/main/java/meteordevelopment/meteorclient/utils/ReflectInit.java b/src/main/java/meteordevelopment/meteorclient/utils/ReflectInit.java index ac4ca4cd06..9c8d359809 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/ReflectInit.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/ReflectInit.java @@ -5,10 +5,11 @@ package meteordevelopment.meteorclient.utils; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.MethodInfo; +import io.github.classgraph.ScanResult; import meteordevelopment.meteorclient.addons.AddonManager; import meteordevelopment.meteorclient.addons.MeteorAddon; -import org.reflections.Reflections; -import org.reflections.scanners.Scanners; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; @@ -17,7 +18,7 @@ import java.util.stream.Collectors; public class ReflectInit { - private static final List reflections = new ArrayList<>(); + private static final List packages = new ArrayList<>(); private ReflectInit() { } @@ -35,19 +36,32 @@ public static void registerPackages() { private static void add(MeteorAddon addon) { String pkg = addon.getPackage(); if (pkg == null || pkg.isBlank()) return; - reflections.add(new Reflections(pkg, Scanners.MethodsAnnotated)); + packages.add(pkg); } public static void init(Class annotation) { - for (Reflections reflection : reflections) { - Set initTasks = reflection.getMethodsAnnotatedWith(annotation); - if (initTasks == null) return; + for (String pkg : packages) { + try (ScanResult scanResult = new ClassGraph() + .acceptPackages(pkg) + .enableMethodInfo() + .enableAnnotationInfo() + .scan()) { - Map, List> byClass = initTasks.stream().collect(Collectors.groupingBy(Method::getDeclaringClass)); - Set left = new HashSet<>(initTasks); + Set initTasks = scanResult.getClassesWithMethodAnnotation(annotation) + .stream() + .flatMap(classInfo -> classInfo.getMethodInfo().stream()) + .filter(methodInfo -> methodInfo.hasAnnotation(annotation)) + .map(MethodInfo::loadClassAndGetMethod) + .collect(Collectors.toSet()); - for (Method m; (m = left.stream().findAny().orElse(null)) != null; ) { - reflectInit(m, annotation, left, byClass); + if (initTasks.isEmpty()) continue; + + Map, List> byClass = initTasks.stream().collect(Collectors.groupingBy(Method::getDeclaringClass)); + Set left = new HashSet<>(initTasks); + + for (Method m; (m = left.stream().findAny().orElse(null)) != null; ) { + reflectInit(m, annotation, left, byClass); + } } } } diff --git a/src/main/java/meteordevelopment/meteorclient/utils/entity/TargetUtils.java b/src/main/java/meteordevelopment/meteorclient/utils/entity/TargetUtils.java index bf852e0823..92f9e2b00a 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/entity/TargetUtils.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/entity/TargetUtils.java @@ -13,8 +13,8 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.GameMode; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; diff --git a/src/main/java/meteordevelopment/meteorclient/utils/network/FailedHttpResponse.java b/src/main/java/meteordevelopment/meteorclient/utils/network/FailedHttpResponse.java index c108179288..202989d31f 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/network/FailedHttpResponse.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/network/FailedHttpResponse.java @@ -5,7 +5,8 @@ package meteordevelopment.meteorclient.utils.network; -import javax.annotation.Nullable; +import org.jetbrains.annotations.Nullable; + import javax.net.ssl.SSLSession; import java.net.URI; import java.net.http.HttpClient; diff --git a/src/main/java/meteordevelopment/meteorclient/utils/network/Http.java b/src/main/java/meteordevelopment/meteorclient/utils/network/Http.java index 9245689f6f..7dfdf30373 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/network/Http.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/network/Http.java @@ -8,8 +8,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import meteordevelopment.meteorclient.utils.other.JsonDateDeserializer; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Type; diff --git a/src/main/java/meteordevelopment/meteorclient/utils/network/PacketUtilsUtil.java b/src/main/java/meteordevelopment/meteorclient/utils/network/PacketUtilsUtil.java index c82981f035..851b4dd307 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/network/PacketUtilsUtil.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/network/PacketUtilsUtil.java @@ -5,23 +5,22 @@ package meteordevelopment.meteorclient.utils.network; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; import net.minecraft.network.packet.BundlePacket; import net.minecraft.network.packet.BundleSplitterPacket; import net.minecraft.network.packet.Packet; -import org.reflections.Reflections; -import org.reflections.scanners.Scanners; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; import java.util.Comparator; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.function.Predicate; +import java.util.stream.Collectors; -public class PacketUtilsUtil { +public final class PacketUtilsUtil { private PacketUtilsUtil() { } @@ -34,106 +33,108 @@ public static void main(String[] args) { } public static void init() throws IOException { - // Generate PacketUtils.java - File file = new File("src/main/java/%s/PacketUtils.java".formatted(PacketUtilsUtil.class.getPackageName().replace('.', '/'))); - if (!file.exists()) { - file.getParentFile().mkdirs(); - file.createNewFile(); - } - - try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { - writer.write("/*\n"); - writer.write(" * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client/).\n"); - writer.write(" * Copyright (c) Meteor Development.\n"); - writer.write(" */\n\n"); - - writer.write("package meteordevelopment.meteorclient.utils.network;\n\n"); - - // Write imports - writer.write("import com.google.common.collect.Sets;\n"); - writer.write("import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;\n"); - writer.write("import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;\n"); - writer.write("import net.minecraft.network.packet.Packet;\n\n"); - - writer.write("import java.util.Map;\n"); - writer.write("import java.util.Set;\n"); - - // Write class - writer.write("\npublic class PacketUtils {\n"); - - // Write fields - writer.write(" private static final Map>, String> S2C_PACKETS = new Reference2ObjectOpenHashMap<>();\n"); - writer.write(" private static final Map>, String> C2S_PACKETS = new Reference2ObjectOpenHashMap<>();\n\n"); - writer.write(" private static final Map>> S2C_PACKETS_R = new Object2ReferenceOpenHashMap<>();\n"); - writer.write(" private static final Map>> C2S_PACKETS_R = new Object2ReferenceOpenHashMap<>();\n\n"); - writer.write(" public static final Set>> PACKETS = Sets.union(getC2SPackets(), getS2CPackets());\n\n"); - - // Write static block - writer.write(" static {\n"); - - // Process packets - processPackets(writer, "net.minecraft.network.packet.c2s", "C2S_PACKETS", "C2S_PACKETS_R", - packet -> false // No exclusions for C2S packets - ); - writer.newLine(); - processPackets(writer, "net.minecraft.network.packet.s2c", "S2C_PACKETS", "S2C_PACKETS_R", - packet -> BundlePacket.class.isAssignableFrom(packet) || BundleSplitterPacket.class.isAssignableFrom(packet) - ); - - writer.write(" }\n\n"); - - writer.write(" private PacketUtils() {\n"); - writer.write(" }\n\n"); - - // Write getName method - writer.write(" public static String getName(Class> packetClass) {\n"); - writer.write(" String name = S2C_PACKETS.get(packetClass);\n"); - writer.write(" if (name != null) return name;\n"); - writer.write(" return C2S_PACKETS.get(packetClass);\n"); - writer.write(" }\n\n"); - - // Write getPacket method - writer.write(" public static Class> getPacket(String name) {\n"); - writer.write(" Class> packet = S2C_PACKETS_R.get(name);\n"); - writer.write(" if (packet != null) return packet;\n"); - writer.write(" return C2S_PACKETS_R.get(name);\n"); - writer.write(" }\n\n"); - - // Write getS2CPackets method - writer.write(" public static Set>> getS2CPackets() {\n"); - writer.write(" return S2C_PACKETS.keySet();\n"); - writer.write(" }\n\n"); - - // Write getC2SPackets method - writer.write(" public static Set>> getC2SPackets() {\n"); - writer.write(" return C2S_PACKETS.keySet();\n"); - writer.write(" }\n"); - - // Write end class - writer.write("}\n"); - } + // Target path + Path filePath = Path.of( + "src", "main", "java", + PacketUtilsUtil.class.getPackageName().replace('.', File.separatorChar), + "PacketUtils.java" + ); + + Files.createDirectories(filePath.getParent()); + + // Generate mappings + String c2sMappings = processPackets("net.minecraft.network.packet.c2s", "C2S_PACKETS", "C2S_PACKETS_R", + packet -> false + ); + String s2cMappings = processPackets("net.minecraft.network.packet.s2c", "S2C_PACKETS", "S2C_PACKETS_R", + packet -> BundlePacket.class.isAssignableFrom(packet) || BundleSplitterPacket.class.isAssignableFrom(packet) + ); + + // Write to file + String content = """ + /* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client/). + * Copyright (c) Meteor Development. + */ + + package meteordevelopment.meteorclient.utils.network; + + import com.google.common.collect.Sets; + import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; + import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; + import net.minecraft.network.packet.Packet; + + import java.util.Map; + import java.util.Set; + + public class PacketUtils { + private static final Map>, String> S2C_PACKETS = new Reference2ObjectOpenHashMap<>(); + private static final Map>, String> C2S_PACKETS = new Reference2ObjectOpenHashMap<>(); + + private static final Map>> S2C_PACKETS_R = new Object2ReferenceOpenHashMap<>(); + private static final Map>> C2S_PACKETS_R = new Object2ReferenceOpenHashMap<>(); + + public static final Set>> PACKETS = Sets.union(getC2SPackets(), getS2CPackets()); + + static { + %s + + %s + } + + private PacketUtils() { + } + + public static String getName(Class> packetClass) { + String name = S2C_PACKETS.get(packetClass); + if (name != null) return name; + return C2S_PACKETS.get(packetClass); + } + + public static Class> getPacket(String name) { + Class> packet = S2C_PACKETS_R.get(name); + if (packet != null) return packet; + return C2S_PACKETS_R.get(name); + } + + public static Set>> getS2CPackets() { + return S2C_PACKETS.keySet(); + } + + public static Set>> getC2SPackets() { + return C2S_PACKETS.keySet(); + } + } + """.formatted( + c2sMappings.indent(8).stripTrailing(), + s2cMappings.indent(8).stripTrailing() + ); + + Files.writeString(filePath, content, StandardCharsets.UTF_8); } - @SuppressWarnings("rawtypes") - private static void processPackets(BufferedWriter writer, String packageName, String packetMapName, String reverseMapName, Predicate> exclusionFilter) throws IOException { - Comparator> packetsComparator = Comparator - .comparing((Class cls) -> cls.getName().substring(cls.getName().lastIndexOf('.') + 1)) - .thenComparing(Class::getName); - - Reflections reflections = new Reflections(packageName, Scanners.SubTypes); - Set> packets = reflections.getSubTypesOf(Packet.class); - SortedSet> sortedPackets = new TreeSet<>(packetsComparator); - sortedPackets.addAll(packets); - - for (Class packet : sortedPackets) { - if (exclusionFilter.test(packet)) continue; - - String name = packet.getName(); - String className = name.substring(name.lastIndexOf('.') + 1).replace('$', '.'); - String fullName = name.replace('$', '.'); - - writer.write(" %s.put(%s.class, \"%s\");%n".formatted(packetMapName, fullName, className)); - writer.write(" %s.put(\"%s\", %s.class);%n".formatted(reverseMapName, className, fullName)); + private static String processPackets(String packageName, String packetMapName, String reverseMapName, Predicate> exclusionFilter) { + try (ScanResult scanResult = new ClassGraph() + .acceptPackages(packageName) + .enableClassInfo() + .ignoreClassVisibility() + .scan()) { + + return scanResult.getClassesImplementing(Packet.class).stream() + .map(ClassInfo::loadClass) + .filter(exclusionFilter.negate()) + .sorted(Comparator + .comparing((Class cls) -> cls.getName().substring(cls.getName().lastIndexOf('.') + 1)) + .thenComparing(Class::getName) + ) + .map(packet -> { + String name = packet.getName(); + String className = name.substring(name.lastIndexOf('.') + 1).replace('$', '.'); + String fullName = name.replace('$', '.'); + return "%s.put(%s.class, \"%s\");%n%s.put(\"%s\", %s.class);" + .formatted(packetMapName, fullName, className, reverseMapName, className, fullName); + }) + .collect(Collectors.joining("\n")); } } }