mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-06 16:37:38 +01:00
feat: start reentry of config phase
(cherry picked from commit e702c09f06
)
This commit is contained in:
parent
fb0c8c5405
commit
b9c2d42696
@ -64,6 +64,7 @@ public class Main {
|
|||||||
commandManager.register(new DisplayCommand());
|
commandManager.register(new DisplayCommand());
|
||||||
commandManager.register(new NotificationCommand());
|
commandManager.register(new NotificationCommand());
|
||||||
commandManager.register(new TestCommand2());
|
commandManager.register(new TestCommand2());
|
||||||
|
commandManager.register(new ConfigCommand());
|
||||||
|
|
||||||
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED)));
|
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED)));
|
||||||
|
|
||||||
@ -109,10 +110,10 @@ public class Main {
|
|||||||
|
|
||||||
OptifineSupport.enable();
|
OptifineSupport.enable();
|
||||||
|
|
||||||
VelocityProxy.enable("abc");
|
// VelocityProxy.enable("abc");
|
||||||
//BungeeCordProxy.enable();
|
//BungeeCordProxy.enable();
|
||||||
|
|
||||||
//MojangAuth.init();c
|
//MojangAuth.init();
|
||||||
|
|
||||||
// useful for testing - we don't need to worry about event calls so just set this to a long time
|
// useful for testing - we don't need to worry about event calls so just set this to a long time
|
||||||
OpenToLAN.open(new OpenToLANConfig().eventCallDelay(Duration.of(1, TimeUnit.DAY)));
|
OpenToLAN.open(new OpenToLANConfig().eventCallDelay(Duration.of(1, TimeUnit.DAY)));
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package net.minestom.demo.commands;
|
||||||
|
|
||||||
|
import net.minestom.server.command.builder.Command;
|
||||||
|
import net.minestom.server.entity.Player;
|
||||||
|
|
||||||
|
public class ConfigCommand extends Command {
|
||||||
|
public ConfigCommand() {
|
||||||
|
super("config");
|
||||||
|
|
||||||
|
setDefaultExecutor((sender, context) -> {
|
||||||
|
if (!(sender instanceof Player player)) return;
|
||||||
|
player.startConfigurationPhase2();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1524,8 +1524,11 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev
|
|||||||
* WARNING: this does not trigger {@link EntityDeathEvent}.
|
* WARNING: this does not trigger {@link EntityDeathEvent}.
|
||||||
*/
|
*/
|
||||||
public void remove() {
|
public void remove() {
|
||||||
if (isRemoved()) return;
|
remove(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void remove(boolean permanent) {
|
||||||
|
if (isRemoved()) return;
|
||||||
EventDispatcher.call(new EntityDespawnEvent(this));
|
EventDispatcher.call(new EntityDespawnEvent(this));
|
||||||
try {
|
try {
|
||||||
despawn();
|
despawn();
|
||||||
@ -1541,10 +1544,21 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev
|
|||||||
|
|
||||||
MinecraftServer.process().dispatcher().removeElement(this);
|
MinecraftServer.process().dispatcher().removeElement(this);
|
||||||
this.removed = true;
|
this.removed = true;
|
||||||
Entity.ENTITY_BY_ID.remove(id);
|
if (permanent) {
|
||||||
Entity.ENTITY_BY_UUID.remove(uuid);
|
Entity.ENTITY_BY_ID.remove(id);
|
||||||
|
Entity.ENTITY_BY_UUID.remove(uuid);
|
||||||
|
} else {
|
||||||
|
// Reset some other state
|
||||||
|
this.position = Pos.ZERO;
|
||||||
|
this.previousPosition = Pos.ZERO;
|
||||||
|
this.lastSyncedPosition = Pos.ZERO;
|
||||||
|
}
|
||||||
Instance currentInstance = this.instance;
|
Instance currentInstance = this.instance;
|
||||||
if (currentInstance != null) removeFromInstance(currentInstance);
|
if (currentInstance != null) {
|
||||||
|
removeFromInstance(currentInstance);
|
||||||
|
this.instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,6 +60,7 @@ import net.minestom.server.network.PlayerProvider;
|
|||||||
import net.minestom.server.network.packet.client.ClientPacket;
|
import net.minestom.server.network.packet.client.ClientPacket;
|
||||||
import net.minestom.server.network.packet.server.SendablePacket;
|
import net.minestom.server.network.packet.server.SendablePacket;
|
||||||
import net.minestom.server.network.packet.server.ServerPacket;
|
import net.minestom.server.network.packet.server.ServerPacket;
|
||||||
|
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||||
import net.minestom.server.network.packet.server.common.*;
|
import net.minestom.server.network.packet.server.common.*;
|
||||||
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.login.LoginDisconnectPacket;
|
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
|
||||||
@ -249,19 +250,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
metadata.setNotifyAboutChanges(false);
|
metadata.setNotifyAboutChanges(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UNSAFE_enterConfiguration(boolean isFirstConfig) {
|
|
||||||
AsyncUtils.runAsync(() -> {
|
|
||||||
var event = new AsyncPlayerConfigurationEvent(this, isFirstConfig);
|
|
||||||
EventDispatcher.call(event);
|
|
||||||
|
|
||||||
final Instance spawningInstance = event.getSpawningInstance();
|
|
||||||
Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent");
|
|
||||||
|
|
||||||
MinecraftServer.getConnectionManager().startPlayState(this, event.getSpawningInstance());
|
|
||||||
sendPacket(new FinishConfigurationPacket());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used when the player is created.
|
* Used when the player is created.
|
||||||
* Init the player and spawn him.
|
* Init the player and spawn him.
|
||||||
@ -271,9 +259,12 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
*
|
*
|
||||||
* @param spawnInstance the player spawn instance (defined in {@link AsyncPlayerConfigurationEvent})
|
* @param spawnInstance the player spawn instance (defined in {@link AsyncPlayerConfigurationEvent})
|
||||||
*/
|
*/
|
||||||
|
@ApiStatus.Internal
|
||||||
public CompletableFuture<Void> UNSAFE_init(@NotNull Instance spawnInstance) {
|
public CompletableFuture<Void> UNSAFE_init(@NotNull Instance spawnInstance) {
|
||||||
this.dimensionType = spawnInstance.getDimensionType();
|
this.dimensionType = spawnInstance.getDimensionType();
|
||||||
|
|
||||||
|
System.out.println("INIT PLAYER");
|
||||||
|
|
||||||
final JoinGamePacket joinGamePacket = new JoinGamePacket(
|
final JoinGamePacket joinGamePacket = new JoinGamePacket(
|
||||||
getEntityId(), false, List.of(), 0,
|
getEntityId(), false, List.of(), 0,
|
||||||
MinecraftServer.getChunkViewDistance(), MinecraftServer.getChunkViewDistance(),
|
MinecraftServer.getChunkViewDistance(), MinecraftServer.getChunkViewDistance(),
|
||||||
@ -281,8 +272,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
0, gameMode, null, false, levelFlat, deathLocation, portalCooldown);
|
0, gameMode, null, false, levelFlat, deathLocation, portalCooldown);
|
||||||
sendPacket(joinGamePacket);
|
sendPacket(joinGamePacket);
|
||||||
|
|
||||||
// Server brand name
|
|
||||||
sendPacket(PluginMessagePacket.getBrandPacket());
|
|
||||||
// Difficulty
|
// Difficulty
|
||||||
sendPacket(new ServerDifficultyPacket(MinecraftServer.getDifficulty(), true));
|
sendPacket(new ServerDifficultyPacket(MinecraftServer.getDifficulty(), true));
|
||||||
|
|
||||||
@ -356,6 +345,71 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
return setInstance(spawnInstance);
|
return setInstance(spawnInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the player immediately to the configuration state. The player is automatically moved
|
||||||
|
* to configuration upon finishing login, this method can be used to move them back to configuration
|
||||||
|
* after entering the play state.
|
||||||
|
*
|
||||||
|
* <p>This will result in them being removed from the current instance, player list, etc.</p>
|
||||||
|
*/
|
||||||
|
public void startConfigurationPhase() {
|
||||||
|
boolean isFirstConfig = true;
|
||||||
|
|
||||||
|
// If the player is currently in the play state, we need to put them back in configuration.
|
||||||
|
if (playerConnection.getClientState() == ConnectionState.PLAY) {
|
||||||
|
remove(false);
|
||||||
|
sendPacket(new StartConfigurationPacket());
|
||||||
|
} else {
|
||||||
|
// Sanity check that they are already in configuration.
|
||||||
|
// On first join, they will already be in the config state when this is called.
|
||||||
|
assert playerConnection.getClientState() == ConnectionState.CONFIGURATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the event and spawn the player.
|
||||||
|
AsyncUtils.runAsync(() -> {
|
||||||
|
System.out.println("CALL EVENT");
|
||||||
|
var event = new AsyncPlayerConfigurationEvent(this, isFirstConfig);
|
||||||
|
EventDispatcher.call(event);
|
||||||
|
|
||||||
|
System.out.println("FINISHED EVENT");
|
||||||
|
final Instance spawningInstance = event.getSpawningInstance();
|
||||||
|
Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent");
|
||||||
|
|
||||||
|
MinecraftServer.getConnectionManager().startPlayState(this, event.getSpawningInstance());
|
||||||
|
sendPacket(new FinishConfigurationPacket());
|
||||||
|
System.out.println("SENT CHANGE PACKET");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startConfigurationPhase2() {
|
||||||
|
boolean isFirstConfig = true;
|
||||||
|
|
||||||
|
// If the player is currently in the play state, we need to put them back in configuration.
|
||||||
|
if (playerConnection.getClientState() == ConnectionState.PLAY) {
|
||||||
|
remove(false);
|
||||||
|
sendPacket(new StartConfigurationPacket());
|
||||||
|
} else {
|
||||||
|
// Sanity check that they are already in configuration.
|
||||||
|
// On first join, they will already be in the config state when this is called.
|
||||||
|
assert playerConnection.getClientState() == ConnectionState.CONFIGURATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the event and spawn the player.
|
||||||
|
// AsyncUtils.runAsync(() -> {
|
||||||
|
// System.out.println("CALL EVENT");
|
||||||
|
// var event = new AsyncPlayerConfigurationEvent(this, isFirstConfig);
|
||||||
|
// EventDispatcher.call(event);
|
||||||
|
//
|
||||||
|
// System.out.println("FINISHED EVENT");
|
||||||
|
// final Instance spawningInstance = event.getSpawningInstance();
|
||||||
|
// Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent");
|
||||||
|
//
|
||||||
|
// MinecraftServer.getConnectionManager().startPlayState(this, event.getSpawningInstance());
|
||||||
|
// sendPacket(new FinishConfigurationPacket());
|
||||||
|
// System.out.println("SENT CHANGE PACKET");
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to initialize the player connection
|
* Used to initialize the player connection
|
||||||
*/
|
*/
|
||||||
@ -538,11 +592,16 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public void remove(boolean permanent) {
|
||||||
if (isRemoved()) return;
|
if (isRemoved()) return;
|
||||||
EventDispatcher.call(new PlayerDisconnectEvent(this));
|
|
||||||
super.remove();
|
if (permanent) {
|
||||||
this.packets.clear();
|
this.packets.clear();
|
||||||
|
EventDispatcher.call(new PlayerDisconnectEvent(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
super.remove(permanent);
|
||||||
|
|
||||||
final Inventory currentInventory = getOpenInventory();
|
final Inventory currentInventory = getOpenInventory();
|
||||||
if (currentInventory != null) currentInventory.removeViewer(this);
|
if (currentInventory != null) currentInventory.removeViewer(this);
|
||||||
MinecraftServer.getBossBarManager().removeAllBossBars(this);
|
MinecraftServer.getBossBarManager().removeAllBossBars(this);
|
||||||
@ -565,7 +624,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
|
|
||||||
// Prevent the player from being stuck in loading screen, or just unable to interact with the server
|
// Prevent the player from being stuck in loading screen, or just unable to interact with the server
|
||||||
// This should be considered as a bug, since the player will ultimately time out anyway.
|
// This should be considered as a bug, since the player will ultimately time out anyway.
|
||||||
if (playerConnection.isOnline()) kick(REMOVE_MESSAGE);
|
if (permanent && playerConnection.isOnline()) kick(REMOVE_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package net.minestom.server.listener;
|
||||||
|
|
||||||
|
import net.minestom.server.entity.Player;
|
||||||
|
import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class PlayConfigListener {
|
||||||
|
|
||||||
|
public static void configAckListener(@NotNull ClientConfigurationAckPacket packet, @NotNull Player player) {
|
||||||
|
player.startConfigurationPhase();
|
||||||
|
}
|
||||||
|
}
|
@ -65,6 +65,7 @@ public final class PacketListenerManager {
|
|||||||
setPlayListener(ClientChatMessagePacket.class, ChatMessageListener::chatMessageListener);
|
setPlayListener(ClientChatMessagePacket.class, ChatMessageListener::chatMessageListener);
|
||||||
setPlayListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener);
|
setPlayListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener);
|
||||||
setPlayListener(ClientCloseWindowPacket.class, WindowListener::closeWindowListener);
|
setPlayListener(ClientCloseWindowPacket.class, WindowListener::closeWindowListener);
|
||||||
|
setPlayListener(ClientConfigurationAckPacket.class, PlayConfigListener::configAckListener);
|
||||||
setPlayListener(ClientPongPacket.class, WindowListener::pong);
|
setPlayListener(ClientPongPacket.class, WindowListener::pong);
|
||||||
setPlayListener(ClientEntityActionPacket.class, EntityActionListener::listener);
|
setPlayListener(ClientEntityActionPacket.class, EntityActionListener::listener);
|
||||||
setPlayListener(ClientHeldItemChangePacket.class, PlayerHeldListener::heldListener);
|
setPlayListener(ClientHeldItemChangePacket.class, PlayerHeldListener::heldListener);
|
||||||
|
@ -8,24 +8,19 @@ 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.entity.damage.DamageType;
|
||||||
import net.minestom.server.event.EventDispatcher;
|
|
||||||
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
|
|
||||||
import net.minestom.server.extras.MojangAuth;
|
import net.minestom.server.extras.MojangAuth;
|
||||||
import net.minestom.server.extras.bungee.BungeeCordProxy;
|
import net.minestom.server.extras.bungee.BungeeCordProxy;
|
||||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||||
import net.minestom.server.extras.velocity.VelocityProxy;
|
import net.minestom.server.extras.velocity.VelocityProxy;
|
||||||
import net.minestom.server.instance.Instance;
|
|
||||||
import net.minestom.server.message.Messenger;
|
import net.minestom.server.message.Messenger;
|
||||||
import net.minestom.server.network.ConnectionManager;
|
import net.minestom.server.network.ConnectionManager;
|
||||||
import net.minestom.server.network.ConnectionState;
|
|
||||||
import net.minestom.server.network.NetworkBuffer;
|
import net.minestom.server.network.NetworkBuffer;
|
||||||
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;
|
||||||
import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket;
|
import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket;
|
||||||
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.ResourcePackSendPacket;
|
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.common.TagsPacket;
|
||||||
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.configuration.RegistryDataPacket;
|
||||||
import net.minestom.server.network.packet.server.login.EncryptionRequestPacket;
|
import net.minestom.server.network.packet.server.login.EncryptionRequestPacket;
|
||||||
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
|
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
|
||||||
@ -33,12 +28,9 @@ import net.minestom.server.network.packet.server.login.LoginPluginRequestPacket;
|
|||||||
import net.minestom.server.network.player.GameProfile;
|
import net.minestom.server.network.player.GameProfile;
|
||||||
import net.minestom.server.network.player.PlayerConnection;
|
import net.minestom.server.network.player.PlayerConnection;
|
||||||
import net.minestom.server.network.player.PlayerSocketConnection;
|
import net.minestom.server.network.player.PlayerSocketConnection;
|
||||||
import net.minestom.server.registry.Registry;
|
|
||||||
import net.minestom.server.utils.async.AsyncUtils;
|
import net.minestom.server.utils.async.AsyncUtils;
|
||||||
import net.minestom.server.utils.validate.Check;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||||
import org.jglrxavpok.hephaistos.nbt.NBTType;
|
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@ -49,7 +41,6 @@ import java.net.http.HttpResponse;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
import static net.minestom.server.network.NetworkBuffer.STRING;
|
import static net.minestom.server.network.NetworkBuffer.STRING;
|
||||||
@ -241,8 +232,11 @@ public final class LoginListener {
|
|||||||
// Tags
|
// Tags
|
||||||
connection.sendPacket(TagsPacket.DEFAULT_TAGS);
|
connection.sendPacket(TagsPacket.DEFAULT_TAGS);
|
||||||
|
|
||||||
|
// Server Brand
|
||||||
|
connection.sendPacket(PluginMessagePacket.getBrandPacket());
|
||||||
|
|
||||||
// Enter configuration phase (for the first time)
|
// Enter configuration phase (for the first time)
|
||||||
player.UNSAFE_enterConfiguration(true);
|
player.startConfigurationPhase();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,13 @@ import net.minestom.server.event.EventDispatcher;
|
|||||||
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.network.packet.client.login.ClientLoginStartPacket;
|
import net.minestom.server.network.packet.client.login.ClientLoginStartPacket;
|
||||||
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
|
|
||||||
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.login.LoginSuccessPacket;
|
||||||
import net.minestom.server.network.player.PlayerConnection;
|
import net.minestom.server.network.player.PlayerConnection;
|
||||||
import net.minestom.server.network.player.PlayerSocketConnection;
|
import net.minestom.server.network.player.PlayerSocketConnection;
|
||||||
import net.minestom.server.utils.StringUtils;
|
import net.minestom.server.utils.StringUtils;
|
||||||
import net.minestom.server.utils.async.AsyncUtils;
|
import net.minestom.server.utils.async.AsyncUtils;
|
||||||
import net.minestom.server.utils.debug.DebugUtils;
|
import net.minestom.server.utils.debug.DebugUtils;
|
||||||
import net.minestom.server.utils.validate.Check;
|
|
||||||
import org.jctools.queues.MessagePassingQueue;
|
import org.jctools.queues.MessagePassingQueue;
|
||||||
import org.jctools.queues.MpscUnboundedArrayQueue;
|
import org.jctools.queues.MpscUnboundedArrayQueue;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
@ -36,11 +35,14 @@ public final class ConnectionManager {
|
|||||||
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);
|
||||||
|
|
||||||
private record PendingPlayer(@NotNull Player player, @NotNull Instance instance) {}
|
private record PendingPlayer(@NotNull Player player, @NotNull Instance instance) {
|
||||||
|
}
|
||||||
|
|
||||||
private final MessagePassingQueue<PendingPlayer> waitingPlayers = new MpscUnboundedArrayQueue<>(64);
|
private final MessagePassingQueue<PendingPlayer> waitingPlayers = new MpscUnboundedArrayQueue<>(64);
|
||||||
private final Set<Player> players = new CopyOnWriteArraySet<>();
|
private final Set<Player> players = new CopyOnWriteArraySet<>();
|
||||||
private final Set<Player> unmodifiablePlayers = Collections.unmodifiableSet(players);
|
private final Set<Player> unmodifiablePlayers = Collections.unmodifiableSet(players);
|
||||||
|
|
||||||
|
// All players once their Player object has been instantiated.
|
||||||
private final Map<PlayerConnection, Player> connectionPlayerMap = new ConcurrentHashMap<>();
|
private final Map<PlayerConnection, Player> connectionPlayerMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
// The uuid provider once a player login
|
// The uuid provider once a player login
|
||||||
@ -48,16 +50,6 @@ public final class ConnectionManager {
|
|||||||
// The player provider to have your own Player implementation
|
// The player provider to have your own Player implementation
|
||||||
private volatile PlayerProvider playerProvider = Player::new;
|
private volatile PlayerProvider playerProvider = Player::new;
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the {@link Player} linked to a {@link PlayerConnection}.
|
|
||||||
*
|
|
||||||
* @param connection the player connection
|
|
||||||
* @return the player linked to the connection
|
|
||||||
*/
|
|
||||||
public Player getPlayer(@NotNull PlayerConnection connection) {
|
|
||||||
return connectionPlayerMap.get(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all online players.
|
* Gets all online players.
|
||||||
*
|
*
|
||||||
@ -68,25 +60,28 @@ public final class ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the closest player matching a given username.
|
* Gets online players filtered by state.
|
||||||
*
|
*
|
||||||
* @param username the player username (can be partial)
|
* <p>States before login are not considered online, and will result in nothing being returned.</p>
|
||||||
* @return the closest match, null if no players are online
|
*
|
||||||
|
* @return An unmodifiable collection containing the filtered players.
|
||||||
|
* @apiNote The returned collection has no defined update behavior relative to the state of the server,
|
||||||
|
* so it should be refetched whenever used, rather than kept and reused.
|
||||||
*/
|
*/
|
||||||
public @Nullable Player findPlayer(@NotNull String username) {
|
public @NotNull Collection<@NotNull Player> getPlayers(@NotNull ConnectionState... state) {
|
||||||
Player exact = getPlayer(username);
|
// connectionPlayerMap.values().stream()
|
||||||
if (exact != null) return exact;
|
// .filter()
|
||||||
final String username1 = username.toLowerCase(Locale.ROOT);
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
Function<Player, Double> distanceFunction = player -> {
|
/**
|
||||||
final String username2 = player.getUsername().toLowerCase(Locale.ROOT);
|
* Gets the {@link Player} linked to a {@link PlayerConnection}.
|
||||||
return StringUtils.jaroWinklerScore(username1, username2);
|
*
|
||||||
};
|
* @param connection the player connection
|
||||||
return getOnlinePlayers()
|
* @return the player linked to the connection
|
||||||
.stream()
|
*/
|
||||||
.min(Comparator.comparingDouble(distanceFunction::apply))
|
public Player getPlayer(@NotNull PlayerConnection connection) {
|
||||||
.filter(player -> distanceFunction.apply(player) > 0)
|
return connectionPlayerMap.get(connection);
|
||||||
.orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,6 +116,28 @@ public final class ConnectionManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the closest player matching a given username.
|
||||||
|
*
|
||||||
|
* @param username the player username (can be partial)
|
||||||
|
* @return the closest match, null if no players are online
|
||||||
|
*/
|
||||||
|
public @Nullable Player findPlayer(@NotNull String username) {
|
||||||
|
Player exact = getPlayer(username);
|
||||||
|
if (exact != null) return exact;
|
||||||
|
final String username1 = username.toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
|
Function<Player, Double> distanceFunction = player -> {
|
||||||
|
final String username2 = player.getUsername().toLowerCase(Locale.ROOT);
|
||||||
|
return StringUtils.jaroWinklerScore(username1, username2);
|
||||||
|
};
|
||||||
|
return getOnlinePlayers()
|
||||||
|
.stream()
|
||||||
|
.min(Comparator.comparingDouble(distanceFunction::apply))
|
||||||
|
.filter(player -> distanceFunction.apply(player) > 0)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes how {@link UUID} are attributed to players.
|
* Changes how {@link UUID} are attributed to players.
|
||||||
* <p>
|
* <p>
|
||||||
@ -168,6 +185,23 @@ public final class ConnectionManager {
|
|||||||
return playerProvider;
|
return playerProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo REDONE TRANSITIONS
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public void transitionLoginToConfig(@NotNull Player player) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public void transitionConfigToPlay(@NotNull Player player) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public void transitionPlayToConfig(@NotNull Player player) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a {@link Player} to the players list.
|
* Adds a {@link Player} to the players list.
|
||||||
* <p>
|
* <p>
|
||||||
@ -198,7 +232,7 @@ public final class ConnectionManager {
|
|||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
public @NotNull Player startConfigurationState(@NotNull PlayerConnection connection,
|
public @NotNull Player startConfigurationState(@NotNull PlayerConnection connection,
|
||||||
@NotNull UUID uuid, @NotNull String username) {
|
@NotNull UUID uuid, @NotNull String username) {
|
||||||
final Player player = playerProvider.createPlayer(uuid, username, connection);
|
final Player player = playerProvider.createPlayer(uuid, username, connection);
|
||||||
startConfigurationState(player);
|
startConfigurationState(player);
|
||||||
return player;
|
return player;
|
||||||
@ -255,6 +289,8 @@ public final class ConnectionManager {
|
|||||||
public void updateWaitingPlayers() {
|
public void updateWaitingPlayers() {
|
||||||
this.waitingPlayers.drain(pp -> {
|
this.waitingPlayers.drain(pp -> {
|
||||||
|
|
||||||
|
System.out.println("DRAIN PP " + pp);
|
||||||
|
|
||||||
// Spawn the player at Player#getRespawnPoint
|
// Spawn the player at Player#getRespawnPoint
|
||||||
CompletableFuture<Void> spawnFuture = pp.player.UNSAFE_init(pp.instance);
|
CompletableFuture<Void> spawnFuture = pp.player.UNSAFE_init(pp.instance);
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ public sealed class ClientPacketsHandler permits ClientPacketsHandler.Status, Cl
|
|||||||
register(nextId(), ClientStatusPacket::new);
|
register(nextId(), ClientStatusPacket::new);
|
||||||
register(nextId(), ClientSettingsPacket::new);
|
register(nextId(), ClientSettingsPacket::new);
|
||||||
register(nextId(), ClientTabCompletePacket::new);
|
register(nextId(), ClientTabCompletePacket::new);
|
||||||
nextId(); // configuration acknowledged
|
register(nextId(), ClientConfigurationAckPacket::new);
|
||||||
register(nextId(), ClientClickWindowButtonPacket::new);
|
register(nextId(), ClientClickWindowButtonPacket::new);
|
||||||
register(nextId(), ClientClickWindowPacket::new);
|
register(nextId(), ClientClickWindowPacket::new);
|
||||||
register(nextId(), ClientCloseWindowPacket::new);
|
register(nextId(), ClientCloseWindowPacket::new);
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package net.minestom.server.network.packet.client.play;
|
||||||
|
|
||||||
|
import net.minestom.server.network.ConnectionState;
|
||||||
|
import net.minestom.server.network.NetworkBuffer;
|
||||||
|
import net.minestom.server.network.packet.client.ClientPacket;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public record ClientConfigurationAckPacket() implements ClientPacket {
|
||||||
|
|
||||||
|
public ClientConfigurationAckPacket(@NotNull NetworkBuffer buffer) {
|
||||||
|
this();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(@NotNull NetworkBuffer writer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConnectionState nextState() {
|
||||||
|
return ConnectionState.CONFIGURATION;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package net.minestom.server.network.packet.server.play;
|
||||||
|
|
||||||
|
import net.minestom.server.network.ConnectionState;
|
||||||
|
import net.minestom.server.network.NetworkBuffer;
|
||||||
|
import net.minestom.server.network.packet.server.ServerPacket;
|
||||||
|
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public record StartConfigurationPacket() implements ServerPacket {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(@NotNull NetworkBuffer writer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId(@NotNull ConnectionState state) {
|
||||||
|
return ServerPacketIdentifier.START_CONFIGURATION_PACKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConnectionState nextState() {
|
||||||
|
return ConnectionState.CONFIGURATION;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user