Search in sources :

Example 1 with ServerSideConnection

use of org.spongepowered.api.network.ServerSideConnection in project SpongeCommon by SpongePowered.

the class ServerLoginPacketListenerImplMixin method handleAcceptedLogin.

/**
 * @author morph - April 27th, 2021
 * @author dualspiral - July 17th, 2021
 *
 * @reason support async ban/whitelist service and user->player syncing.
 */
@Overwrite
public void handleAcceptedLogin() {
    if (!this.gameProfile.isComplete()) {
        this.gameProfile = this.shadow$createFakeProfile(this.gameProfile);
    }
    // Sponge start - avoid #tick calling handleAcceptedLogin more than once.
    if (this.impl$accepted) {
        return;
    }
    this.impl$accepted = true;
    final PlayerList playerList = this.server.getPlayerList();
    // Sponge end
    // Sponge start - completable future
    ((PlayerListBridge) playerList).bridge$canPlayerLogin(this.connection.getRemoteAddress(), this.gameProfile).handle((componentOpt, throwable) -> {
        if (throwable != null) {
            // An error occurred during login checks so we ask to abort.
            ((ConnectionBridge) this.connection).bridge$setKickReason(new TextComponent("An error occurred checking ban/whitelist status."));
            SpongeCommon.logger().error("An error occurred when checking the ban/whitelist status of {}.", this.gameProfile.getId().toString());
            SpongeCommon.logger().error(throwable);
        } else if (componentOpt != null) {
            // We handle this later
            ((ConnectionBridge) this.connection).bridge$setKickReason(componentOpt);
        }
        try {
            ((SpongeServer) SpongeCommon.server()).userManager().handlePlayerLogin(this.gameProfile);
        } catch (final IOException e) {
            throw new CompletionException(e);
        }
        return null;
    }).handleAsync((ignored, throwable) -> {
        if (throwable != null) {
            // We're just going to disconnect here, because something went horribly wrong.
            if (throwable instanceof CompletionException) {
                throw (CompletionException) throwable;
            } else {
                throw new CompletionException(throwable);
            }
        }
        // Sponge end
        this.state = ServerLoginPacketListenerImpl.State.ACCEPTED;
        if (this.server.getCompressionThreshold() >= 0 && !this.connection.isMemoryConnection()) {
            this.connection.send(new ClientboundLoginCompressionPacket(this.server.getCompressionThreshold()), (param0) -> this.connection.setupCompression(this.server.getCompressionThreshold()));
        }
        this.connection.send(new ClientboundGameProfilePacket(this.gameProfile));
        final ServerPlayer var1 = this.server.getPlayerList().getPlayer(this.gameProfile.getId());
        if (var1 != null) {
            this.state = ServerLoginPacketListenerImpl.State.DELAY_ACCEPT;
            this.delayedAcceptPlayer = this.server.getPlayerList().getPlayerForLogin(this.gameProfile);
        } else {
            // Sponge start - Also send the channel registrations using the minecraft channel, for compatibility
            final ServerSideConnection connection = (ServerSideConnection) this;
            ((SpongeChannelManager) Sponge.channelManager()).sendChannelRegistrations(connection);
            try {
                this.server.getPlayerList().placeNewPlayer(this.connection, this.server.getPlayerList().getPlayerForLogin(this.gameProfile));
                // invalidate just to be sure there is no user cached for the online player anymore
                Sponge.server().userManager().removeFromCache(this.gameProfile.getId());
            } catch (final Exception e) {
                throw new RuntimeException(e);
            }
        }
        return null;
    }, SpongeCommon.server()).exceptionally(throwable -> {
        // If a throwable exists, we're just going to disconnect the user, better than leaving them in limbo.
        if (throwable != null) {
            this.impl$disconnectError(throwable, this.state == ServerLoginPacketListenerImpl.State.ACCEPTED || this.state == ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT);
        }
        return null;
    // Sponge End
    });
}
Also used : TextComponent(net.minecraft.network.chat.TextComponent) ServerSideConnection(org.spongepowered.api.network.ServerSideConnection) ConnectionBridge(org.spongepowered.common.bridge.network.ConnectionBridge) ServerSideConnectionEvent(org.spongepowered.api.event.network.ServerSideConnectionEvent) Inject(org.spongepowered.asm.mixin.injection.Inject) SpongeServer(org.spongepowered.common.SpongeServer) Connection(net.minecraft.network.Connection) Overwrite(org.spongepowered.asm.mixin.Overwrite) SpongeAdventure(org.spongepowered.common.adventure.SpongeAdventure) EventContext(org.spongepowered.api.event.EventContext) PlayerList(net.minecraft.server.players.PlayerList) ClientboundLoginCompressionPacket(net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket) ServerPlayer(net.minecraft.server.level.ServerPlayer) CallbackInfo(org.spongepowered.asm.mixin.injection.callback.CallbackInfo) MinecraftServer(net.minecraft.server.MinecraftServer) Mixin(org.spongepowered.asm.mixin.Mixin) Component(net.kyori.adventure.text.Component) ConnectionHolderBridge(org.spongepowered.common.bridge.network.ConnectionHolderBridge) PlayerListBridge(org.spongepowered.common.bridge.server.players.PlayerListBridge) At(org.spongepowered.asm.mixin.injection.At) Opcodes(org.objectweb.asm.Opcodes) ServerLoginPacketListenerImplBridge(org.spongepowered.common.bridge.server.network.ServerLoginPacketListenerImplBridge) ClientboundGameProfilePacket(net.minecraft.network.protocol.login.ClientboundGameProfilePacket) ServerLoginPacketListenerImpl(net.minecraft.server.network.ServerLoginPacketListenerImpl) Redirect(org.spongepowered.asm.mixin.injection.Redirect) SpongeEventFactory(org.spongepowered.api.event.SpongeEventFactory) Sponge(org.spongepowered.api.Sponge) SpongeChannelManager(org.spongepowered.common.network.channel.SpongeChannelManager) IOException(java.io.IOException) CompletionException(java.util.concurrent.CompletionException) SpongeCommon(org.spongepowered.common.SpongeCommon) Final(org.spongepowered.asm.mixin.Final) ClientboundDisconnectPacket(net.minecraft.network.protocol.game.ClientboundDisconnectPacket) Cause(org.spongepowered.api.event.Cause) TextComponent(net.minecraft.network.chat.TextComponent) Shadow(org.spongepowered.asm.mixin.Shadow) ClientboundLoginCompressionPacket(net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket) PlayerList(net.minecraft.server.players.PlayerList) ConnectionBridge(org.spongepowered.common.bridge.network.ConnectionBridge) CompletionException(java.util.concurrent.CompletionException) ServerPlayer(net.minecraft.server.level.ServerPlayer) ServerSideConnection(org.spongepowered.api.network.ServerSideConnection) IOException(java.io.IOException) IOException(java.io.IOException) CompletionException(java.util.concurrent.CompletionException) ClientboundGameProfilePacket(net.minecraft.network.protocol.login.ClientboundGameProfilePacket) Overwrite(org.spongepowered.asm.mixin.Overwrite)

