Skip to content

Commit 4022c09

Browse files
authored
Merge pull request #134 from Prime-Codes-GmbH/fix/viaversion-play-state
fix: guard ViaVersion packet sends by connection state
2 parents f42a5fd + 44ff232 commit 4022c09

3 files changed

Lines changed: 84 additions & 14 deletions

File tree

implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
import com.viaversion.viaversion.api.type.Types;
1111
import io.netty.buffer.ByteBuf;
1212
import io.netty.buffer.Unpooled;
13+
import io.netty.channel.Channel;
1314
import net.megavex.scoreboardlibrary.implementation.commons.LegacyFormatUtil;
1415
import net.megavex.scoreboardlibrary.implementation.packetAdapter.ImmutableTeamProperties;
1516
import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType;
1617
import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl;
18+
import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ViaConnectionGuard;
1719
import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.EntriesPacketType;
1820
import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants;
1921
import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamDisplayPacketAdapter;
@@ -45,14 +47,14 @@ public void removeTeam(@NotNull Iterable<Player> players) {
4547
assert via != null;
4648
for (final Player player : players) {
4749
final UserConnection conn = via.getConnection(player.getUniqueId());
48-
if (conn == null) continue;
50+
if (conn == null || !ViaConnectionGuard.isCurrentPlayConnection(via, player, conn)) continue;
4951

5052
final ByteBuf buf = Unpooled.buffer(128);
5153
Types.VAR_INT.writePrimitive(buf, teamsPacketId(player, conn));
5254
Types.STRING.write(buf, teamName);
5355
Types.BYTE.writePrimitive(buf, (byte) TeamConstants.MODE_REMOVE);
5456

55-
via.sendRawPacket(player.getUniqueId(), buf);
57+
sendRawPacket(via, player, conn, buf);
5658
}
5759
}
5860

@@ -62,7 +64,7 @@ public void sendEntries(@NotNull EntriesPacketType packetType, @NotNull Collecti
6264
assert via != null;
6365
for (final Player player : players) {
6466
final UserConnection conn = via.getConnection(player.getUniqueId());
65-
if (conn == null) continue;
67+
if (conn == null || !ViaConnectionGuard.isCurrentPlayConnection(via, player, conn)) continue;
6668

6769
final ByteBuf buf = Unpooled.buffer(128);
6870
Types.VAR_INT.writePrimitive(buf, teamsPacketId(player, conn));
@@ -81,7 +83,7 @@ public void sendEntries(@NotNull EntriesPacketType packetType, @NotNull Collecti
8183
Types.STRING.write(buf, entry);
8284
}
8385

84-
via.sendRawPacket(player.getUniqueId(), buf);
86+
sendRawPacket(via, player, conn, buf);
8587
}
8688
}
8789

@@ -91,7 +93,7 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co
9193
assert via != null;
9294
for (final Player player : players) {
9395
final UserConnection conn = via.getConnection(player.getUniqueId());
94-
if (conn == null) continue;
96+
if (conn == null || !ViaConnectionGuard.isCurrentPlayConnection(via, player, conn)) continue;
9597

9698
final ByteBuf buf = Unpooled.buffer(128);
9799
Types.VAR_INT.writePrimitive(buf, teamsPacketId(player, conn));
@@ -134,7 +136,28 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co
134136
}
135137
}
136138

137-
via.sendRawPacket(player.getUniqueId(), buf);
139+
sendRawPacket(via, player, conn, buf);
140+
}
141+
}
142+
143+
private static void sendRawPacket(ViaAPI<Player> via, Player player, UserConnection connection, ByteBuf packet) {
144+
final Channel channel = connection.getChannel();
145+
if (!ViaConnectionGuard.isCurrentPlayConnection(via, player, connection, channel)) {
146+
packet.release();
147+
return;
148+
}
149+
150+
try {
151+
channel.eventLoop().execute(() -> {
152+
if (ViaConnectionGuard.isCurrentPlayConnection(via, player, connection, channel)) {
153+
connection.sendRawPacket(packet);
154+
} else {
155+
packet.release();
156+
}
157+
});
158+
} catch (RuntimeException | Error exception) {
159+
packet.release();
160+
throw exception;
138161
}
139162
}
140163

implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernPacketSender.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,25 @@ public void sendPacket(Player player, Object packet) {
8282
final UserConnection conn = this.via.getConnection(player.getUniqueId());
8383
if (conn != null) {
8484
final Channel channel = conn.getChannel();
85-
if (channel != null) {
86-
// Paper has some "network optimization" patch that makes the NMS sendPacket method
87-
// not always send the packet immediately to the player's netty channel,
88-
// and this is a problem when we send some packets using ViaVersion API because it always sends
89-
// the packet to the channel immediately, so the packet order between NMS and ViaVersion API can
90-
// get messed up. So for ViaVersion players we send the packet directly to the player's channel
91-
// bypassing Paper logic to work around this. Fortunately ViaVersion provides easy access to the player's channel.
92-
channel.eventLoop().execute(() -> channel.writeAndFlush(packet));
85+
if (!ViaConnectionGuard.isCurrentPlayConnection(this.via, player, conn, channel)) {
9386
return;
9487
}
88+
89+
// Paper has some "network optimization" patch that makes the NMS sendPacket method
90+
// not always send the packet immediately to the player's netty channel,
91+
// and this is a problem when we send some packets using ViaVersion API because it always sends
92+
// the packet to the channel immediately, so the packet order between NMS and ViaVersion API can
93+
// get messed up. So for ViaVersion players we send the packet directly to the player's channel
94+
// bypassing Paper logic to work around this. Fortunately ViaVersion provides easy access to the player's channel.
95+
channel.eventLoop().execute(() -> {
96+
// The player can disconnect or enter configuration while this write is queued. The
97+
// channel remains open in that state, but its encoder no longer accepts game packets.
98+
// Also guard against a reconnect replacing ViaVersion's UUID mapping in the meantime.
99+
if (ViaConnectionGuard.isCurrentPlayConnection(this.via, player, conn, channel)) {
100+
channel.writeAndFlush(packet);
101+
}
102+
});
103+
return;
95104
}
96105
}
97106

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util;
2+
3+
import com.viaversion.viaversion.api.ViaAPI;
4+
import com.viaversion.viaversion.api.connection.ProtocolInfo;
5+
import com.viaversion.viaversion.api.connection.UserConnection;
6+
import com.viaversion.viaversion.api.protocol.packet.State;
7+
import io.netty.channel.Channel;
8+
import org.bukkit.entity.Player;
9+
10+
public final class ViaConnectionGuard {
11+
private ViaConnectionGuard() {
12+
}
13+
14+
public static boolean isCurrentPlayConnection(
15+
ViaAPI<Player> via,
16+
Player player,
17+
UserConnection connection
18+
) {
19+
return isCurrentPlayConnection(via, player, connection, connection.getChannel());
20+
}
21+
22+
public static boolean isCurrentPlayConnection(
23+
ViaAPI<Player> via,
24+
Player player,
25+
UserConnection connection,
26+
Channel channel
27+
) {
28+
final ProtocolInfo protocolInfo = connection.getProtocolInfo();
29+
return channel != null
30+
&& player.isOnline()
31+
&& channel.isActive()
32+
&& !connection.isPendingDisconnect()
33+
&& protocolInfo != null
34+
&& protocolInfo.getServerState() == State.PLAY
35+
&& protocolInfo.getClientState() == State.PLAY
36+
&& via.getConnection(player.getUniqueId()) == connection;
37+
}
38+
}

0 commit comments

Comments
 (0)