1
0
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:
Kas-tle
2023-09-26 10:36:02 -07:00
committed by GitHub
parent 492be77ad9
commit 26c11bdede
6 changed files with 132 additions and 23 deletions

View File

@@ -8,7 +8,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - name: Checkout repository and submodules
uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v2 uses: actions/setup-java@v2

View File

@@ -31,6 +31,7 @@ import static org.geysermc.floodgate.util.ReflectionUtils.setValue;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig;
@@ -57,9 +58,27 @@ public final class SpigotDataHandler extends CommonDataHandler {
} }
@Override @Override
protected Object setHostname(Object handshakePacket, String hostname) { protected Object setHostname(Object handshakePacket, String hostname) throws IllegalStateException {
setValue(handshakePacket, ClassNames.HANDSHAKE_HOST, hostname); if (ClassNames.IS_PRE_1_20_2) {
return handshakePacket; // 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 @Override
@@ -157,16 +176,23 @@ public final class SpigotDataHandler extends CommonDataHandler {
// we have to fake the offline player (login) cycle // we have to fake the offline player (login) cycle
// just like on Spigot: // just like on Spigot:
// LoginListener#initUUID Object loginHandler = ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener);
// new LoginHandler().fireEvents();
// 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 = // and the tick of LoginListener will do the rest
ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener);
ClassNames.FIRE_LOGIN_EVENTS.invoke(loginHandler); 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); ctx.pipeline().remove(this);
return true; return true;

View File

@@ -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.getBooleanValue;
import static org.geysermc.floodgate.util.ReflectionUtils.getClassOrFallback; import static org.geysermc.floodgate.util.ReflectionUtils.getClassOrFallback;
import static org.geysermc.floodgate.util.ReflectionUtils.getClassSilently; 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.getField;
import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType; import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType;
import static org.geysermc.floodgate.util.ReflectionUtils.getMethod; import static org.geysermc.floodgate.util.ReflectionUtils.getMethod;
import static org.geysermc.floodgate.util.ReflectionUtils.getValue; import static org.geysermc.floodgate.util.ReflectionUtils.getValue;
import static org.geysermc.floodgate.util.ReflectionUtils.invoke; import static org.geysermc.floodgate.util.ReflectionUtils.invoke;
import static org.geysermc.floodgate.util.ReflectionUtils.makeAccessible;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
@@ -58,27 +60,35 @@ public class ClassNames {
public static final Class<?> LOGIN_START_PACKET; public static final Class<?> LOGIN_START_PACKET;
public static final Class<?> LOGIN_LISTENER; public static final Class<?> LOGIN_LISTENER;
public static final Class<?> LOGIN_HANDLER; 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<OfflinePlayer> CRAFT_OFFLINE_PLAYER_CONSTRUCTOR;
public static final Constructor<?> LOGIN_HANDLER_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 SOCKET_ADDRESS;
public static final Field HANDSHAKE_HOST; public static final Field HANDSHAKE_HOST;
public static final Field LOGIN_PROFILE; public static final Field LOGIN_PROFILE;
public static final Field PACKET_LISTENER; 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 Field PAPER_DISABLE_USERNAME_VALIDATION;
@Nullable public static final BooleanSupplier PAPER_VELOCITY_SUPPORT; @Nullable public static final BooleanSupplier PAPER_VELOCITY_SUPPORT;
public static final Method GET_PROFILE_METHOD; public static final Method GET_PROFILE_METHOD;
public static final Method LOGIN_DISCONNECT; public static final Method LOGIN_DISCONNECT;
public static final Method NETWORK_EXCEPTION_CAUGHT; public static final Method NETWORK_EXCEPTION_CAUGHT;
public static final Method INIT_UUID; @Nullable public static final Method INIT_UUID;
public static final Method FIRE_LOGIN_EVENTS; @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 Field BUNGEE;
public static final boolean IS_FOLIA; public static final boolean IS_FOLIA;
public static final boolean IS_PRE_1_20_2;
static { static {
String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
@@ -153,14 +163,24 @@ public class ClassNames {
); );
// there are multiple no-arg void methods // 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"); INIT_UUID = getMethod(LOGIN_LISTENER, "initUUID");
checkNotNull(INIT_UUID, "initUUID from LoginListener"); IS_PRE_1_20_2 = INIT_UUID != null;
Class<?> packetListenerClass = getClassOrFallback( if (IS_PRE_1_20_2) {
"net.minecraft.network.PacketListener", Class<?> packetListenerClass = getClassOrFallback(
nmsPackage + "PacketListener" "net.minecraft.network.PacketListener",
); nmsPackage + "PacketListener"
PACKET_LISTENER = getFieldOfType(networkManager, packetListenerClass); );
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"); checkNotNull(PACKET_LISTENER, "Packet listener");
LOGIN_HANDLER = getClassOrFallback( LOGIN_HANDLER = getClassOrFallback(
@@ -173,8 +193,11 @@ public class ClassNames {
checkNotNull(LOGIN_HANDLER_CONSTRUCTOR, "LoginHandler constructor"); checkNotNull(LOGIN_HANDLER_CONSTRUCTOR, "LoginHandler constructor");
FIRE_LOGIN_EVENTS = getMethod(LOGIN_HANDLER, "fireEvents"); 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, PAPER_DISABLE_USERNAME_VALIDATION = getField(LOGIN_LISTENER,
"iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation"); "iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation");
@@ -229,9 +252,53 @@ public class ClassNames {
IS_FOLIA = ReflectionUtils.getClassSilently( IS_FOLIA = ReflectionUtils.getClassSilently(
"io.papermc.paper.threadedregions.RegionizedServer" "io.papermc.paper.threadedregions.RegionizedServer"
) != null; ) != 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) { private static <T> T checkNotNull(@CheckForNull T toCheck, @CheckForNull String objectName) {
return Preconditions.checkNotNull(toCheck, objectName + " cannot be null"); 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");
}
} }

View File

@@ -1,8 +1,15 @@
var velocityVersion = "3.1.1" var velocityVersion = "3.2.0-SNAPSHOT"
var log4jVersion = "2.11.2" var log4jVersion = "2.11.2"
var gsonVersion = "2.8.8" var gsonVersion = "2.8.8"
var guavaVersion = "25.1-jre" var guavaVersion = "25.1-jre"
indra {
javaVersions {
// For Velocity API
target(11)
}
}
dependencies { dependencies {
api(projects.core) api(projects.core)
implementation("cloud.commandframework", "cloud-velocity", Versions.cloudVersion) implementation("cloud.commandframework", "cloud-velocity", Versions.cloudVersion)

View File

@@ -76,7 +76,13 @@ public final class VelocityProxyDataHandler extends CommonDataHandler {
SERVER_LOGIN_PACKET = getPrefixedClass("protocol.packet.ServerLogin"); SERVER_LOGIN_PACKET = getPrefixedClass("protocol.packet.ServerLogin");
checkNotNull(SERVER_LOGIN_PACKET, "ServerLogin packet class cannot be null"); 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"); checkNotNull(GET_SESSION_HANDLER, "getSessionHandler method cannot be null");
INITIAL_LOGIN_SESSION_HANDLER = INITIAL_LOGIN_SESSION_HANDLER =

View File

@@ -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"}