Example 2 with ServerSideConnection

use of org.spongepowered.api.network.ServerSideConnection in project SpongeCommon by SpongePowered.

the class ServerLoginPacketListenerImplMixin_Vanilla method impl$onTick.

@Inject(method = "tick", at = @At("HEAD"))
private void impl$onTick(final CallbackInfo ci) {
    if (this.state == ServerLoginPacketListenerImpl.State.NEGOTIATING) {
        final ServerSideConnection connection = (ServerSideConnection) this;
        if (this.impl$handshakeState == ServerLoginPacketListenerImplMixin_Vanilla.HANDSHAKE_NOT_STARTED) {
            this.impl$handshakeState = ServerLoginPacketListenerImplMixin_Vanilla.HANDSHAKE_CLIENT_TYPE;
            ((SpongeChannelManager) Sponge.channelManager()).requestClientType(connection).thenAccept(result -> {
                this.impl$handshakeState = ServerLoginPacketListenerImplMixin_Vanilla.HANDSHAKE_SYNC_CHANNEL_REGISTRATIONS;
            });
        } else if (this.impl$handshakeState == ServerLoginPacketListenerImplMixin_Vanilla.HANDSHAKE_SYNC_CHANNEL_REGISTRATIONS) {
            ((SpongeChannelManager) Sponge.channelManager()).sendLoginChannelRegistry(connection).thenAccept(result -> {
                final Cause cause = Cause.of(EventContext.empty(), this);
                final ServerSideConnectionEvent.Handshake event = SpongeEventFactory.createServerSideConnectionEventHandshake(cause, connection);
                SpongeCommon.post(event);
                this.impl$handshakeState = ServerLoginPacketListenerImplMixin_Vanilla.HANDSHAKE_SYNC_PLUGIN_DATA;
            });
        } else if (this.impl$handshakeState == ServerLoginPacketListenerImplMixin_Vanilla.HANDSHAKE_SYNC_PLUGIN_DATA) {
            final TransactionStore store = ConnectionUtil.getTransactionStore(connection);
            if (store.isEmpty()) {
                this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
            }
        }
    }
}
Also used : ServerSideConnection(org.spongepowered.api.network.ServerSideConnection) ServerLoginPacketListener(net.minecraft.network.protocol.login.ServerLoginPacketListener) ServerLoginPacketListenerImpl(net.minecraft.server.network.ServerLoginPacketListenerImpl) ServerSideConnectionEvent(org.spongepowered.api.event.network.ServerSideConnectionEvent) TransactionStore(org.spongepowered.common.network.channel.TransactionStore) ServerboundCustomQueryPacket(net.minecraft.network.protocol.login.ServerboundCustomQueryPacket) Inject(org.spongepowered.asm.mixin.injection.Inject) SpongeEventFactory(org.spongepowered.api.event.SpongeEventFactory) EngineConnection(org.spongepowered.api.network.EngineConnection) Sponge(org.spongepowered.api.Sponge) SpongeChannelManager(org.spongepowered.common.network.channel.SpongeChannelManager) SpongeCommon(org.spongepowered.common.SpongeCommon) Final(org.spongepowered.asm.mixin.Final) EventContext(org.spongepowered.api.event.EventContext) Cause(org.spongepowered.api.event.Cause) CallbackInfo(org.spongepowered.asm.mixin.injection.callback.CallbackInfo) MinecraftServer(net.minecraft.server.MinecraftServer) Mixin(org.spongepowered.asm.mixin.Mixin) ConnectionUtil(org.spongepowered.common.network.channel.ConnectionUtil) ServerboundHelloPacket(net.minecraft.network.protocol.login.ServerboundHelloPacket) Shadow(org.spongepowered.asm.mixin.Shadow) At(org.spongepowered.asm.mixin.injection.At) TransactionStore(org.spongepowered.common.network.channel.TransactionStore) Cause(org.spongepowered.api.event.Cause) SpongeChannelManager(org.spongepowered.common.network.channel.SpongeChannelManager) ServerSideConnection(org.spongepowered.api.network.ServerSideConnection) Inject(org.spongepowered.asm.mixin.injection.Inject)

