2020import com .velocitypowered .proxy .connection .MinecraftConnection ;
2121import com .velocitypowered .proxy .connection .client .ConnectedPlayer ;
2222import com .velocitypowered .proxy .protocol .MinecraftPacket ;
23+ import io .netty .channel .ChannelFuture ;
24+ import org .checkerframework .checker .nullness .qual .Nullable ;
2325import java .time .Instant ;
2426import java .util .concurrent .CompletableFuture ;
25- import java .util .function .BiConsumer ;
27+ import java .util .function .Function ;
2628
2729/**
2830 * A precisely ordered queue which allows for outside entries into the ordered queue through
@@ -58,9 +60,8 @@ public void queuePacket(CompletableFuture<MinecraftPacket> nextPacket, Instant t
5860 MinecraftConnection smc = player .ensureAndGetCurrentServer ().ensureConnected ();
5961
6062 CompletableFuture <WrappedPacket > nextInLine = WrappedPacket .wrap (timestamp , nextPacket );
61- awaitChat (smc , this .packetFuture ,
63+ this . packetFuture = awaitChat (smc , this .packetFuture ,
6264 nextInLine ); // we await chat, binding `this.packetFuture` -> `nextInLine`
63- this .packetFuture = nextInLine ;
6465 }
6566 }
6667
@@ -84,21 +85,26 @@ public <K, V extends MinecraftPacket> void hijack(K packet,
8485 }
8586 }
8687
87- private static BiConsumer <WrappedPacket , Throwable > writePacket (MinecraftConnection connection ) {
88- return (wrappedPacket , throwable ) -> {
89- if (wrappedPacket != null && !connection .isClosed ()) {
90- wrappedPacket .write (connection );
88+ private static Function <WrappedPacket , WrappedPacket > writePacket (MinecraftConnection connection ) {
89+ return wrappedPacket -> {
90+ if (!connection .isClosed ()) {
91+ ChannelFuture future = wrappedPacket .write (connection );
92+ if (future != null ) {
93+ future .awaitUninterruptibly ();
94+ }
9195 }
96+
97+ return wrappedPacket ;
9298 };
9399 }
94100
95- private static <T extends MinecraftPacket > void awaitChat (
101+ private static <T extends MinecraftPacket > CompletableFuture < WrappedPacket > awaitChat (
96102 MinecraftConnection connection ,
97103 CompletableFuture <WrappedPacket > binder ,
98104 CompletableFuture <WrappedPacket > future
99105 ) {
100106 // the binder will run -> then the future will get the `write packet` caller
101- binder .whenComplete (( ignored1 , ignored2 ) -> future .whenComplete (writePacket (connection )));
107+ return binder .thenCompose ( ignored -> future .thenApply (writePacket (connection )));
102108 }
103109
104110 private static <K , V extends MinecraftPacket > CompletableFuture <WrappedPacket > hijackCurrentPacket (
@@ -113,7 +119,7 @@ private static <K, V extends MinecraftPacket> CompletableFuture<WrappedPacket> h
113119 // map the new packet into a better "designed" packet with the hijacked packet's timestamp
114120 WrappedPacket .wrap (previous .timestamp ,
115121 future .thenApply (item -> packetMapper .map (previous .timestamp , item )))
116- .whenCompleteAsync (writePacket (connection ), connection .eventLoop ())
122+ .thenApplyAsync (writePacket (connection ), connection .eventLoop ())
117123 .whenComplete (
118124 (packet , throwable ) -> awaitedFuture .complete (throwable != null ? null : packet ));
119125 });
@@ -148,10 +154,12 @@ private WrappedPacket(Instant timestamp, MinecraftPacket packet) {
148154 this .packet = packet ;
149155 }
150156
151- public void write (MinecraftConnection connection ) {
157+ @ Nullable
158+ public ChannelFuture write (MinecraftConnection connection ) {
152159 if (packet != null ) {
153- connection .write (packet );
160+ return connection .write (packet );
154161 }
162+ return null ;
155163 }
156164
157165 private static CompletableFuture <WrappedPacket > wrap (Instant timestamp ,
0 commit comments