diff --git a/pom.xml b/pom.xml index 3147ad5..08afce6 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ dev.waterdog.waterdogpe waterdog - 2.0.2-SNAPSHOT + 2.0.3-20240423.203337-2 provided diff --git a/src/main/java/org/nethergames/proxytransport/impl/TransportChannelInitializer.java b/src/main/java/org/nethergames/proxytransport/impl/TransportChannelInitializer.java index 988e989..f525937 100644 --- a/src/main/java/org/nethergames/proxytransport/impl/TransportChannelInitializer.java +++ b/src/main/java/org/nethergames/proxytransport/impl/TransportChannelInitializer.java @@ -1,7 +1,6 @@ package org.nethergames.proxytransport.impl; import dev.waterdog.waterdogpe.network.NetworkMetrics; -import dev.waterdog.waterdogpe.network.PacketDirection; import dev.waterdog.waterdogpe.network.connection.client.ClientConnection; import dev.waterdog.waterdogpe.network.connection.codec.batch.BedrockBatchDecoder; import dev.waterdog.waterdogpe.network.connection.codec.batch.BedrockBatchEncoder; @@ -16,8 +15,9 @@ import io.netty.util.concurrent.Promise; import lombok.RequiredArgsConstructor; import org.cloudburstmc.netty.channel.raknet.RakChannel; +import org.cloudburstmc.netty.channel.raknet.config.RakChannelMetrics; import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; -import org.cloudburstmc.netty.channel.raknet.config.RakMetrics; +import org.cloudburstmc.protocol.bedrock.PacketDirection; import org.cloudburstmc.protocol.bedrock.netty.codec.compression.CompressionCodec; import org.nethergames.proxytransport.compression.FrameIdCodec; import org.nethergames.proxytransport.compression.ProxyTransportCompressionCodec; @@ -44,14 +44,14 @@ protected void initChannel(Channel channel) { int rakVersion = this.player.getProtocol().getRaknetVersion(); CompressionType compression = this.player.getProxy().getConfiguration().getCompression(); - channel.attr(PacketDirection.ATTRIBUTE).set(PacketDirection.FROM_SERVER); + channel.attr(PacketDirection.ATTRIBUTE).set(PacketDirection.SERVER_BOUND); NetworkMetrics metrics = this.player.getProxy().getNetworkMetrics(); if (metrics != null) { channel.attr(NetworkMetrics.ATTRIBUTE).set(metrics); } - if (metrics instanceof RakMetrics rakMetrics && channel instanceof RakChannel) { + if (metrics instanceof RakChannelMetrics rakMetrics && channel instanceof RakChannel) { channel.config().setOption(RakChannelOption.RAK_METRICS, rakMetrics); } @@ -72,6 +72,10 @@ protected void initChannel(Channel channel) { channel.pipeline().addLast(ClientConnection.NAME, handler); } + if (connection.getPacketDirection() != PacketDirection.SERVER_BOUND) { + throw new IllegalStateException("Client connection must have a server-bound packet direction"); + } + channel.pipeline() .addLast(CustomClientEventHandler.NAME, new CustomClientEventHandler(this.player, connection)) .addLast(new TransportChannelInitializer.ChannelActiveHandler(connection, this.promise)); diff --git a/src/main/java/org/nethergames/proxytransport/impl/TransportClientConnection.java b/src/main/java/org/nethergames/proxytransport/impl/TransportClientConnection.java index 0ad7e29..abc9e3b 100644 --- a/src/main/java/org/nethergames/proxytransport/impl/TransportClientConnection.java +++ b/src/main/java/org/nethergames/proxytransport/impl/TransportClientConnection.java @@ -13,6 +13,7 @@ import io.netty.incubator.codec.quic.QuicConnectionPathStats; import io.netty.incubator.codec.quic.QuicStreamChannel; import io.netty.util.concurrent.Future; +import lombok.Getter; import lombok.NonNull; import lombok.extern.log4j.Log4j2; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; @@ -51,6 +52,14 @@ public class TransportClientConnection extends BedrockClientConnection { private long lastPingTimestamp = -1; private long latency = 0; // Latency in microseconds + private long lastSentPackets = 0; + private long lastLostPackets = 0; + /** + * Get the lost percentage of packets sent to the server as a 3 decimal integer. + */ + @Getter + private Integer lostPercentage = null; + private final List> scheduledTasks = new ArrayList<>(); public TransportClientConnection(ProxiedPlayer player, ServerInfo serverInfo, Channel channel) { @@ -175,13 +184,37 @@ public long getMicroSecondsPing() { return this.latency; } + private void setLostPercentage(long lostPackets, long sentPackets) { + long lost = lostPackets - this.lastLostPackets; + long sent = sentPackets - this.lastSentPackets; + this.lastLostPackets = lostPackets; + this.lastSentPackets = sentPackets; + + if (sent == 0) { + this.lostPercentage = 0; + return; + } + + long lostPercentage = Math.round(((double) (lost * 100) / sent) * 1000); + + if (lostPercentage > 65535) { + this.lostPercentage = 65535; + return; + } + + this.lostPercentage = (int) lostPercentage; + } + public void collectStats() { var connection = getPlayer().getDownstreamConnection(); if (connection instanceof TransportClientConnection && connection.getServerInfo().getServerName().equalsIgnoreCase(getServerInfo().getServerName())) { if (this.channel instanceof QuicStreamChannel quicChannel) { quicChannel.parent().collectPathStats(0).addListener((Future quicChannelFuture) -> { if (quicChannelFuture.isSuccess()) { - this.latency = quicChannelFuture.getNow().rtt() / 1000; // convert to nanoseconds to microseconds + QuicConnectionPathStats quicStats = quicChannelFuture.getNow(); + + this.latency = quicStats.rtt() / 1000; // convert to nanoseconds to microsecond + this.setLostPercentage(quicStats.lost(), quicStats.sent()); this.broadcastPing(); } }); diff --git a/src/main/java/org/nethergames/proxytransport/utils/CodecUpdater.java b/src/main/java/org/nethergames/proxytransport/utils/CodecUpdater.java index 0edefe3..aac1a4e 100644 --- a/src/main/java/org/nethergames/proxytransport/utils/CodecUpdater.java +++ b/src/main/java/org/nethergames/proxytransport/utils/CodecUpdater.java @@ -3,13 +3,14 @@ import dev.waterdog.waterdogpe.network.protocol.updaters.ProtocolCodecUpdater; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.v388.serializer.TickSyncSerializer_v388; +import org.cloudburstmc.protocol.bedrock.data.PacketRecipient; import org.cloudburstmc.protocol.bedrock.packet.TickSyncPacket; public class CodecUpdater implements ProtocolCodecUpdater { @Override public BedrockCodec.Builder updateCodec(BedrockCodec.Builder builder, BedrockCodec baseCodec) { - builder.registerPacket(TickSyncPacket::new, TickSyncSerializer_v388.INSTANCE, 23); + builder.registerPacket(TickSyncPacket::new, TickSyncSerializer_v388.INSTANCE, 23, PacketRecipient.SERVER); return builder; }