Example 3 with ServerSideConnection

use of org.spongepowered.api.network.ServerSideConnection in project SpongeCommon by SpongePowered.

the class PlayerListMixin method impl$onInitPlayer_join.

@Inject(method = "placeNewPlayer", at = @At(value = "RETURN"))
private void impl$onInitPlayer_join(final Connection networkManager, final net.minecraft.server.level.ServerPlayer mcPlayer, final CallbackInfo ci) {
    final ServerPlayer player = (ServerPlayer) mcPlayer;
    final ServerSideConnection connection = player.connection();
    final Cause cause = Cause.of(EventContext.empty(), connection, player);
    final Audience audience = Audiences.onlinePlayers();
    final Component joinComponent = SpongeAdventure.asAdventure(((ServerPlayerBridge) mcPlayer).bridge$getConnectionMessageToSend());
    final ServerSideConnectionEvent.Join event = SpongeEventFactory.createServerSideConnectionEventJoin(cause, audience, Optional.of(audience), joinComponent, joinComponent, connection, player, false);
    SpongeCommon.post(event);
    if (!event.isMessageCancelled()) {
        event.audience().ifPresent(audience1 -> audience1.sendMessage(Identity.nil(), event.message()));
    }
    ((ServerPlayerBridge) mcPlayer).bridge$setConnectionMessageToSend(null);
    final PhaseContext<?> context = PhaseTracker.SERVER.getPhaseContext();
    PhaseTracker.SERVER.pushCause(event);
    final TransactionalCaptureSupplier transactor = context.getTransactor();
    transactor.logPlayerInventoryChange(mcPlayer, PlayerInventoryTransaction.EventCreator.STANDARD);
    try (EffectTransactor ignored = BroadcastInventoryChangesEffect.transact(transactor)) {
        // in case plugins modified it
        mcPlayer.inventoryMenu.broadcastChanges();
    }
}
Also used : TransactionalCaptureSupplier(org.spongepowered.common.event.tracking.context.transaction.TransactionalCaptureSupplier) Audience(net.kyori.adventure.audience.Audience) ServerPlayer(org.spongepowered.api.entity.living.player.server.ServerPlayer) Cause(org.spongepowered.api.event.Cause) ServerSideConnection(org.spongepowered.api.network.ServerSideConnection) ServerSideConnectionEvent(org.spongepowered.api.event.network.ServerSideConnectionEvent) EffectTransactor(org.spongepowered.common.event.tracking.context.transaction.EffectTransactor) TranslatableComponent(net.minecraft.network.chat.TranslatableComponent) TextComponent(net.minecraft.network.chat.TextComponent) MutableComponent(net.minecraft.network.chat.MutableComponent) Component(net.kyori.adventure.text.Component) ServerPlayerBridge(org.spongepowered.common.bridge.server.level.ServerPlayerBridge) Inject(org.spongepowered.asm.mixin.injection.Inject)

