Skip to content

Commit

Permalink
1.20.2 Support (#449)
Browse files Browse the repository at this point in the history
* Spigot 1.20.2

Signed-off-by: Joshua Castle <[email protected]>

* Oops

Signed-off-by: Joshua Castle <[email protected]>

* 1.20.2 velocity (#1)

* 1.20.2 Velocity

Signed-off-by: Joshua Castle <[email protected]>

* Archive build artifacts

Signed-off-by: Joshua Castle <[email protected]>

* Fix typo in velocity-plugin.json

Signed-off-by: Joshua Castle <[email protected]>

---------

Signed-off-by: Joshua Castle <[email protected]>

* Fix formatting and apply codestyle to eclipse

Signed-off-by: Joshua Castle <[email protected]>

* Ignore changes to core base prefs

Signed-off-by: Joshua Castle <[email protected]>

* Proper ignore

Signed-off-by: Joshua Castle <[email protected]>

* Remove buildship prefs

Signed-off-by: Joshua Castle <[email protected]>

* Formatting

Signed-off-by: GitHub <[email protected]>

* Formatting

Signed-off-by: GitHub <[email protected]>

* Properly build PRs

* Formatting + remove artifacts

Signed-off-by: GitHub <[email protected]>

* Throw IllegalStateException

Signed-off-by: GitHub <[email protected]>

---------

Signed-off-by: Joshua Castle <[email protected]>
Signed-off-by: GitHub <[email protected]>
  • Loading branch information
Kas-tle authored Sep 26, 2023
1 parent 492be77 commit 26c11bd
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 23 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/pullrequest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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;
Expand All @@ -57,9 +58,27 @@ protected void setNewIp(Channel channel, InetSocketAddress newIp) {
}

@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
Expand Down Expand Up @@ -157,16 +176,23 @@ private boolean checkAndHandleLogin(Object packet) throws Exception {
// 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;
Expand Down
85 changes: 76 additions & 9 deletions spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@
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;
Expand All @@ -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];
Expand Down Expand Up @@ -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(
Expand All @@ -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");
Expand Down Expand Up @@ -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");
}
}
9 changes: 8 additions & 1 deletion velocity/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
2 changes: 1 addition & 1 deletion velocity/src/main/resources/velocity-plugin.json
Original file line number Diff line number Diff line change
@@ -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"}

0 comments on commit 26c11bd

Please sign in to comment.