1717
1818package com .velocitypowered .proxy .connection .backend ;
1919
20+ import com .velocityctd .api .queue .QueueState ;
2021import com .velocityctd .proxy .queue .VelocityQueue ;
2122import com .velocitypowered .api .network .ProtocolVersion ;
2223import com .velocitypowered .api .permission .Tristate ;
3536import edu .umd .cs .findbugs .annotations .SuppressFBWarnings ;
3637import io .netty .buffer .ByteBuf ;
3738import io .netty .buffer .Unpooled ;
38- import java .util .Objects ;
39+ import java .util .Comparator ;
40+ import java .util .List ;
3941import java .util .Optional ;
4042import java .util .StringJoiner ;
4143import java .util .UUID ;
44+ import java .util .stream .Stream ;
4245import net .kyori .adventure .text .Component ;
4346import net .kyori .adventure .text .serializer .ComponentSerializer ;
4447import net .kyori .adventure .text .serializer .gson .GsonComponentSerializer ;
@@ -196,21 +199,15 @@ private void queuedServer(ByteBufDataInput in) {
196199
197200 ByteBuf buf = Unpooled .buffer ();
198201
199- String queuedServer = null ;
200-
201- if (proxy .isQueueEnabled ()) {
202- for (VelocityQueue <?> queue : proxy .getQueueManager ().getQueues ()) {
203- if (queue .contains (playerUuid )) {
204- queuedServer = queue .getName ();
205- break ;
206- }
207- }
208- }
202+ String queuedServer = getQueues (playerUuid )
203+ .findFirst ()
204+ .map (VelocityQueue ::getName )
205+ .orElse ("N/A" );
209206
210207 try (ByteBufDataOutput out = new ByteBufDataOutput (buf )) {
211208 out .writeUTF ("QueuedServer" );
212209 out .writeUTF (playerUuid .toString ());
213- out .writeUTF (Objects . requireNonNullElse ( queuedServer , "N/A" ) );
210+ out .writeUTF (queuedServer );
214211 }
215212
216213 if (buf .isReadable ()) {
@@ -225,22 +222,15 @@ private void queuedPosition(ByteBufDataInput in) {
225222
226223 ByteBuf buf = Unpooled .buffer ();
227224
228- Integer position = null ;
229- if (proxy .isQueueEnabled ()) {
230- for (VelocityQueue <?> queue : proxy .getQueueManager ().getQueues ()) {
231- if (queue .contains (playerUuid )) {
232- position = queue .getPosition (playerUuid ).orElse (null );
233- if (position != null ) {
234- break ;
235- }
236- }
237- }
238- }
225+ int position = getQueues (playerUuid )
226+ .findFirst ()
227+ .flatMap (q -> q .getPosition (playerUuid ))
228+ .orElse (-1 );
239229
240230 try (ByteBufDataOutput out = new ByteBufDataOutput (buf )) {
241231 out .writeUTF ("QueuedPosition" );
242232 out .writeUTF (playerUuid .toString ());
243- out .writeInt (position != null ? position : - 1 );
233+ out .writeInt (position );
244234 }
245235
246236 if (buf .isReadable ()) {
@@ -255,21 +245,15 @@ private void queuedMaxPosition(ByteBufDataInput in) {
255245
256246 ByteBuf buf = Unpooled .buffer ();
257247
258- int position = -1 ;
259-
260- if (proxy .isQueueEnabled ()) {
261- for (VelocityQueue <?> queue : proxy .getQueueManager ().getQueues ()) {
262- if (queue .contains (playerUuid )) {
263- position = queue .size ();
264- break ;
265- }
266- }
267- }
248+ int maxPosition = getQueues (playerUuid )
249+ .findFirst ()
250+ .map (VelocityQueue ::size )
251+ .orElse (-1 );
268252
269253 try (ByteBufDataOutput out = new ByteBufDataOutput (buf )) {
270254 out .writeUTF ("MaxQueuedPosition" );
271255 out .writeUTF (playerUuid .toString ());
272- out .writeInt (position );
256+ out .writeInt (maxPosition );
273257 }
274258
275259 if (buf .isReadable ()) {
@@ -284,16 +268,10 @@ private void queuedPaused(ByteBufDataInput in) {
284268
285269 ByteBuf buf = Unpooled .buffer ();
286270
287- boolean paused = false ;
288-
289- if (proxy .isQueueEnabled ()) {
290- for (VelocityQueue <?> queue : proxy .getQueueManager ().getQueues ()) {
291- if (queue .contains (playerUuid )) {
292- paused = true ;
293- break ;
294- }
295- }
296- }
271+ boolean paused = getQueues (playerUuid )
272+ .findFirst ()
273+ .map (q -> q .getState () == QueueState .PAUSED )
274+ .orElse (false );
297275
298276 try (ByteBufDataOutput out = new ByteBufDataOutput (buf )) {
299277 out .writeUTF ("QueuedPausedChannel" );
@@ -308,6 +286,33 @@ private void queuedPaused(ByteBufDataInput in) {
308286 }
309287 }
310288
289+ private void queueStates (ByteBufDataInput in ) {
290+ UUID playerUuid = UUID .fromString (in .readUTF ());
291+
292+ ByteBuf buf = Unpooled .buffer ();
293+
294+ List <VelocityQueue <?>> queues = getQueues (playerUuid ).toList ();
295+
296+ try (ByteBufDataOutput out = new ByteBufDataOutput (buf )) {
297+ out .writeUTF ("QueueStates" );
298+ out .writeUTF (playerUuid .toString ());
299+
300+ out .writeInt (queues .size ());
301+ for (VelocityQueue <?> queue : queues ) {
302+ out .writeUTF (queue .getName ());
303+ out .writeInt (queue .getPosition (playerUuid ).orElse (-1 ));
304+ out .writeInt (queue .size ());
305+ out .writeBoolean (queue .getState () == QueueState .PAUSED );
306+ }
307+ }
308+
309+ if (buf .isReadable ()) {
310+ sendResponseOnConnection (buf );
311+ } else {
312+ buf .release ();
313+ }
314+ }
315+
311316 private void processPlayerList (ByteBufDataInput in ) {
312317 ByteBuf buf = Unpooled .buffer ();
313318
@@ -506,6 +511,24 @@ private void processGetPlayerServer(ByteBufDataInput in) {
506511 }));
507512 }
508513
514+ /**
515+ * Returns all queues a specific player is a part of ({@link VelocityQueue#contains(UUID)}) in a
516+ * stable ordering (alphabetical by queue name), or {@link Stream#empty()} if the queue subsystem
517+ * is disabled.
518+ *
519+ * @param playerUuid the player in question
520+ * @return the computed queue list
521+ */
522+ private Stream <VelocityQueue <?>> getQueues (UUID playerUuid ) {
523+ if (!proxy .isQueueEnabled ()) {
524+ return Stream .empty ();
525+ }
526+ return proxy .getQueueManager ().getQueues ()
527+ .stream ()
528+ .filter (q -> q .contains (playerUuid ))
529+ .sorted (Comparator .comparing (VelocityQueue ::getName ));
530+ }
531+
509532 static ChannelIdentifier getBungeeCordChannel (ProtocolVersion version ) {
510533 return version .noLessThan (ProtocolVersion .MINECRAFT_1_13 ) ? MODERN_CHANNEL : LEGACY_CHANNEL ;
511534 }
@@ -562,6 +585,7 @@ final boolean process(PluginMessagePacket message) {
562585 case "QueuedPosition" -> this .queuedPosition (in );
563586 case "MaxQueuedPosition" -> this .queuedMaxPosition (in );
564587 case "QueuedPausedChannel" -> this .queuedPaused (in );
588+ case "QueueStates" -> this .queueStates (in );
565589 default -> {
566590 // Do nothing, unknown command
567591 }
0 commit comments