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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 1.0.11 — Strict Channel Field Resolution in FastLoginPlus Adapter

- Fix `FuzzyReflection.getFieldValue(injector, Channel.class, true)` selecting the **preceding Object-typed `networkManager` field** instead of NettyChannelInjector's actual `Channel channel` field. The wrong bidirectional assignability check caused an inactive/null Channel or ClassCastException when FastLoginPlus examined a Java Premium connection during async Mojang session verification, then logged `disconnected during session verification` and timed the player out.
- Only match fields whose declared type is assignable to the requested class. This is the reflection rule that prevents unsafe casts; don't fall back to unrelated superclasses like `Object`.
- Add regression tests against the real NettyChannelInjector and a separate Object-before-Channel fixture. Both tests **fail on v1.0.10 and pass on v1.0.11**.
- Preserve all previous 1.0.7–1.0.10 transport/encryption/late-handler fixes and do not disable FastLoginPlus or AuthMe authentication.

## 1.0.10 — Late-binding race during Java Premium login

- Fix the v1.0.9 startup race where `NetworkManagerInjector.getTemporaryInjector` refuses to associate a valid active PacketEvents pre-login Channel with the generated `TemporaryPlayer` if native `packet_handler` has not appeared yet. FastLoginPlus thus loses its Channel for the whole verification session and aborts as disconnected.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib2PacketEvents</artifactId>
<version>1.0.10</version>
<version>1.0.11</version>
<packaging>jar</packaging>

<name>ProtocolLib2PacketEvents</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ public static <T> T getFieldValue(Object instance, Class<T> fieldClass, boolean
if (instance == null) throw new IllegalArgumentException("instance cannot be null");
for (Class<?> current = instance.getClass(); current != null; current = current.getSuperclass()) {
for (Field field : current.getDeclaredFields()) {
if (fieldClass.isAssignableFrom(field.getType()) || field.getType().isAssignableFrom(fieldClass)) {
// Only accept fields whose declared value can be safely read as
// fieldClass. The reverse assignability check incorrectly chose
// a preceding Object networkManager field when FastLoginPlus
// asked for io.netty.channel.Channel, returning null or throwing
// ClassCastException even though the real Channel was present.
if (fieldClass.isAssignableFrom(field.getType())) {
try {
if (forceAccess) field.setAccessible(true);
return fieldClass.cast(field.get(instance));
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ main: com.comphenix.protocol.ProtocolLib
version: 5.4.0
author: CyoriaSMP Team
description: A drop-in ProtocolLib compatibility layer powered by PacketEvents.
p2p-version: 1.0.10
p2p-version: 1.0.11
protocol-lib-api-version: 5.4.0
depend: [packetevents]
provides: [ProtocolLib]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.comphenix.protocol.reflect;

import com.comphenix.protocol.injector.netty.channel.NettyChannelInjector;
import io.netty.channel.Channel;
import io.netty.channel.embedded.EmbeddedChannel;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class NettyChannelFieldLookupTest {
private static final class OldFieldOrder {
private final Object networkManager = new Object();
private final Channel channel;
OldFieldOrder(Channel channel) { this.channel = channel; }
}

@Test
void picksExactChannelInsteadOfObjectWithNativeConnection() {
EmbeddedChannel channel = new EmbeddedChannel();
try {
assertSame(channel, FuzzyReflection.getFieldValue(new OldFieldOrder(channel), Channel.class, true));
} finally { channel.finishAndReleaseAll(); }
}

@Test
void realNettyInjectorReturnsChannelWhenNativeConnectionNotReady() {
EmbeddedChannel channel = new EmbeddedChannel();
try {
NettyChannelInjector injector = new NettyChannelInjector(null, null, channel, null, null, null);
assertSame(channel, FuzzyReflection.getFieldValue(injector, Channel.class, true));
} finally { channel.finishAndReleaseAll(); }
}
}
Loading