Example 4 with ServerSideConnection

use of org.spongepowered.api.network.ServerSideConnection in project SpongeCommon by SpongePowered.

the class PlayerListMixin method impl$onInitPlayer_getWorld.

@Redirect(method = "placeNewPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getLevel(Lnet/minecraft/resources/ResourceKey;)Lnet/minecraft/server/level/ServerLevel;"))
private net.minecraft.server.level.ServerLevel impl$onInitPlayer_getWorld(final MinecraftServer minecraftServer, final ResourceKey<Level> dimension, final Connection networkManager, final net.minecraft.server.level.ServerPlayer mcPlayer) {
    @Nullable final net.minecraft.network.chat.Component kickReason = ((ConnectionBridge) networkManager).bridge$getKickReason();
    final Component disconnectMessage;
    if (kickReason != null) {
        disconnectMessage = SpongeAdventure.asAdventure(kickReason);
    } else {
        disconnectMessage = Component.text("You are not allowed to log in to this server.");
    }
    net.minecraft.server.level.ServerLevel mcWorld = minecraftServer.getLevel(dimension);
    if (mcWorld == null) {
        SpongeCommon.logger().warn("The player '{}' was located in a world that isn't loaded or doesn't exist. This is not safe so " + "the player will be moved to the spawn of the default world.", mcPlayer.getGameProfile().getName());
        mcWorld = minecraftServer.overworld();
        final BlockPos spawnPoint = mcWorld.getSharedSpawnPos();
        mcPlayer.setPos(spawnPoint.getX() + 0.5, spawnPoint.getY() + 0.5, spawnPoint.getZ() + 0.5);
    }
    mcPlayer.setLevel(mcWorld);
    final ServerPlayer player = (ServerPlayer) mcPlayer;
    final ServerLocation location = player.serverLocation();
    final Vector3d rotation = player.rotation();
    // player.connection() cannot be used here, because it's still be null at this point
    final ServerSideConnection connection = (ServerSideConnection) networkManager.getPacketListener();
    // The user is not yet in the player list, so we need to make special provision.
    final User user = SpongeUserView.createLoginEventUser(player);
    final Cause cause = Cause.of(EventContext.empty(), connection, user);
    final ServerSideConnectionEvent.Login event = SpongeEventFactory.createServerSideConnectionEventLogin(cause, disconnectMessage, disconnectMessage, location, location, rotation, rotation, connection, user);
    if (kickReason != null) {
        event.setCancelled(true);
    }
    if (SpongeCommon.post(event)) {
        this.impl$disconnectClient(networkManager, event.message(), player.profile());
        return null;
    }
    final ServerLocation toLocation = event.toLocation();
    final Vector3d toRotation = event.toRotation();
    mcPlayer.absMoveTo(toLocation.x(), toLocation.y(), toLocation.z(), (float) toRotation.y(), (float) toRotation.x());
    return (net.minecraft.server.level.ServerLevel) toLocation.world();
}
Also used : ServerLevel(net.minecraft.server.level.ServerLevel) User(org.spongepowered.api.entity.living.player.User) ServerLocation(org.spongepowered.api.world.server.ServerLocation) ServerSideConnection(org.spongepowered.api.network.ServerSideConnection) ServerSideConnectionEvent(org.spongepowered.api.event.network.ServerSideConnectionEvent) ServerLevel(net.minecraft.server.level.ServerLevel) Vector3d(org.spongepowered.math.vector.Vector3d) ConnectionBridge(org.spongepowered.common.bridge.network.ConnectionBridge) ServerPlayer(org.spongepowered.api.entity.living.player.server.ServerPlayer) Cause(org.spongepowered.api.event.Cause) BlockPos(net.minecraft.core.BlockPos) TranslatableComponent(net.minecraft.network.chat.TranslatableComponent) TextComponent(net.minecraft.network.chat.TextComponent) MutableComponent(net.minecraft.network.chat.MutableComponent) Component(net.kyori.adventure.text.Component) Nullable(javax.annotation.Nullable) Redirect(org.spongepowered.asm.mixin.injection.Redirect)

