Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Event for Handling Server Connection Failures #3638

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package net.md_5.bungee.api.event;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import net.md_5.bungee.api.ServerConnectRequest;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.plugin.Event;

/**
* This event is called when a connection to a server fails (e.g. the server is down).
* Only called when the server cannot be connected to, and is not called when kicked from a server (e.g. the server is full).
* Cancelling this event will cancel the transfer to the fallback lobby and prevent the default error message from being shown.
* <p>
* If you are using {@link ProxiedPlayer#connect}, this event will be called after the callback is called.
* So, you can't cancel the callback by cancelling this event.
*/
@Data
@ToString(callSuper = false)
@EqualsAndHashCode(callSuper = false)
public class ServerConnectFailEvent extends Event
{

/**
* Player whom the server is for.
*/
private final ProxiedPlayer player;
/**
* The server itself.
*/
private final Server server;
/**
* Request used to connect to given server.
*/
private final ServerConnectRequest request;
/**
* Cancelled state.
*/
private boolean cancelled;
}
26 changes: 16 additions & 10 deletions proxy/src/main/java/net/md_5/bungee/UserConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PermissionCheckEvent;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.event.ServerConnectFailEvent;
import net.md_5.bungee.api.score.Scoreboard;
import net.md_5.bungee.chat.ComponentSerializer;
import net.md_5.bungee.connection.InitialHandler;
Expand Down Expand Up @@ -374,17 +375,22 @@ public void operationComplete(ChannelFuture future) throws Exception
future.channel().close();
pendingConnects.remove( target );

ServerInfo def = updateAndGetNextServer( target );
if ( request.isRetry() && def != null && ( getServer() == null || def != getServer().getInfo() ) )
ServerConnection server = getServer();
ServerConnectFailEvent event = new ServerConnectFailEvent( UserConnection.this, server, request );
if ( !bungee.getPluginManager().callEvent( event ).isCancelled() )
Copy link
Member

@md-5 md-5 Apr 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you cancel this doesn't the player just get stuck in limbo?

Copy link
Author

@Kamesuta Kamesuta Apr 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, when your plugin cancels the event without disconnect or sendMessage,

  • If a player tries to log in, "Joining World..." will be displayed and stuck until timeout.
  • If the player tries to move with /server, etc., the server move will be canceled and nothing will happen.

I think this is the correct behavior, since the point of canceling this event is to handle it on the plugin side.

Your plugin can for example do the following

  • Start the server asynchronously while the player is connected and stuck, then connect the player after the server starts. You can kick if it fails to start server.

Do you have any ideas for a more appropriate behavior for cancellations?
I will be glad to implement it if you request it!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me think about it. I think this is a hard one because already have callback and connect events

{
sendMessage( bungee.getTranslation( "fallback_lobby" ) );
connect( def, null, true, ServerConnectEvent.Reason.LOBBY_FALLBACK );
} else if ( dimensionChange )
{
disconnect( bungee.getTranslation( "fallback_kick", connectionFailMessage( future.cause() ) ) );
} else
{
sendMessage( bungee.getTranslation( "fallback_kick", connectionFailMessage( future.cause() ) ) );
ServerInfo def = updateAndGetNextServer( target );
if ( request.isRetry() && def != null && ( server == null || def != server.getInfo() ) )
{
sendMessage( bungee.getTranslation( "fallback_lobby" ) );
connect( def, null, true, ServerConnectEvent.Reason.LOBBY_FALLBACK );
} else if ( dimensionChange )
{
disconnect( bungee.getTranslation( "fallback_kick", connectionFailMessage( future.cause() ) ) );
} else
{
sendMessage( bungee.getTranslation( "fallback_kick", connectionFailMessage( future.cause() ) ) );
}
}
}
}
Expand Down