mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-25 10:38:18 +01:00
Misc network improvement
This commit is contained in:
parent
54fd65eded
commit
71b6e8df90
@ -2,14 +2,12 @@ package net.minestom.server.network;
|
|||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
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.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.EventDispatcher;
|
import net.minestom.server.event.EventDispatcher;
|
||||||
import net.minestom.server.event.player.AsyncPlayerPreLoginEvent;
|
import net.minestom.server.event.player.AsyncPlayerPreLoginEvent;
|
||||||
import net.minestom.server.event.player.PlayerLoginEvent;
|
import net.minestom.server.event.player.PlayerLoginEvent;
|
||||||
import net.minestom.server.instance.Instance;
|
import net.minestom.server.instance.Instance;
|
||||||
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.DisconnectPacket;
|
|
||||||
import net.minestom.server.network.packet.server.play.KeepAlivePacket;
|
import net.minestom.server.network.packet.server.play.KeepAlivePacket;
|
||||||
import net.minestom.server.network.player.PlayerConnection;
|
import net.minestom.server.network.player.PlayerConnection;
|
||||||
import net.minestom.server.utils.StringUtils;
|
import net.minestom.server.utils.StringUtils;
|
||||||
@ -45,8 +43,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;
|
||||||
|
|
||||||
private Component shutdownText = Component.text("The server is shutting down.", NamedTextColor.RED);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link Player} linked to a {@link PlayerConnection}.
|
* Gets the {@link Player} linked to a {@link PlayerConnection}.
|
||||||
*
|
*
|
||||||
@ -167,25 +163,6 @@ public final class ConnectionManager {
|
|||||||
return playerProvider;
|
return playerProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the kick reason when the server is shutdown using {@link MinecraftServer#stopCleanly()}.
|
|
||||||
*
|
|
||||||
* @return the kick reason in case on a shutdown
|
|
||||||
*/
|
|
||||||
public @NotNull Component getShutdownText() {
|
|
||||||
return shutdownText;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the kick reason in case of a shutdown.
|
|
||||||
*
|
|
||||||
* @param shutdownText the new shutdown kick reason
|
|
||||||
* @see #getShutdownText()
|
|
||||||
*/
|
|
||||||
public void setShutdownText(@NotNull Component shutdownText) {
|
|
||||||
this.shutdownText = shutdownText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void registerPlayer(@NotNull Player player) {
|
public synchronized void registerPlayer(@NotNull Player player) {
|
||||||
this.players.add(player);
|
this.players.add(player);
|
||||||
this.connectionPlayerMap.put(player.getPlayerConnection(), player);
|
this.connectionPlayerMap.put(player.getPlayerConnection(), player);
|
||||||
@ -220,12 +197,8 @@ public final class ConnectionManager {
|
|||||||
// Call pre login event
|
// Call pre login event
|
||||||
AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(player);
|
AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(player);
|
||||||
EventDispatcher.call(asyncPlayerPreLoginEvent);
|
EventDispatcher.call(asyncPlayerPreLoginEvent);
|
||||||
// Close the player channel if he has been disconnected (kick)
|
if (!player.isOnline())
|
||||||
if (!player.isOnline()) {
|
return; // Player has been kicked
|
||||||
playerConnection.flush();
|
|
||||||
//playerConnection.disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Change UUID/Username based on the event
|
// Change UUID/Username based on the event
|
||||||
{
|
{
|
||||||
final String eventUsername = asyncPlayerPreLoginEvent.getUsername();
|
final String eventUsername = asyncPlayerPreLoginEvent.getUsername();
|
||||||
@ -265,14 +238,6 @@ public final class ConnectionManager {
|
|||||||
* Shutdowns the connection manager by kicking all the currently connected players.
|
* Shutdowns the connection manager by kicking all the currently connected players.
|
||||||
*/
|
*/
|
||||||
public synchronized void shutdown() {
|
public synchronized void shutdown() {
|
||||||
DisconnectPacket disconnectPacket = new DisconnectPacket(shutdownText);
|
|
||||||
for (Player player : getOnlinePlayers()) {
|
|
||||||
final PlayerConnection playerConnection = player.getPlayerConnection();
|
|
||||||
playerConnection.sendPacket(disconnectPacket);
|
|
||||||
playerConnection.flush();
|
|
||||||
player.remove();
|
|
||||||
playerConnection.disconnect();
|
|
||||||
}
|
|
||||||
this.players.clear();
|
this.players.clear();
|
||||||
this.connectionPlayerMap.clear();
|
this.connectionPlayerMap.clear();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.minestom.server.network.player;
|
package net.minestom.server.network.player;
|
||||||
|
|
||||||
import net.minestom.server.MinecraftServer;
|
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.entity.fakeplayer.FakePlayer;
|
import net.minestom.server.entity.fakeplayer.FakePlayer;
|
||||||
import net.minestom.server.entity.fakeplayer.FakePlayerController;
|
import net.minestom.server.entity.fakeplayer.FakePlayerController;
|
||||||
@ -27,13 +26,6 @@ public class FakePlayerConnection extends PlayerConnection {
|
|||||||
return new InetSocketAddress(0);
|
return new InetSocketAddress(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disconnect() {
|
|
||||||
super.disconnect();
|
|
||||||
if (getFakePlayer().getOption().isRegistered())
|
|
||||||
MinecraftServer.getConnectionManager().removePlayer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FakePlayer getFakePlayer() {
|
public FakePlayer getFakePlayer() {
|
||||||
return (FakePlayer) getPlayer();
|
return (FakePlayer) getPlayer();
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package net.minestom.server.network.player;
|
|||||||
import net.kyori.adventure.text.Component;
|
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.Entity;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||||
import net.minestom.server.network.ConnectionState;
|
import net.minestom.server.network.ConnectionState;
|
||||||
@ -95,15 +96,6 @@ public abstract class PlayerConnection {
|
|||||||
sendPackets(List.of(packets));
|
sendPackets(List.of(packets));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush waiting data to the connection.
|
|
||||||
* <p>
|
|
||||||
* Might not do anything depending on the implementation.
|
|
||||||
*/
|
|
||||||
public void flush() {
|
|
||||||
// Empty
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the remote address of the client.
|
* Gets the remote address of the client.
|
||||||
*
|
*
|
||||||
@ -148,6 +140,11 @@ public abstract class PlayerConnection {
|
|||||||
*/
|
*/
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
this.online = false;
|
this.online = false;
|
||||||
|
MinecraftServer.getConnectionManager().removePlayer(this);
|
||||||
|
final Player player = getPlayer();
|
||||||
|
if (player != null && !player.isRemoved()) {
|
||||||
|
player.scheduleNextTick(Entity::remove);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -182,11 +182,6 @@ public class PlayerSocketConnection extends PlayerConnection {
|
|||||||
write(buffer, buffer.position(), buffer.remaining());
|
write(buffer, buffer.position(), buffer.remaining());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
this.workerQueue.relaxedOffer(this::flushSync);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull SocketAddress getRemoteAddress() {
|
public @NotNull SocketAddress getRemoteAddress() {
|
||||||
return remoteAddress;
|
return remoteAddress;
|
||||||
@ -377,7 +372,6 @@ public class PlayerSocketConnection extends PlayerConnection {
|
|||||||
}
|
}
|
||||||
var buffer = PacketUtils.createFramedPacket(serverPacket, compressed);
|
var buffer = PacketUtils.createFramedPacket(serverPacket, compressed);
|
||||||
writeBufferSync0(buffer, 0, buffer.limit());
|
writeBufferSync0(buffer, 0, buffer.limit());
|
||||||
if (player == null) flushSync(); // Player is probably not logged yet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeBufferSync(@NotNull ByteBuffer buffer, int index, int length) {
|
private void writeBufferSync(@NotNull ByteBuffer buffer, int index, int length) {
|
||||||
@ -418,10 +412,8 @@ public class PlayerSocketConnection extends PlayerConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flushSync() {
|
public void flushSync() throws IOException {
|
||||||
try {
|
|
||||||
if (!channel.isConnected()) throw new ClosedChannelException();
|
if (!channel.isConnected()) throw new ClosedChannelException();
|
||||||
try {
|
|
||||||
if (waitingBuffers.isEmpty() && tickBuffer.getPlain().writeChannel(channel))
|
if (waitingBuffers.isEmpty() && tickBuffer.getPlain().writeChannel(channel))
|
||||||
return; // Fast exit if the tick buffer can be reused
|
return; // Fast exit if the tick buffer can be reused
|
||||||
|
|
||||||
@ -441,13 +433,6 @@ public class PlayerSocketConnection extends PlayerConnection {
|
|||||||
iterator.remove();
|
iterator.remove();
|
||||||
PooledBuffers.add(waitingBuffer);
|
PooledBuffers.add(waitingBuffer);
|
||||||
}
|
}
|
||||||
} catch (IOException e) { // Couldn't write to the socket
|
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
|
||||||
throw new ClosedChannelException();
|
|
||||||
}
|
|
||||||
} catch (ClosedChannelException e) {
|
|
||||||
disconnect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BinaryBuffer updateLocalBuffer() {
|
private BinaryBuffer updateLocalBuffer() {
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package net.minestom.server.network.socket;
|
package net.minestom.server.network.socket;
|
||||||
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.entity.Entity;
|
|
||||||
import net.minestom.server.entity.Player;
|
|
||||||
import net.minestom.server.network.player.PlayerSocketConnection;
|
import net.minestom.server.network.player.PlayerSocketConnection;
|
||||||
import net.minestom.server.thread.MinestomThread;
|
import net.minestom.server.thread.MinestomThread;
|
||||||
import net.minestom.server.utils.binary.BinaryBuffer;
|
import net.minestom.server.utils.binary.BinaryBuffer;
|
||||||
@ -49,17 +47,27 @@ public final class Worker extends MinestomThread {
|
|||||||
MinecraftServer.getExceptionManager().handleException(e);
|
MinecraftServer.getExceptionManager().handleException(e);
|
||||||
}
|
}
|
||||||
// Flush all connections if needed
|
// Flush all connections if needed
|
||||||
|
for (PlayerSocketConnection connection : connectionMap.values()) {
|
||||||
try {
|
try {
|
||||||
connectionMap.values().forEach(PlayerSocketConnection::flushSync);
|
connection.flushSync();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
connection.disconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Wait for an event
|
// Wait for an event
|
||||||
this.selector.select(key -> {
|
this.selector.select(key -> {
|
||||||
final SocketChannel channel = (SocketChannel) key.channel();
|
final SocketChannel channel = (SocketChannel) key.channel();
|
||||||
if (!channel.isOpen()) return;
|
if (!channel.isOpen()) return;
|
||||||
if (!key.isReadable()) return;
|
if (!key.isReadable()) return;
|
||||||
PlayerSocketConnection connection = connectionMap.get(channel);
|
final PlayerSocketConnection connection = connectionMap.get(channel);
|
||||||
|
if (connection == null) {
|
||||||
|
try {
|
||||||
|
channel.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Empty
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
BinaryBuffer readBuffer = BinaryBuffer.wrap(PooledBuffers.packetBuffer());
|
BinaryBuffer readBuffer = BinaryBuffer.wrap(PooledBuffers.packetBuffer());
|
||||||
// Consume last incomplete packet
|
// Consume last incomplete packet
|
||||||
@ -84,17 +92,14 @@ public final class Worker extends MinestomThread {
|
|||||||
public void disconnect(PlayerSocketConnection connection, SocketChannel channel) {
|
public void disconnect(PlayerSocketConnection connection, SocketChannel channel) {
|
||||||
assert !connection.isOnline();
|
assert !connection.isOnline();
|
||||||
assert Thread.currentThread() == this;
|
assert Thread.currentThread() == this;
|
||||||
connection.flushSync();
|
|
||||||
try {
|
|
||||||
channel.close();
|
|
||||||
this.connectionMap.remove(channel);
|
this.connectionMap.remove(channel);
|
||||||
MinecraftServer.getConnectionManager().removePlayer(connection);
|
if (channel.isOpen()) {
|
||||||
Player player = connection.getPlayer();
|
try {
|
||||||
if (player != null && !player.isRemoved()) {
|
connection.flushSync();
|
||||||
player.scheduleNextTick(Entity::remove);
|
channel.close();
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
// Socket operation may fail if the socket is already closed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user