Example 5 with ServerSideConnection

use of org.spongepowered.api.network.ServerSideConnection in project SpongeCommon by SpongePowered.

the class ChannelTest method onConnectionJoin.

@Listener
public void onConnectionJoin(final ServerSideConnectionEvent.Join event) {
    this.plugin.logger().info("Player \"" + event.player().name() + "\" joined.");
    final ServerSideConnection connection = event.connection();
    final PingPacket pingPacket1 = new PingPacket(789);
    this.channel.sendTo(connection, pingPacket1).thenAccept(response1 -> this.logReceived(this.channel, response1, connection)).exceptionally(cause -> {
        this.plugin.logger().error("Failed to get a response to {}", pingPacket1, cause);
        return null;
    });
    this.basicChannel.play().sendTo(connection, new PrintTextPacket("You successfully joined the server.")).exceptionally(cause -> {
        this.plugin.logger().error(cause);
        return null;
    });
}
Also used : Channel(org.spongepowered.api.network.channel.Channel) BasicPacketChannel(org.spongepowered.api.network.channel.packet.basic.BasicPacketChannel) Plugin(org.spongepowered.plugin.builtin.jvm.Plugin) ServerSideConnection(org.spongepowered.api.network.ServerSideConnection) ServerSideConnectionEvent(org.spongepowered.api.event.network.ServerSideConnectionEvent) Inject(com.google.inject.Inject) EngineConnection(org.spongepowered.api.network.EngineConnection) NoResponseException(org.spongepowered.api.network.channel.NoResponseException) EngineConnectionSide(org.spongepowered.api.network.EngineConnectionSide) CompletionException(java.util.concurrent.CompletionException) RawDataChannel(org.spongepowered.api.network.channel.raw.RawDataChannel) PluginContainer(org.spongepowered.plugin.PluginContainer) RegisterChannelEvent(org.spongepowered.api.event.lifecycle.RegisterChannelEvent) ResourceKey(org.spongepowered.api.ResourceKey) PacketChannel(org.spongepowered.api.network.channel.packet.PacketChannel) Listener(org.spongepowered.api.event.Listener) ServerSideConnection(org.spongepowered.api.network.ServerSideConnection) Listener(org.spongepowered.api.event.Listener)

Aggregations

ServerSideConnectionEvent (org.spongepowered.api.event.network.ServerSideConnectionEvent)6 ServerSideConnection (org.spongepowered.api.network.ServerSideConnection)6 Cause (org.spongepowered.api.event.Cause)4 CompletionException (java.util.concurrent.CompletionException)3 Component (net.kyori.adventure.text.Component)3 TextComponent (net.minecraft.network.chat.TextComponent)3 EngineConnection (org.spongepowered.api.network.EngineConnection)3 Inject (org.spongepowered.asm.mixin.injection.Inject)3 Inject (com.google.inject.Inject)2 MutableComponent (net.minecraft.network.chat.MutableComponent)2 TranslatableComponent (net.minecraft.network.chat.TranslatableComponent)2 MinecraftServer (net.minecraft.server.MinecraftServer)2 ServerLoginPacketListenerImpl (net.minecraft.server.network.ServerLoginPacketListenerImpl)2 ResourceKey (org.spongepowered.api.ResourceKey)2 Sponge (org.spongepowered.api.Sponge)2 ServerPlayer (org.spongepowered.api.entity.living.player.server.ServerPlayer)2 EventContext (org.spongepowered.api.event.EventContext)2 Listener (org.spongepowered.api.event.Listener)2 SpongeEventFactory (org.spongepowered.api.event.SpongeEventFactory)2 RegisterChannelEvent (org.spongepowered.api.event.lifecycle.RegisterChannelEvent)2