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:
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
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;
|
||||
}));
|
||||
|
||||
channel.pipeline().addBefore(
|
||||
PipelineUtils.FRAME_DECODER, BUNGEE_INIT,
|
||||
new BungeeClientToProxyInjectInitializer(BungeeInjector.this)
|
||||
);
|
||||
BungeeChannelInitializer backend = unsafe.getBackendChannelInitializer();
|
||||
unsafe.setBackendChannelInitializer(BungeeChannelInitializer.create(channel -> {
|
||||
if (!backend.getChannelAcceptor().accept(channel)) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
BungeeReflectionUtils.setFieldValue(null, clientChannelInitField, wrapper);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user