Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down
36 changes: 25 additions & 11 deletions src/main/java/meteordevelopment/meteorclient/utils/ReflectInit.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -17,7 +18,7 @@
import java.util.stream.Collectors;

public class ReflectInit {
private static final List<Reflections> reflections = new ArrayList<>();
private static final List<String> packages = new ArrayList<>();

private ReflectInit() {
}
Expand All @@ -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<? extends Annotation> annotation) {
for (Reflections reflection : reflections) {
Set<Method> initTasks = reflection.getMethodsAnnotatedWith(annotation);
if (initTasks == null) return;
for (String pkg : packages) {
try (ScanResult scanResult = new ClassGraph()
.acceptPackages(pkg)
.enableMethodInfo()
.enableAnnotationInfo()
.scan()) {

Map<Class<?>, List<Method>> byClass = initTasks.stream().collect(Collectors.groupingBy(Method::getDeclaringClass));
Set<Method> left = new HashSet<>(initTasks);
Set<Method> 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<Class<?>, List<Method>> byClass = initTasks.stream().collect(Collectors.groupingBy(Method::getDeclaringClass));
Set<Method> left = new HashSet<>(initTasks);

for (Method m; (m = left.stream().findAny().orElse(null)) != null; ) {
reflectInit(m, annotation, left, byClass);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
}

Expand All @@ -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<Class<? extends Packet<?>>, String> S2C_PACKETS = new Reference2ObjectOpenHashMap<>();\n");
writer.write(" private static final Map<Class<? extends Packet<?>>, String> C2S_PACKETS = new Reference2ObjectOpenHashMap<>();\n\n");
writer.write(" private static final Map<String, Class<? extends Packet<?>>> S2C_PACKETS_R = new Object2ReferenceOpenHashMap<>();\n");
writer.write(" private static final Map<String, Class<? extends Packet<?>>> C2S_PACKETS_R = new Object2ReferenceOpenHashMap<>();\n\n");
writer.write(" public static final Set<Class<? extends Packet<?>>> 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<? extends Packet<?>> 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<? extends Packet<?>> getPacket(String name) {\n");
writer.write(" Class<? extends Packet<?>> 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<Class<? extends Packet<?>>> getS2CPackets() {\n");
writer.write(" return S2C_PACKETS.keySet();\n");
writer.write(" }\n\n");

// Write getC2SPackets method
writer.write(" public static Set<Class<? extends Packet<?>>> 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<Class<? extends Packet<?>>, String> S2C_PACKETS = new Reference2ObjectOpenHashMap<>();
private static final Map<Class<? extends Packet<?>>, String> C2S_PACKETS = new Reference2ObjectOpenHashMap<>();

private static final Map<String, Class<? extends Packet<?>>> S2C_PACKETS_R = new Object2ReferenceOpenHashMap<>();
private static final Map<String, Class<? extends Packet<?>>> C2S_PACKETS_R = new Object2ReferenceOpenHashMap<>();

public static final Set<Class<? extends Packet<?>>> PACKETS = Sets.union(getC2SPackets(), getS2CPackets());

static {
%s

%s
}

private PacketUtils() {
}

public static String getName(Class<? extends Packet<?>> packetClass) {
String name = S2C_PACKETS.get(packetClass);
if (name != null) return name;
return C2S_PACKETS.get(packetClass);
}

public static Class<? extends Packet<?>> getPacket(String name) {
Class<? extends Packet<?>> packet = S2C_PACKETS_R.get(name);
if (packet != null) return packet;
return C2S_PACKETS_R.get(name);
}

public static Set<Class<? extends Packet<?>>> getS2CPackets() {
return S2C_PACKETS.keySet();
}

public static Set<Class<? extends Packet<?>>> 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<Class<?>> exclusionFilter) throws IOException {
Comparator<Class<?>> packetsComparator = Comparator
.comparing((Class<?> cls) -> cls.getName().substring(cls.getName().lastIndexOf('.') + 1))
.thenComparing(Class::getName);

Reflections reflections = new Reflections(packageName, Scanners.SubTypes);
Set<Class<? extends Packet>> packets = reflections.getSubTypesOf(Packet.class);
SortedSet<Class<? extends Packet>> sortedPackets = new TreeSet<>(packetsComparator);
sortedPackets.addAll(packets);

for (Class<? extends Packet> 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<Class<?>> 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"));
}
}
}