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 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
* of this software and associated documentation files (the "Software"), to deal
@@ -26,86 +26,46 @@
package org.geysermc.floodgate.inject.bungee;
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.RequiredArgsConstructor;
import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.MinecraftEncoder;
import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender;
import net.md_5.bungee.protocol.Varint21LengthFieldPrepender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ProxyServer.Unsafe;
import net.md_5.bungee.protocol.channel.BungeeChannelInitializer;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
import org.geysermc.floodgate.util.BungeeReflectionUtils;
import org.geysermc.floodgate.util.ReflectionUtils;
@RequiredArgsConstructor
public final class BungeeInjector extends CommonPlatformInjector {
private static final String BUNGEE_INIT = "floodgate-bungee-init";
private final FloodgateLogger logger;
@Getter private boolean injected;
@Override
public void inject() {
// Can everyone just switch to Velocity please :)
// :( ~BungeeCord Collaborator
// Newer Bungee versions have a separate prepender for backend and client connections
// this field is not touched by client -> proxy
Field serverFramePrepender =
ReflectionUtils.getField(PipelineUtils.class, "serverFramePrepender");
if (serverFramePrepender != null) {
BungeeCustomServerPrepender customServerPrepender = new BungeeCustomServerPrepender(
this, ReflectionUtils.castedStaticValue(serverFramePrepender)
);
BungeeReflectionUtils.setFieldValue(null, serverFramePrepender, customServerPrepender);
try {
ProxyServer.getInstance().unsafe();
} catch (NoSuchMethodError ignored) {
logger.error("You're running an outdated version of BungeeCord. Please update BungeeCord to the latest version!");
throw new Error("You're running an outdated version of BungeeCord. Please update BungeeCord to the latest version!");
}
// for backwards compatibility
Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender");
if (framePrepender != null) {
logger.warn("You are running an old version of BungeeCord consider updating to a newer version");
// Required in order to inject into both Geyser <-> proxy AND proxy <-> server
// (Instead of just replacing the ChannelInitializer which is only called for
// player <-> proxy)
BungeeCustomPrepender customPrepender = new BungeeCustomPrepender(
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);
}
Unsafe unsafe = ProxyServer.getInstance().unsafe();
BungeeChannelInitializer frontend = unsafe.getFrontendChannelInitializer();
unsafe.setFrontendChannelInitializer(BungeeChannelInitializer.create(channel -> {
if (!frontend.getChannelAcceptor().accept(channel)) {
return false;
}
injectClient(channel, true);
return true;
}));
BungeeChannelInitializer backend = unsafe.getBackendChannelInitializer();
unsafe.setBackendChannelInitializer(BungeeChannelInitializer.create(channel -> {
if (!backend.getChannelAcceptor().accept(channel)) {
return false;
}
injectClient(channel, false);
return true;
}));
injected = true;
}
@@ -121,91 +81,7 @@ public final class BungeeInjector extends CommonPlatformInjector {
}
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);
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);
}
}
}