|
11 | 11 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; |
12 | 12 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; |
13 | 13 | import net.fabricmc.loader.api.FabricLoader; |
| 14 | +import net.fabricmc.loader.api.ModContainer; |
14 | 15 | import net.minecraft.core.BlockPos; |
15 | 16 | import net.minecraft.network.FriendlyByteBuf; |
16 | 17 | import net.minecraft.network.protocol.Packet; |
|
19 | 20 | import net.minecraft.world.item.ItemStack; |
20 | 21 | import net.minecraft.world.level.block.state.BlockState; |
21 | 22 | import org.jetbrains.annotations.NotNull; |
22 | | -import org.reflections.Reflections; |
| 23 | +import org.objectweb.asm.*; |
| 24 | + |
23 | 25 |
|
24 | 26 | import java.io.File; |
| 27 | +import java.io.IOException; |
| 28 | +import java.io.InputStream; |
| 29 | +import java.io.UncheckedIOException; |
25 | 30 | import java.lang.annotation.Annotation; |
| 31 | +import java.nio.file.FileSystem; |
| 32 | +import java.nio.file.FileSystems; |
| 33 | +import java.nio.file.Files; |
| 34 | +import java.nio.file.Path; |
| 35 | +import java.util.ArrayList; |
26 | 36 | import java.util.List; |
27 | 37 | import java.util.Set; |
28 | | - |
29 | | -import static org.reflections.scanners.Scanners.SubTypes; |
30 | | -import static org.reflections.scanners.Scanners.TypesAnnotated; |
| 38 | +import java.util.stream.Stream; |
31 | 39 |
|
32 | 40 | public class FabricModLoader implements ModLoader { |
33 | 41 | private final File configFolder = net.fabricmc.loader.api.FabricLoader.getInstance() |
@@ -73,19 +81,74 @@ public double getItemEntityReach(double baseRange, ItemStack itemStack, Equipmen |
73 | 81 | } |
74 | 82 |
|
75 | 83 |
|
76 | | - @Override |
77 | | - public @NotNull List<Class<?>> getClassesAnnotated(@NotNull Class<? extends Annotation> annotation, |
78 | | - @NotNull String modId, |
79 | | - @NotNull String packagePath) { |
80 | | - Reflections reflections = new Reflections( |
81 | | - packagePath, |
82 | | - SubTypes, TypesAnnotated |
83 | | - ); |
84 | | - |
85 | | - Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(annotation); |
86 | | - return annotated.stream().toList(); |
| 84 | + public @NotNull List<Class<?>> getClassesAnnotated( |
| 85 | + @NotNull Class<? extends Annotation> annotation, |
| 86 | + @NotNull String modId, |
| 87 | + @NotNull String packagePath |
| 88 | + ) { |
| 89 | + try { |
| 90 | + List<Class<?>> result = new ArrayList<>(); |
| 91 | + |
| 92 | + // Locate our mod container |
| 93 | + ModContainer container = FabricLoader.getInstance() |
| 94 | + .getModContainer(modId) |
| 95 | + .orElseThrow(() -> new IllegalArgumentException("Unknown mod: " + modId)); |
| 96 | + |
| 97 | + // Convert package to path form |
| 98 | + String pkgPath = packagePath.replace('.', '/'); |
| 99 | + |
| 100 | + // Iterate every root (jar or folder) |
| 101 | + for (Path root : container.getRootPaths()) { |
| 102 | + // resolve into each root |
| 103 | + Path pkgRoot = root.resolve(pkgPath); |
| 104 | + if (!Files.exists(pkgRoot)) continue; |
| 105 | + |
| 106 | + try (Stream<Path> stream = Files.walk(pkgRoot)) { |
| 107 | + stream |
| 108 | + .filter(p -> p.getFileName().toString().endsWith(".class")) |
| 109 | + .forEach(classFile -> { |
| 110 | + try (InputStream in = Files.newInputStream(classFile)) { |
| 111 | + ClassReader reader = new ClassReader(in); |
| 112 | + reader.accept(new ClassVisitor(Opcodes.ASM9) { |
| 113 | + @Override |
| 114 | + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { |
| 115 | + String found = Type.getType(desc).getClassName(); |
| 116 | + if (found.equals(annotation.getName())) { |
| 117 | + // reconstruct FQCN from path |
| 118 | + Path rel = pkgRoot.relativize(classFile); |
| 119 | + String className = packagePath + "." |
| 120 | + + rel.toString() |
| 121 | + .replace('/', '.') |
| 122 | + .replace('\\', '.') |
| 123 | + .replaceAll("\\.class$", ""); |
| 124 | + try { |
| 125 | + result.add( |
| 126 | + Class.forName( |
| 127 | + className, |
| 128 | + false, |
| 129 | + Thread.currentThread().getContextClassLoader() |
| 130 | + ) |
| 131 | + ); |
| 132 | + } catch (ClassNotFoundException e) { |
| 133 | + throw new RuntimeException(e); |
| 134 | + } |
| 135 | + } |
| 136 | + return super.visitAnnotation(desc, visible); |
| 137 | + } |
| 138 | + }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); |
| 139 | + } catch (IOException e) { |
| 140 | + throw new UncheckedIOException(e); |
| 141 | + } |
| 142 | + }); |
| 143 | + } |
| 144 | + } |
| 145 | + return result; |
| 146 | + }catch (Exception e){ |
| 147 | + throw new RuntimeException(e); |
| 148 | + } |
87 | 149 | } |
88 | 150 |
|
| 151 | + |
89 | 152 | @Override |
90 | 153 | public @NotNull Packet<?> createPacketToClient(@NotNull VisorPayloadToClient payload) { |
91 | 154 | FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer()); |
|
0 commit comments