Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,21 @@ curl -I -L --fail https://github.com/minekube/connect-java/releases/download/<ve
- Compile-only platform deps live in `build-logic/.../Versions.kt` and are excluded
from the shaded jar by `provided(...)`; the `viaversion-bukkit` artifact declares
no transitive deps, so `viaversion-common` must be requested explicitly.
- Spigot NMS drift is expected when a Minecraft release renames an internal accessor:
`spigot/.../util/ClassNames.java` resolves server internals in one static initializer,
and failures are latched in the separate `NmsDiagnostics` class so they remain
available after `ClassNames` becomes erroneous. `SpigotPlatform.enable()` logs the
accessor and environment from that latch. Route new lookups through the
`NmsDiagnostics` helpers so they stay reportable; `spigot/.../util/NmsDiagnosticsTest`
guards this contract.

## Java runtime compatibility

- Java 26 is not a libp2p classloader incompatibility; the isolation has been verified on
Java 26. Treat a Java 26 report as an NMS compatibility signal until the
`NmsDiagnostics` line identifies the server and Minecraft version.
- CI currently stops at JDK 21 because the repository uses Gradle 8.5; the authoritative
matrix is `.github/workflows/pullrequest.yml`.

## Velocity Join Bugs

Expand Down
22 changes: 22 additions & 0 deletions spigot/src/main/java/com/minekube/connect/SpigotPlatform.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,53 @@
import com.minekube.connect.api.inject.PlatformInjector;
import com.minekube.connect.api.logger.ConnectLogger;
import com.minekube.connect.bedrock.BedrockAdmissionCoordinator;
import com.minekube.connect.util.NmsDiagnostics;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;

public final class SpigotPlatform extends ConnectPlatform {
@Inject private JavaPlugin plugin;

private final ConnectLogger logger;

public SpigotPlatform(ConnectApi api, PlatformInjector platformInjector,
ConnectLogger logger, Injector injector) {
super(api, platformInjector, logger, injector);
this.logger = logger;
}

@Inject
public SpigotPlatform(ConnectApi api, PlatformInjector platformInjector,
ConnectLogger logger, Injector injector,
BedrockAdmissionCoordinator admissionCoordinator) {
super(api, platformInjector, logger, injector, admissionCoordinator);
this.logger = logger;
}

@Override
public boolean enable(Module... postInitializeModules) {
boolean success = super.enable(postInitializeModules);
if (!success) {
reportNmsInitializationFailure();
Bukkit.getPluginManager().disablePlugin(plugin);
return false;
}
return true;
}

/**
* Re-states why Connect's server-internals lookup failed, if that is what went wrong.
*
* <p>{@code ClassNames} resolves those internals from a static initializer, so only the very
* first touch carries the reason directly; every later one surfaces as
* {@code NoClassDefFoundError: Could not initialize class ...ClassNames}, which names the
* class but not the accessor. Whichever of the two the enable path happened to hit, this puts
* the accessor that actually drifted back into the log as a plain top-level line.
*/
private void reportNmsInitializationFailure() {
String failure = NmsDiagnostics.initializationFailure();
if (failure != null) {
logger.error(failure);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,15 @@
import com.minekube.connect.config.ConnectConfig;
import com.minekube.connect.network.netty.LocalSession.Context;
import com.minekube.connect.util.ClassNames;
import com.minekube.connect.util.NmsDiagnostics;
import com.minekube.connect.util.ProxyUtils;
import com.minekube.connect.util.SpigotGameProfiles;
import com.mojang.authlib.GameProfile;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.function.UnaryOperator;
import javax.annotation.Nullable;

public final class SpigotDataHandler extends CommonDataHandler {
private final Context sessionCtx;
Expand Down Expand Up @@ -185,13 +188,15 @@ public boolean channelRead(Object packet) throws Exception {
return false;
}

if (ProxyUtils.isVelocitySupport()) {
// We securely skip the velocity plugin message login method entirely.
// Setting this field to a value other than -1 skips the velocity check in paper and
// prevents the player getting kicked due to "This server requires you to connect with Velocity."
// when invoking LoginHandler#fireEvents() below.
setValue(packetListener, ClassNames.VELOCITY_LOGIN_MESSAGE_ID, 0);
}
// We securely skip the velocity plugin message login method entirely.
// Setting this field to a value other than -1 skips the velocity check in paper and
// prevents the player getting kicked due to "This server requires you to connect with Velocity."
// when invoking LoginHandler#fireEvents() below.
setVelocityLoginMessageIdIfSupported(
packetListener,
ProxyUtils.isVelocitySupport(),
ClassNames.VELOCITY_LOGIN_MESSAGE_ID,
ClassNames.LOGIN_LISTENER);

// Set the player's correct GameProfile, including signed texture properties for skins.
GameProfile gameProfile = SpigotGameProfiles.fromConnectProfile(sessionCtx.getPlayer().getGameProfile());
Expand Down Expand Up @@ -252,6 +257,21 @@ boolean enforceBedrockIdentity() {
return false;
}

static void setVelocityLoginMessageIdIfSupported(
Object packetListener,
boolean velocitySupport,
@Nullable Field velocityLoginMessageId,
Class<?> loginListener) {
if (!velocitySupport) {
return;
}
if (velocityLoginMessageId == null) {
String accessor = loginListener.getName() + "#velocityLoginMessageId";
throw NmsDiagnostics.missingAccessor(accessor, "Tried: " + accessor + ".");
}
setValue(packetListener, velocityLoginMessageId, 0);
}

private static final Gson GSON = new Gson();

// source https://github.com/PaperMC/Velocity/blob/2586210ca67f2510eb4f91bf7567643f8a26ee7b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java#L126
Expand Down
Loading
Loading