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
|
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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
if (ClassNames.IS_PRE_1_20_2) {
|
||||||
|
// 1.20.1 and below
|
||||||
setValue(handshakePacket, ClassNames.HANDSHAKE_HOST, hostname);
|
setValue(handshakePacket, ClassNames.HANDSHAKE_HOST, hostname);
|
||||||
|
|
||||||
return handshakePacket;
|
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:
|
||||||
|
|
||||||
|
Object loginHandler = ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener);
|
||||||
|
|
||||||
|
if (ClassNames.IS_PRE_1_20_2) {
|
||||||
|
// 1.20.1 and below
|
||||||
|
|
||||||
// LoginListener#initUUID
|
// LoginListener#initUUID
|
||||||
// new LoginHandler().fireEvents();
|
// new LoginHandler().fireEvents();
|
||||||
|
|
||||||
// and the tick of LoginListener will do the rest
|
// and the tick of LoginListener will do the rest
|
||||||
|
|
||||||
ClassNames.INIT_UUID.invoke(packetListener);
|
ClassNames.INIT_UUID.invoke(packetListener);
|
||||||
|
|
||||||
Object loginHandler =
|
|
||||||
ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener);
|
|
||||||
ClassNames.FIRE_LOGIN_EVENTS.invoke(loginHandler);
|
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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
if (IS_PRE_1_20_2) {
|
||||||
Class<?> packetListenerClass = getClassOrFallback(
|
Class<?> packetListenerClass = getClassOrFallback(
|
||||||
"net.minecraft.network.PacketListener",
|
"net.minecraft.network.PacketListener",
|
||||||
nmsPackage + "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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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