mirror of
https://github.com/GeyserMC/Floodgate.git
synced 2025-12-19 14:59:20 +00:00
1.20.2 Support (#449)
* Spigot 1.20.2 Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Oops Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * 1.20.2 velocity (#1) * 1.20.2 Velocity Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Archive build artifacts Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Fix typo in velocity-plugin.json Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Fix formatting and apply codestyle to eclipse Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Ignore changes to core base prefs Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Proper ignore Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Remove buildship prefs Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Formatting Signed-off-by: GitHub <noreply@github.com> * Formatting Signed-off-by: GitHub <noreply@github.com> * Properly build PRs * Formatting + remove artifacts Signed-off-by: GitHub <noreply@github.com> * Throw IllegalStateException Signed-off-by: GitHub <noreply@github.com> --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> Signed-off-by: GitHub <noreply@github.com>
This commit is contained in:
5
.github/workflows/pullrequest.yml
vendored
5
.github/workflows/pullrequest.yml
vendored
@@ -8,7 +8,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout repository and submodules
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v2
|
||||
|
||||
@@ -31,6 +31,7 @@ import static org.geysermc.floodgate.util.ReflectionUtils.setValue;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.util.AttributeKey;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||
@@ -57,9 +58,27 @@ public final class SpigotDataHandler extends CommonDataHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object setHostname(Object handshakePacket, String hostname) {
|
||||
setValue(handshakePacket, ClassNames.HANDSHAKE_HOST, hostname);
|
||||
return handshakePacket;
|
||||
protected Object setHostname(Object handshakePacket, String hostname) throws IllegalStateException {
|
||||
if (ClassNames.IS_PRE_1_20_2) {
|
||||
// 1.20.1 and below
|
||||
setValue(handshakePacket, ClassNames.HANDSHAKE_HOST, hostname);
|
||||
|
||||
return handshakePacket;
|
||||
} else {
|
||||
// 1.20.2 and above
|
||||
try {
|
||||
Object[] components = new Object[]{
|
||||
ClassNames.HANDSHAKE_PORT.get(handshakePacket),
|
||||
hostname,
|
||||
ClassNames.HANDSHAKE_PROTOCOL.get(handshakePacket),
|
||||
ClassNames.HANDSHAKE_INTENTION.get(handshakePacket)
|
||||
};
|
||||
|
||||
return ClassNames.HANDSHAKE_PACKET_CONSTRUCTOR.newInstance(components);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalStateException("Failed to create new Handshake packet", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,16 +176,23 @@ public final class SpigotDataHandler extends CommonDataHandler {
|
||||
// we have to fake the offline player (login) cycle
|
||||
// just like on Spigot:
|
||||
|
||||
// LoginListener#initUUID
|
||||
// new LoginHandler().fireEvents();
|
||||
Object loginHandler = ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener);
|
||||
|
||||
// and the tick of LoginListener will do the rest
|
||||
if (ClassNames.IS_PRE_1_20_2) {
|
||||
// 1.20.1 and below
|
||||
|
||||
ClassNames.INIT_UUID.invoke(packetListener);
|
||||
// LoginListener#initUUID
|
||||
// new LoginHandler().fireEvents();
|
||||
|
||||
Object loginHandler =
|
||||
ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener);
|
||||
ClassNames.FIRE_LOGIN_EVENTS.invoke(loginHandler);
|
||||
// and the tick of LoginListener will do the rest
|
||||
|
||||
ClassNames.INIT_UUID.invoke(packetListener);
|
||||
ClassNames.FIRE_LOGIN_EVENTS.invoke(loginHandler);
|
||||
} else {
|
||||
// 1.20.2 and above we directly register the profile
|
||||
|
||||
ClassNames.FIRE_LOGIN_EVENTS_GAME_PROFILE.invoke(loginHandler, gameProfile);
|
||||
}
|
||||
|
||||
ctx.pipeline().remove(this);
|
||||
return true;
|
||||
|
||||
@@ -29,11 +29,13 @@ import static org.geysermc.floodgate.util.ReflectionUtils.castedStaticBooleanVal
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.getBooleanValue;
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.getClassOrFallback;
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.getClassSilently;
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.getConstructor;
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.getField;
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType;
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.getMethod;
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.getValue;
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.invoke;
|
||||
import static org.geysermc.floodgate.util.ReflectionUtils.makeAccessible;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
@@ -58,27 +60,35 @@ public class ClassNames {
|
||||
public static final Class<?> LOGIN_START_PACKET;
|
||||
public static final Class<?> LOGIN_LISTENER;
|
||||
public static final Class<?> LOGIN_HANDLER;
|
||||
@Nullable public static final Class<?> CLIENT_INTENT;
|
||||
|
||||
public static final Constructor<OfflinePlayer> CRAFT_OFFLINE_PLAYER_CONSTRUCTOR;
|
||||
public static final Constructor<?> LOGIN_HANDLER_CONSTRUCTOR;
|
||||
@Nullable public static final Constructor<?> HANDSHAKE_PACKET_CONSTRUCTOR;
|
||||
|
||||
public static final Field SOCKET_ADDRESS;
|
||||
public static final Field HANDSHAKE_HOST;
|
||||
public static final Field LOGIN_PROFILE;
|
||||
public static final Field PACKET_LISTENER;
|
||||
|
||||
@Nullable public static final Field HANDSHAKE_PORT;
|
||||
@Nullable public static final Field HANDSHAKE_PROTOCOL;
|
||||
@Nullable public static final Field HANDSHAKE_INTENTION;
|
||||
|
||||
@Nullable public static final Field PAPER_DISABLE_USERNAME_VALIDATION;
|
||||
@Nullable public static final BooleanSupplier PAPER_VELOCITY_SUPPORT;
|
||||
|
||||
public static final Method GET_PROFILE_METHOD;
|
||||
public static final Method LOGIN_DISCONNECT;
|
||||
public static final Method NETWORK_EXCEPTION_CAUGHT;
|
||||
public static final Method INIT_UUID;
|
||||
public static final Method FIRE_LOGIN_EVENTS;
|
||||
@Nullable public static final Method INIT_UUID;
|
||||
@Nullable public static final Method FIRE_LOGIN_EVENTS;
|
||||
@Nullable public static final Method FIRE_LOGIN_EVENTS_GAME_PROFILE;
|
||||
|
||||
public static final Field BUNGEE;
|
||||
|
||||
public static final boolean IS_FOLIA;
|
||||
public static final boolean IS_PRE_1_20_2;
|
||||
|
||||
static {
|
||||
String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
@@ -153,14 +163,24 @@ public class ClassNames {
|
||||
);
|
||||
|
||||
// there are multiple no-arg void methods
|
||||
// Pre 1.20.2 uses initUUID so if it's null, we're on 1.20.2 or later
|
||||
INIT_UUID = getMethod(LOGIN_LISTENER, "initUUID");
|
||||
checkNotNull(INIT_UUID, "initUUID from LoginListener");
|
||||
IS_PRE_1_20_2 = INIT_UUID != null;
|
||||
|
||||
Class<?> packetListenerClass = getClassOrFallback(
|
||||
"net.minecraft.network.PacketListener",
|
||||
nmsPackage + "PacketListener"
|
||||
);
|
||||
PACKET_LISTENER = getFieldOfType(networkManager, packetListenerClass);
|
||||
if (IS_PRE_1_20_2) {
|
||||
Class<?> packetListenerClass = getClassOrFallback(
|
||||
"net.minecraft.network.PacketListener",
|
||||
nmsPackage + "PacketListener"
|
||||
);
|
||||
|
||||
PACKET_LISTENER = getFieldOfType(networkManager, packetListenerClass);
|
||||
} else {
|
||||
// We get the field by name on 1.20.2+ as there are now multiple fields of this type in network manager
|
||||
|
||||
// PacketListener packetListener of NetworkManager
|
||||
PACKET_LISTENER = getField(networkManager, "q");
|
||||
makeAccessible(PACKET_LISTENER);
|
||||
}
|
||||
checkNotNull(PACKET_LISTENER, "Packet listener");
|
||||
|
||||
LOGIN_HANDLER = getClassOrFallback(
|
||||
@@ -173,8 +193,11 @@ public class ClassNames {
|
||||
checkNotNull(LOGIN_HANDLER_CONSTRUCTOR, "LoginHandler constructor");
|
||||
|
||||
FIRE_LOGIN_EVENTS = getMethod(LOGIN_HANDLER, "fireEvents");
|
||||
checkNotNull(FIRE_LOGIN_EVENTS, "fireEvents from LoginHandler");
|
||||
|
||||
// LoginHandler().fireEvents(GameProfile)
|
||||
FIRE_LOGIN_EVENTS_GAME_PROFILE = getMethod(LOGIN_HANDLER, "fireEvents", GameProfile.class);
|
||||
checkNotNull(FIRE_LOGIN_EVENTS, FIRE_LOGIN_EVENTS_GAME_PROFILE,
|
||||
"fireEvents from LoginHandler", "fireEvents(GameProfile) from LoginHandler");
|
||||
|
||||
PAPER_DISABLE_USERNAME_VALIDATION = getField(LOGIN_LISTENER,
|
||||
"iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation");
|
||||
@@ -229,9 +252,53 @@ public class ClassNames {
|
||||
IS_FOLIA = ReflectionUtils.getClassSilently(
|
||||
"io.papermc.paper.threadedregions.RegionizedServer"
|
||||
) != null;
|
||||
|
||||
if (!IS_PRE_1_20_2) {
|
||||
// PacketHandshakingInSetProtocol is now a record
|
||||
// This means its fields are now private and final
|
||||
// We therefore must use reflection to obtain the constructor
|
||||
CLIENT_INTENT = getClassOrFallback(
|
||||
"net.minecraft.network.protocol.handshake.ClientIntent",
|
||||
nmsPackage + "ClientIntent"
|
||||
);
|
||||
checkNotNull(CLIENT_INTENT, "Client intent enum");
|
||||
|
||||
HANDSHAKE_PACKET_CONSTRUCTOR = getConstructor(HANDSHAKE_PACKET, false, int.class,
|
||||
String.class, int.class, CLIENT_INTENT);
|
||||
checkNotNull(HANDSHAKE_PACKET_CONSTRUCTOR, "Handshake packet constructor");
|
||||
|
||||
HANDSHAKE_PORT = getField(HANDSHAKE_PACKET, "a");
|
||||
checkNotNull(HANDSHAKE_PORT, "Handshake port");
|
||||
makeAccessible(HANDSHAKE_PORT);
|
||||
|
||||
HANDSHAKE_PROTOCOL = getField(HANDSHAKE_PACKET, "c");
|
||||
checkNotNull(HANDSHAKE_PROTOCOL, "Handshake protocol");
|
||||
makeAccessible(HANDSHAKE_PROTOCOL);
|
||||
|
||||
HANDSHAKE_INTENTION = getFieldOfType(HANDSHAKE_PACKET, CLIENT_INTENT);
|
||||
checkNotNull(HANDSHAKE_INTENTION, "Handshake intention");
|
||||
makeAccessible(HANDSHAKE_INTENTION);
|
||||
} else {
|
||||
CLIENT_INTENT = null;
|
||||
HANDSHAKE_PACKET_CONSTRUCTOR = null;
|
||||
HANDSHAKE_PORT = null;
|
||||
HANDSHAKE_PROTOCOL = null;
|
||||
HANDSHAKE_INTENTION = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T checkNotNull(@CheckForNull T toCheck, @CheckForNull String objectName) {
|
||||
return Preconditions.checkNotNull(toCheck, objectName + " cannot be null");
|
||||
}
|
||||
|
||||
// Ensure one of two is not null
|
||||
private static <T> T checkNotNull(
|
||||
@CheckForNull T toCheck,
|
||||
@CheckForNull T toCheck2,
|
||||
@CheckForNull String objectName,
|
||||
@CheckForNull String objectName2
|
||||
) {
|
||||
return Preconditions.checkNotNull(toCheck != null ? toCheck : toCheck2,
|
||||
objectName2 + " cannot be null if " + objectName + " is null");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
var velocityVersion = "3.1.1"
|
||||
var velocityVersion = "3.2.0-SNAPSHOT"
|
||||
var log4jVersion = "2.11.2"
|
||||
var gsonVersion = "2.8.8"
|
||||
var guavaVersion = "25.1-jre"
|
||||
|
||||
indra {
|
||||
javaVersions {
|
||||
// For Velocity API
|
||||
target(11)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.core)
|
||||
implementation("cloud.commandframework", "cloud-velocity", Versions.cloudVersion)
|
||||
|
||||
@@ -76,7 +76,13 @@ public final class VelocityProxyDataHandler extends CommonDataHandler {
|
||||
SERVER_LOGIN_PACKET = getPrefixedClass("protocol.packet.ServerLogin");
|
||||
checkNotNull(SERVER_LOGIN_PACKET, "ServerLogin packet class cannot be null");
|
||||
|
||||
GET_SESSION_HANDLER = getMethodByName(minecraftConnection, "getSessionHandler", true);
|
||||
|
||||
Method sessionHandler = getMethodByName(minecraftConnection, "getSessionHandler", true);
|
||||
if (sessionHandler == null) {
|
||||
// We are 1.20.2+
|
||||
sessionHandler = getMethodByName(minecraftConnection, "getActiveSessionHandler", true);
|
||||
}
|
||||
GET_SESSION_HANDLER = sessionHandler;
|
||||
checkNotNull(GET_SESSION_HANDLER, "getSessionHandler method cannot be null");
|
||||
|
||||
INITIAL_LOGIN_SESSION_HANDLER =
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"id": "${id}", "name": "${name}", "version": "${version}", "description": "${description}", "url": "$url}", "authors": ["${author}"], "main": "org.geysermc.floodgate.VelocityPlugin"}
|
||||
{"id": "${id}", "name": "${name}", "version": "${version}", "description": "${description}", "url": "${url}", "authors": ["${author}"], "main": "org.geysermc.floodgate.VelocityPlugin"}
|
||||
Reference in New Issue
Block a user