fix: begin join game sequence only after client acks configuration finish

This commit is contained in:
mworzala 2023-12-24 12:52:19 -05:00 committed by Matt Worzala
parent 89c57bfac6
commit 197daae608
7 changed files with 81 additions and 27 deletions

View File

@ -19,11 +19,15 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent {
private final Player player; private final Player player;
private final boolean isFirstConfig; private final boolean isFirstConfig;
private Instance spawningInstance = null; private boolean sendRegistryData;
private Instance spawningInstance;
public AsyncPlayerConfigurationEvent(@NotNull Player player, boolean isFirstConfig) { public AsyncPlayerConfigurationEvent(@NotNull Player player, boolean isFirstConfig) {
this.player = player; this.player = player;
this.isFirstConfig = isFirstConfig; this.isFirstConfig = isFirstConfig;
this.sendRegistryData = isFirstConfig;
this.spawningInstance = null;
} }
@Override @Override
@ -38,6 +42,14 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent {
return isFirstConfig; return isFirstConfig;
} }
public boolean willSendRegistryData() {
return sendRegistryData;
}
public void setSendRegistryData(boolean sendRegistryData) {
this.sendRegistryData = sendRegistryData;
}
public @Nullable Instance getSpawningInstance() { public @Nullable Instance getSpawningInstance() {
return spawningInstance; return spawningInstance;
} }

View File

@ -6,12 +6,10 @@ import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket; import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ForkJoinPool;
public class PlayConfigListener { public class PlayConfigListener {
private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager(); private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
public static void configAckListener(@NotNull ClientConfigurationAckPacket packet, @NotNull Player player) { public static void configAckListener(@NotNull ClientConfigurationAckPacket packet, @NotNull Player player) {
CONNECTION_MANAGER.transitionConfigToPlay(player, false); CONNECTION_MANAGER.doConfiguration(player, false);
} }
} }

View File

