Skip to content

Commit

Permalink
fix(spigot): look up fields/methods based on type and predicate inste…
Browse files Browse the repository at this point in the history
…ad of hardcoding obfuscated field names
  • Loading branch information
radstevee committed Nov 1, 2024
1 parent 4f1ac10 commit 0c3e865
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 5 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ yarn_mappings=1.21.1+build.3
loader_version=0.16.7

# Mod Properties
version=2.1.0
version=2.1.1
group=net.mcbrawls.inject
id=inject

Expand Down
14 changes: 14 additions & 0 deletions spigot/src/main/java/net/mcbrawls/inject/spigot/InjectSpigot.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,25 @@ public class InjectSpigot implements InjectPlatform {
private InjectSpigot() {
}

private boolean isRunningPaper() {
try {
Class.forName("com.destroystokyo.paper.PaperConfig");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}

@Override
public void registerInjector(Injector injector) {
injectors.add(injector);

if (!hasInitialized) {
if (isRunningPaper()) {
LOGGER.warning("It looks like you are running Paper - Inject Spigot is unsupported on Paper!");
LOGGER.warning("Please use Inject Paper instead!");
}

new ClientConnectionInterceptor().install((channel) -> {
var pipeline = channel.pipeline();
injectors.forEach(pipeline::addFirst);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

public class ClientConnectionInterceptor {

Expand Down Expand Up @@ -44,6 +47,22 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
}
}

private Method getMethodByReturnType(Class<?> clazz, Class<?> returnType) {
return Arrays.stream(clazz.getDeclaredMethods())
.filter((method) -> method.getReturnType().equals(returnType))
.findFirst()
.get();
}

// Predicate is needed to make sure we find the `List<ChannelFuture> channels` instead of `List<Connection> connections`
// since `channels` is private.
private Field getFieldByTypeAndPredicate(Class<?> clazz, Class<?> type, Function<Field, Boolean> predicate) {
return Arrays.stream(clazz.getDeclaredFields())
.filter((field) -> field.getType().equals(type) && predicate.apply(field))
.findFirst()
.get();
}

private List<ChannelFuture> getChannels() {
final String serverVersion = this.getServerVersion();

Expand All @@ -55,15 +74,14 @@ private List<ChannelFuture> getChannels() {
final Method craftServerGetServerMethod = craftServerClass.getDeclaredMethod("getServer");

final Object minecraftServer = craftServerGetServerMethod.invoke(craftServerObject);
final Method getConnectionMethod = minecraftServerClass.getDeclaredMethod("ai");
final Method getConnectionMethod = getMethodByReturnType(minecraftServerClass, Class.forName("net.minecraft.server.network.ServerConnection"));

final Object serverConnection = getConnectionMethod.invoke(minecraftServer);
final Field channelsField = serverConnection.getClass().getDeclaredField("f");
final Field channelsField = getFieldByTypeAndPredicate(serverConnection.getClass(), List.class, (field) -> Modifier.isPrivate(field.getModifiers()));

channelsField.setAccessible(true);
return (List<ChannelFuture>) channelsField.get(serverConnection);
} catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException |
NoSuchFieldException e) {
} catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
Expand Down

0 comments on commit 0c3e865

Please sign in to comment.