1
0
mirror of https://github.com/GeyserMC/Floodgate.git synced 2025-12-19 14:59:20 +00:00

Use newly added BungeeCord ChannelInitializer API (#575)

* Update BungeeInjector.java

* Update bungee version

* Add a message when running an outdated Bungee version
This commit is contained in:
Outfluencer
2025-02-16 15:36:11 +01:00
committed by GitHub
parent 2deccf3144
commit 0e3163c942
2 changed files with 27 additions and 151 deletions

View File

@@ -1,4 +1,4 @@
var bungeeVersion = "1.20-R0.3-SNAPSHOT" var bungeeVersion = "1.21-R0.1-SNAPSHOT"
var gsonVersion = "2.8.0" var gsonVersion = "2.8.0"
var guavaVersion = "21.0" var guavaVersion = "21.0"

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * Copyright (c) 2019-2025 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -26,86 +26,46 @@
package org.geysermc.floodgate.inject.bungee; package org.geysermc.floodgate.inject.bungee;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.md_5.bungee.netty.PipelineUtils; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.protocol.MinecraftEncoder; import net.md_5.bungee.api.ProxyServer.Unsafe;
import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender; import net.md_5.bungee.protocol.channel.BungeeChannelInitializer;
import net.md_5.bungee.protocol.Varint21LengthFieldPrepender;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.inject.CommonPlatformInjector; import org.geysermc.floodgate.inject.CommonPlatformInjector;
import org.geysermc.floodgate.util.BungeeReflectionUtils;
import org.geysermc.floodgate.util.ReflectionUtils;
@RequiredArgsConstructor @RequiredArgsConstructor
public final class BungeeInjector extends CommonPlatformInjector { public final class BungeeInjector extends CommonPlatformInjector {
private static final String BUNGEE_INIT = "floodgate-bungee-init";
private final FloodgateLogger logger; private final FloodgateLogger logger;
@Getter private boolean injected; @Getter private boolean injected;
@Override @Override
public void inject() { public void inject() {
// Can everyone just switch to Velocity please :) try {
// :( ~BungeeCord Collaborator ProxyServer.getInstance().unsafe();
} catch (NoSuchMethodError ignored) {
// Newer Bungee versions have a separate prepender for backend and client connections logger.error("You're running an outdated version of BungeeCord. Please update BungeeCord to the latest version!");
// this field is not touched by client -> proxy throw new Error("You're running an outdated version of BungeeCord. Please update BungeeCord to the latest version!");
Field serverFramePrepender =
ReflectionUtils.getField(PipelineUtils.class, "serverFramePrepender");
if (serverFramePrepender != null) {
BungeeCustomServerPrepender customServerPrepender = new BungeeCustomServerPrepender(
this, ReflectionUtils.castedStaticValue(serverFramePrepender)
);
BungeeReflectionUtils.setFieldValue(null, serverFramePrepender, customServerPrepender);
} }
// for backwards compatibility Unsafe unsafe = ProxyServer.getInstance().unsafe();
Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender"); BungeeChannelInitializer frontend = unsafe.getFrontendChannelInitializer();
if (framePrepender != null) { unsafe.setFrontendChannelInitializer(BungeeChannelInitializer.create(channel -> {
logger.warn("You are running an old version of BungeeCord consider updating to a newer version"); if (!frontend.getChannelAcceptor().accept(channel)) {
// Required in order to inject into both Geyser <-> proxy AND proxy <-> server return false;
// (Instead of just replacing the ChannelInitializer which is only called for }
// player <-> proxy) injectClient(channel, true);
BungeeCustomPrepender customPrepender = new BungeeCustomPrepender( return true;
this, ReflectionUtils.castedStaticValue(framePrepender) }));
);
BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender);
} else {
// wrap the client -> proxy channel init because the framePrepender field was deleted
ChannelInitializer<Channel> original = PipelineUtils.SERVER_CHILD;
Field clientChannelInitField = ReflectionUtils.getField(
PipelineUtils.class, "SERVER_CHILD"
);
Method initChannelMethod = ReflectionUtils.getMethod(
original.getClass(), "initChannel", Channel.class
);
ChannelInitializer<Channel> wrapper = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) {
ReflectionUtils.invoke(original, initChannelMethod, channel);
// Check if the channel is open, see #547
if (!channel.isOpen()) {
return;
}
channel.pipeline().addBefore(
PipelineUtils.FRAME_DECODER, BUNGEE_INIT,
new BungeeClientToProxyInjectInitializer(BungeeInjector.this)
);
}
};
BungeeReflectionUtils.setFieldValue(null, clientChannelInitField, wrapper);
}
BungeeChannelInitializer backend = unsafe.getBackendChannelInitializer();
unsafe.setBackendChannelInitializer(BungeeChannelInitializer.create(channel -> {
if (!backend.getChannelAcceptor().accept(channel)) {
return false;
}
injectClient(channel, false);
return true;
}));
injected = true; injected = true;
} }
@@ -121,91 +81,7 @@ public final class BungeeInjector extends CommonPlatformInjector {
} }
void injectClient(Channel channel, boolean clientToProxy) { void injectClient(Channel channel, boolean clientToProxy) {
if (!channel.isOpen()) {
return;
}
if (channel.pipeline().get(MinecraftEncoder.class) == null) {
logger.debug(
"Minecraft encoder not found while injecting! {}",
String.join(", ", channel.pipeline().names())
);
return;
}
injectAddonsCall(channel, !clientToProxy); injectAddonsCall(channel, !clientToProxy);
addInjectedClient(channel); addInjectedClient(channel);
} }
@RequiredArgsConstructor
private static final class BungeeCustomPrepender extends Varint21LengthFieldPrepender {
private final BungeeInjector injector;
private final Varint21LengthFieldPrepender original;
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
original.handlerAdded(ctx);
// The Minecraft encoder being in the pipeline isn't present until later
if (ctx.channel().parent() != null) {
// Client <-> Proxy
ctx.pipeline().addBefore(
PipelineUtils.FRAME_DECODER, BUNGEE_INIT,
new BungeeClientToProxyInjectInitializer(injector)
);
} else {
// Proxy <-> Server
ctx.pipeline().addLast(
BUNGEE_INIT, new BungeeProxyToServerInjectInitializer(injector)
);
}
}
}
@RequiredArgsConstructor
private static final class BungeeCustomServerPrepender
extends Varint21LengthFieldExtraBufPrepender {
private final BungeeInjector injector;
private final Varint21LengthFieldExtraBufPrepender original;
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
original.handlerAdded(ctx);
// The Minecraft encoder being in the pipeline isn't present until later
// Proxy <-> Server
ctx.pipeline().addLast(BUNGEE_INIT, new BungeeProxyToServerInjectInitializer(injector));
}
}
@RequiredArgsConstructor
private static final class BungeeClientToProxyInjectInitializer
extends ChannelInboundHandlerAdapter {
private final BungeeInjector injector;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
injector.injectClient(ctx.channel(), true);
ctx.pipeline().remove(this);
super.channelRead(ctx, msg);
}
}
@RequiredArgsConstructor
private static final class BungeeProxyToServerInjectInitializer
extends ChannelOutboundHandlerAdapter {
private final BungeeInjector injector;
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
throws Exception {
injector.injectClient(ctx.channel(), false);
ctx.pipeline().remove(this);
super.write(ctx, msg, promise);
}
}
} }