@ -8,12 +8,14 @@ import net.minestom.server.listener.common.KeepAliveListener;
import net.minestom.server.listener.common.PluginMessageListener; import net.minestom.server.listener.common.PluginMessageListener;
import net.minestom.server.listener.common.ResourcePackListener; import net.minestom.server.listener.common.ResourcePackListener;
import net.minestom.server.listener.common.SettingsListener; import net.minestom.server.listener.common.SettingsListener;
import net.minestom.server.listener.preplay.ConfigListener;
import net.minestom.server.listener.preplay.HandshakeListener; import net.minestom.server.listener.preplay.HandshakeListener;
import net.minestom.server.listener.preplay.LoginListener; import net.minestom.server.listener.preplay.LoginListener;
import net.minestom.server.listener.preplay.StatusListener; import net.minestom.server.listener.preplay.StatusListener;
import net.minestom.server.network.ConnectionState; import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.client.common.*; import net.minestom.server.network.packet.client.common.*;
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket;
import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket; import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket;
import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket;
@ -56,6 +58,7 @@ public final class PacketListenerManager {
setConfigurationListener(ClientKeepAlivePacket.class, KeepAliveListener::listener); setConfigurationListener(ClientKeepAlivePacket.class, KeepAliveListener::listener);
setConfigurationListener(ClientPongPacket.class, (packet, player) -> {/* empty */}); setConfigurationListener(ClientPongPacket.class, (packet, player) -> {/* empty */});
setConfigurationListener(ClientResourcePackStatusPacket.class, ResourcePackListener::listener); setConfigurationListener(ClientResourcePackStatusPacket.class, ResourcePackListener::listener);
setConfigurationListener(ClientFinishConfigurationPacket.class, ConfigListener::finishConfigListener);
setPlayListener(ClientKeepAlivePacket.class, KeepAliveListener::listener); setPlayListener(ClientKeepAlivePacket.class, KeepAliveListener::listener);
setPlayListener(ClientCommandChatPacket.class, ChatMessageListener::commandChatListener); setPlayListener(ClientCommandChatPacket.class, ChatMessageListener::commandChatListener);
@ -90,6 +93,7 @@ public final class PacketListenerManager {
setPlayListener(ClientAdvancementTabPacket.class, AdvancementTabListener::listener); setPlayListener(ClientAdvancementTabPacket.class, AdvancementTabListener::listener);
setPlayListener(ClientSpectatePacket.class, SpectateListener::listener); setPlayListener(ClientSpectatePacket.class, SpectateListener::listener);
setPlayListener(ClientEditBookPacket.class, BookListener::listener); setPlayListener(ClientEditBookPacket.class, BookListener::listener);
setPlayListener(ClientChatSessionUpdatePacket.class, (packet, player) -> {/* empty */});
} }
/** /**

View File

@ -0,0 +1,16 @@
package net.minestom.server.listener.preplay;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket;
import org.jetbrains.annotations.NotNull;
public final class ConfigListener {
private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
public static void finishConfigListener(@NotNull ClientFinishConfigurationPacket packet, @NotNull Player player) {
CONNECTION_MANAGER.transitionConfigToPlay(player);
}
}

View File

@ -219,23 +219,23 @@ public final class LoginListener {
public static void loginAckListener(@NotNull ClientLoginAcknowledgedPacket ignored, @NotNull PlayerConnection connection) { public static void loginAckListener(@NotNull ClientLoginAcknowledgedPacket ignored, @NotNull PlayerConnection connection) {
final Player player = Objects.requireNonNull(connection.getPlayer()); final Player player = Objects.requireNonNull(connection.getPlayer());
CONNECTION_MANAGER.doConfiguration(player, true);
// Registry data // // Registry data
var registry = new HashMap<String, NBT>(); // var registry = new HashMap<String, NBT>();
registry.put("minecraft:chat_type", Messenger.chatRegistry()); // registry.put("minecraft:chat_type", Messenger.chatRegistry());
registry.put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT()); // registry.put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT());
registry.put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT()); // registry.put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT());
registry.put("minecraft:damage_type", DamageType.getNBT()); // registry.put("minecraft:damage_type", DamageType.getNBT());
connection.sendPacket(new RegistryDataPacket(NBT.Compound(registry))); // connection.sendPacket(new RegistryDataPacket(NBT.Compound(registry)));
//
// Tags // // Tags
connection.sendPacket(TagsPacket.DEFAULT_TAGS); // connection.sendPacket(TagsPacket.DEFAULT_TAGS);
//
// Server Brand // // Server Brand
connection.sendPacket(PluginMessagePacket.getBrandPacket()); // connection.sendPacket(PluginMessagePacket.getBrandPacket());
//
// Enter configuration phase (for the first time) // // Enter configuration phase (for the first time)
CONNECTION_MANAGER.transitionConfigToPlay(player, true); // CONNECTION_MANAGER.transitionConfigToPlay(player, true);
} }
} }

View File

@ -4,13 +4,18 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import net.minestom.server.event.player.AsyncPlayerPreLoginEvent; import net.minestom.server.event.player.AsyncPlayerPreLoginEvent;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.message.Messenger;
import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; import net.minestom.server.network.packet.client.login.ClientLoginStartPacket;
import net.minestom.server.network.packet.server.common.KeepAlivePacket; import net.minestom.server.network.packet.server.common.KeepAlivePacket;
import net.minestom.server.network.packet.server.common.PluginMessagePacket;
import net.minestom.server.network.packet.server.common.TagsPacket;
import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket; import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket;
import net.minestom.server.network.packet.server.configuration.RegistryDataPacket;
import net.minestom.server.network.packet.server.login.LoginSuccessPacket; import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
import net.minestom.server.network.packet.server.play.StartConfigurationPacket; import net.minestom.server.network.packet.server.play.StartConfigurationPacket;
import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerConnection;
@ -24,6 +29,9 @@ import org.jctools.queues.MpscUnboundedArrayQueue;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -35,6 +43,8 @@ import java.util.function.Function;
* Manages the connected clients. * Manages the connected clients.
*/ */
public final class ConnectionManager { public final class ConnectionManager {
private static final Logger logger = LoggerFactory.getLogger(ConnectionManager.class);
private static final long KEEP_ALIVE_DELAY = 10_000; private static final long KEEP_ALIVE_DELAY = 10_000;
private static final long KEEP_ALIVE_KICK = 30_000; private static final long KEEP_ALIVE_KICK = 30_000;
private static final Component TIMEOUT_TEXT = Component.text("Timeout", NamedTextColor.RED); private static final Component TIMEOUT_TEXT = Component.text("Timeout", NamedTextColor.RED);
@ -268,21 +278,38 @@ public final class ConnectionManager {
} }
@ApiStatus.Internal @ApiStatus.Internal
public void transitionConfigToPlay(@NotNull Player player, boolean isFirstConfig) { public void doConfiguration(@NotNull Player player, boolean isFirstConfig) {
// Call the event and spawn the player.
AsyncUtils.runAsync(() -> { AsyncUtils.runAsync(() -> {
player.sendPacket(PluginMessagePacket.getBrandPacket());
var event = new AsyncPlayerConfigurationEvent(player, isFirstConfig); var event = new AsyncPlayerConfigurationEvent(player, isFirstConfig);
EventDispatcher.call(event); EventDispatcher.call(event);
final Instance spawningInstance = event.getSpawningInstance(); final Instance spawningInstance = event.getSpawningInstance();
Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent"); Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent");
// Registry data (if it should be sent)
if (event.willSendRegistryData()) {
var registry = new HashMap<String, NBT>();
registry.put("minecraft:chat_type", Messenger.chatRegistry());
registry.put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT());
registry.put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT());
registry.put("minecraft:damage_type", DamageType.getNBT());
player.sendPacket(new RegistryDataPacket(NBT.Compound(registry)));
player.sendPacket(TagsPacket.DEFAULT_TAGS);
}
player.setPendingInstance(spawningInstance); player.setPendingInstance(spawningInstance);
this.waitingPlayers.relaxedOffer(player);
player.sendPacket(new FinishConfigurationPacket()); player.sendPacket(new FinishConfigurationPacket());
}); });
} }
@ApiStatus.Internal
public void transitionConfigToPlay(@NotNull Player player) {
this.waitingPlayers.relaxedOffer(player);
}
/** /**
* Removes a {@link Player} from the players list. * Removes a {@link Player} from the players list.
* <p> * <p>

View File

@ -13,9 +13,6 @@ import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket;
import net.minestom.server.network.packet.server.*; import net.minestom.server.network.packet.server.*;
import net.minestom.server.network.packet.server.login.SetCompressionPacket; import net.minestom.server.network.packet.server.login.SetCompressionPacket;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.TimeUpdatePacket;
import net.minestom.server.network.packet.server.play.UpdateLightPacket;
import net.minestom.server.network.socket.Worker; import net.minestom.server.network.socket.Worker;
import net.minestom.server.utils.ObjectPool; import net.minestom.server.utils.ObjectPool;
import net.minestom.server.utils.PacketUtils; import net.minestom.server.utils.PacketUtils;