From c341b941d3ed0dc177deffc6e1900c7407210e95 Mon Sep 17 00:00:00 2001 From: _Novit_ Date: Wed, 24 Sep 2025 22:15:32 +0300 Subject: [PATCH 1/4] chore: improve documentation for the Dialog API --- src/content/docs/paper/dev/api/dialogs.mdx | 42 +++++++++++++++------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/content/docs/paper/dev/api/dialogs.mdx b/src/content/docs/paper/dev/api/dialogs.mdx index 4af8919f7..f664082a2 100644 --- a/src/content/docs/paper/dev/api/dialogs.mdx +++ b/src/content/docs/paper/dev/api/dialogs.mdx @@ -235,7 +235,7 @@ public class ServerJoinListener implements Listener { /** * A map for holding all currently connecting players. */ - private final Map> awaitingResponse = new HashMap<>(); + private final Map> awaitingResponse = new ConcurrentHashMap<>(); @EventHandler void onPlayerConfigure(AsyncPlayerConnectionConfigureEvent event) { @@ -248,23 +248,31 @@ public class ServerJoinListener implements Listener { return; } + PlayerConfigurationConnection connection = event.getConnection(); + UUID uniqueId = connection.getProfile().getId(); + if (uniqueId == null) { + return; + } + // Construct a new completable future without a task. CompletableFuture response = new CompletableFuture<>(); + // Complete the future if nothing has been done after two minutes. + response.completeOnTimeout(false, 1, TimeUnit.MINUTES); // Put it into our map. - awaitingResponse.put(event.getConnection(), response); + awaitingResponse.put(uniqueId, response); + Audience audience = connection.getAudience(); // Show the connecting player the dialog. - event.getConnection().getAudience().showDialog(dialog); + audience.showDialog(dialog); // Wait until the future is complete. This step is necessary in order to keep the player in the configuration phase. if (!response.join()) { + // We close the dialog manually because the client might not do it on its own. + audience.closeDialog(); // If the response is false, they declined. Therefore, we kick them from the server. - event.getConnection().disconnect(Component.text("You hate Paper-chan :(", NamedTextColor.RED)); + connection.disconnect(Component.text("You hate Paper-chan :(", NamedTextColor.RED)); } - - // We clean the map to avoid unnecessary entry buildup. - awaitingResponse.remove(event.getConnection()); } /** @@ -272,22 +280,32 @@ public class ServerJoinListener implements Listener { */ @EventHandler void onHandleDialog(PlayerCustomClickEvent event) { - Key key = event.getIdentifier(); + // Handle custom click only for configuration connection. + if (!(event.getCommonConnection() instanceof PlayerConfigurationConnection configurationConnection)) { + return; + } + UUID uniqueId = configurationConnection.getProfile().getId(); + if (uniqueId == null) { + return; + } + + Key key = event.getIdentifier(); if (key.equals(Key.key("papermc:paperchan/disagree"))) { // If the identifier is the same as the disagree one, set the connection result to false. - setConnectionJoinResult(event.getCommonConnection(), false); + setConnectionJoinResult(uniqueId, false); } else if (key.equals(Key.key("papermc:paperchan/agree"))) { // If it is the same as the agree one, set the result to true. - setConnectionJoinResult(event.getCommonConnection(), true); + setConnectionJoinResult(uniqueId, true); } } /** * Simple utility method for setting a connection's dialog response result. */ - private void setConnectionJoinResult(PlayerCommonConnection connection, boolean value) { - CompletableFuture future = awaitingResponse.get(connection); + private void setConnectionJoinResult(UUID uniqueId, boolean value) { + // We get the value and clean the map to avoid unnecessary entry buildup. + CompletableFuture future = awaitingResponse.remove(uniqueId); if (future != null) { future.complete(value); } From 60b79d500e0b550785d0bf6726c7fa70568d7e13 Mon Sep 17 00:00:00 2001 From: _Novit_ Date: Wed, 24 Sep 2025 22:56:08 +0300 Subject: [PATCH 2/4] chore: improve documentation for the Dialog API --- src/content/docs/paper/dev/api/dialogs.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/paper/dev/api/dialogs.mdx b/src/content/docs/paper/dev/api/dialogs.mdx index f664082a2..3d84371cb 100644 --- a/src/content/docs/paper/dev/api/dialogs.mdx +++ b/src/content/docs/paper/dev/api/dialogs.mdx @@ -256,7 +256,7 @@ public class ServerJoinListener implements Listener { // Construct a new completable future without a task. CompletableFuture response = new CompletableFuture<>(); - // Complete the future if nothing has been done after two minutes. + // Complete the future if nothing has been done after one minute. response.completeOnTimeout(false, 1, TimeUnit.MINUTES); // Put it into our map. From bc47123edaa44b1c368fa2973d4130e8e02c192c Mon Sep 17 00:00:00 2001 From: _Novit_ Date: Wed, 24 Sep 2025 23:01:14 +0300 Subject: [PATCH 3/4] fix: clean up map to prevent unnecessary entry buildup --- src/content/docs/paper/dev/api/dialogs.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/content/docs/paper/dev/api/dialogs.mdx b/src/content/docs/paper/dev/api/dialogs.mdx index 3d84371cb..fb2dda1dd 100644 --- a/src/content/docs/paper/dev/api/dialogs.mdx +++ b/src/content/docs/paper/dev/api/dialogs.mdx @@ -273,6 +273,9 @@ public class ServerJoinListener implements Listener { // If the response is false, they declined. Therefore, we kick them from the server. connection.disconnect(Component.text("You hate Paper-chan :(", NamedTextColor.RED)); } + + // We clean the map to avoid unnecessary entry buildup. + awaitingResponse.remove(uniqueId); } /** @@ -304,8 +307,7 @@ public class ServerJoinListener implements Listener { * Simple utility method for setting a connection's dialog response result. */ private void setConnectionJoinResult(UUID uniqueId, boolean value) { - // We get the value and clean the map to avoid unnecessary entry buildup. - CompletableFuture future = awaitingResponse.remove(uniqueId); + CompletableFuture future = awaitingResponse.get(uniqueId); if (future != null) { future.complete(value); } From efb6f60fd558805185f88812348f49677291403c Mon Sep 17 00:00:00 2001 From: _Novit_ Date: Fri, 3 Oct 2025 18:01:12 +0300 Subject: [PATCH 4/4] feat: event handler for cleanup the map to avoid unnecessary entry buildup. --- src/content/docs/paper/dev/api/dialogs.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/content/docs/paper/dev/api/dialogs.mdx b/src/content/docs/paper/dev/api/dialogs.mdx index fb2dda1dd..3d28c9cd2 100644 --- a/src/content/docs/paper/dev/api/dialogs.mdx +++ b/src/content/docs/paper/dev/api/dialogs.mdx @@ -303,6 +303,14 @@ public class ServerJoinListener implements Listener { } } + /** + * An event handler for cleanup the map to avoid unnecessary entry buildup. + */ + @EventHandler + void onConnectionClose(PlayerConnectionCloseEvent event) { + awaitingResponse.remove(event.getPlayerUniqueId()); + } + /** * Simple utility method for setting a connection's dialog response result. */