geforkt von Mirrors/Velocity
Another round of improvements to tab complete. Fix fallback servers.
Dieser Commit ist enthalten in:
Ursprung
12f5bdfc48
Commit
02a725035c
@ -57,7 +57,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
private final Set<String> knownChannels = new HashSet<>();
|
||||
private final Queue<PluginMessage> loginPluginMessages = new ArrayDeque<>();
|
||||
private final VelocityServer server;
|
||||
private @Nullable TabCompleteRequest outstandingTabComplete;
|
||||
private @Nullable TabCompleteRequest legacyCommandTabComplete;
|
||||
|
||||
public ClientPlaySessionHandler(VelocityServer server, ConnectedPlayer player) {
|
||||
this.player = player;
|
||||
@ -143,7 +143,63 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if this is a proxy command.
|
||||
if (player.getProtocolVersion().compareTo(MINECRAFT_1_13) >= 0) {
|
||||
return handleTabCompleteModern(packet);
|
||||
} else {
|
||||
return handleTabCompleteLegacy(packet);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleTabCompleteModern(TabCompleteRequest packet) {
|
||||
// In 1.13+, we need to do additional work for the richer suggestions available.
|
||||
String command = packet.getCommand().substring(1);
|
||||
int spacePos = command.indexOf(' ');
|
||||
if (spacePos == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String commandLabel = command.substring(0, spacePos);
|
||||
if (!server.getCommandManager().hasCommand(commandLabel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
List<String> suggestions = server.getCommandManager().offerSuggestions(player, command);
|
||||
if (suggestions.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Offer> offers = new ArrayList<>();
|
||||
int longestLength = 0;
|
||||
for (String suggestion : suggestions) {
|
||||
offers.add(new Offer(suggestion));
|
||||
if (suggestion.length() > longestLength) {
|
||||
longestLength = suggestion.length();
|
||||
}
|
||||
}
|
||||
|
||||
TabCompleteResponse resp = new TabCompleteResponse();
|
||||
resp.setTransactionId(packet.getTransactionId());
|
||||
|
||||
int startPos = packet.getCommand().lastIndexOf(' ') + 1;
|
||||
int length;
|
||||
if (startPos == 0) {
|
||||
startPos = packet.getCommand().length() + 1;
|
||||
length = longestLength;
|
||||
} else {
|
||||
length = packet.getCommand().substring(startPos).indexOf(' ') + 1;
|
||||
}
|
||||
|
||||
resp.setStart(startPos);
|
||||
resp.setLength(length);
|
||||
resp.getOffers().addAll(offers);
|
||||
|
||||
player.getMinecraftConnection().write(resp);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleTabCompleteLegacy(TabCompleteRequest packet) {
|
||||
// Let us check for a possible proxy command.
|
||||
String command = packet.getCommand().substring(1);
|
||||
int spacePos = command.indexOf(' ');
|
||||
if (spacePos >= 0) {
|
||||
@ -151,18 +207,11 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
if (server.getCommandManager().hasCommand(commandLabel)) {
|
||||
List<String> suggestions = server.getCommandManager().offerSuggestions(player, command);
|
||||
if (!suggestions.isEmpty()) {
|
||||
int longestLength = 0;
|
||||
List<Offer> offers = new ArrayList<>();
|
||||
for (String suggestion : suggestions) {
|
||||
offers.add(new Offer(suggestion, null));
|
||||
if (suggestion.length() > longestLength) {
|
||||
longestLength = suggestion.length();
|
||||
}
|
||||
offers.add(new Offer(suggestion));
|
||||
}
|
||||
TabCompleteResponse resp = new TabCompleteResponse();
|
||||
resp.setTransactionId(packet.getTransactionId());
|
||||
resp.setStart(command.lastIndexOf(' ') + 2);
|
||||
resp.setLength(longestLength);
|
||||
resp.getOffers().addAll(offers);
|
||||
|
||||
player.getMinecraftConnection().write(resp);
|
||||
@ -171,13 +220,10 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
boolean is113 = player.getProtocolVersion().compareTo(MINECRAFT_1_13) >= 0;
|
||||
if (!is113) {
|
||||
// Outstanding tab completes are recorded for use with 1.12 clients and below to provide
|
||||
// tab list completion support for command names. In 1.13, Brigadier handles everything for
|
||||
// us.
|
||||
outstandingTabComplete = packet;
|
||||
}
|
||||
// Outstanding tab completes are recorded for use with 1.12 clients and below to provide
|
||||
// tab list completion support for command names. In 1.13, Brigadier handles everything for
|
||||
// us.
|
||||
legacyCommandTabComplete = packet;
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -398,23 +444,20 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
* @param response the tab complete response from the backend
|
||||
*/
|
||||
public void handleTabCompleteResponse(TabCompleteResponse response) {
|
||||
if (outstandingTabComplete != null) {
|
||||
if (!outstandingTabComplete.isAssumeCommand()
|
||||
&& outstandingTabComplete.getCommand().startsWith("/")) {
|
||||
String command = outstandingTabComplete.getCommand().substring(1);
|
||||
try {
|
||||
List<String> offers = server.getCommandManager().offerSuggestions(player, command);
|
||||
for (String offer : offers) {
|
||||
response.getOffers().add(new Offer(offer, null));
|
||||
}
|
||||
response.getOffers().sort(null);
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to provide tab list completions for {} for command '{}'",
|
||||
player.getUsername(),
|
||||
command, e);
|
||||
if (legacyCommandTabComplete != null) {
|
||||
String command = legacyCommandTabComplete.getCommand().substring(1);
|
||||
try {
|
||||
List<String> offers = server.getCommandManager().offerSuggestions(player, command);
|
||||
for (String offer : offers) {
|
||||
response.getOffers().add(new Offer(offer, null));
|
||||
}
|
||||
outstandingTabComplete = null;
|
||||
response.getOffers().sort(null);
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to provide tab list completions for {} for command '{}'",
|
||||
player.getUsername(),
|
||||
command, e);
|
||||
}
|
||||
legacyCommandTabComplete = null;
|
||||
}
|
||||
|
||||
player.getMinecraftConnection().write(response);
|
||||
|
@ -357,13 +357,13 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
|
||||
private void handleConnectionException(RegisteredServer rs, @Nullable Component kickReason,
|
||||
Component friendlyReason) {
|
||||
// There can't be any connection in flight now.
|
||||
connectionInFlight = null;
|
||||
|
||||
if (connectedServer == null) {
|
||||
// The player isn't yet connected to a server.
|
||||
Optional<RegisteredServer> nextServer = getNextServerToTry();
|
||||
Optional<RegisteredServer> nextServer = getNextServerToTry(rs);
|
||||
if (nextServer.isPresent()) {
|
||||
// There can't be any connection in flight now.
|
||||
connectionInFlight = null;
|
||||
|
||||
createConnectionRequest(nextServer.get()).fireAndForget();
|
||||
} else {
|
||||
disconnect(friendlyReason);
|
||||
@ -372,7 +372,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
boolean kickedFromCurrent = connectedServer.getServer().equals(rs);
|
||||
ServerKickResult result;
|
||||
if (kickedFromCurrent) {
|
||||
Optional<RegisteredServer> next = getNextServerToTry();
|
||||
Optional<RegisteredServer> next = getNextServerToTry(rs);
|
||||
result = next.<ServerKickResult>map(RedirectPlayer::create)
|
||||
.orElseGet(() -> DisconnectPlayer.create(friendlyReason));
|
||||
} else {
|
||||
@ -392,6 +392,9 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
DisconnectPlayer res = (DisconnectPlayer) event.getResult();
|
||||
disconnect(res.getReason());
|
||||
} else if (event.getResult() instanceof RedirectPlayer) {
|
||||
// There can't be any connection in flight now.
|
||||
connectionInFlight = null;
|
||||
|
||||
RedirectPlayer res = (RedirectPlayer) event.getResult();
|
||||
createConnectionRequest(res.getServer())
|
||||
.connectWithIndication()
|
||||
@ -419,9 +422,22 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
/**
|
||||
* Finds another server to attempt to log into, if we were unexpectedly disconnected from the
|
||||
* server.
|
||||
*
|
||||
* @return the next server to try
|
||||
*/
|
||||
public Optional<RegisteredServer> getNextServerToTry() {
|
||||
return this.getNextServerToTry(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds another server to attempt to log into, if we were unexpectedly disconnected from the
|
||||
* server.
|
||||
*
|
||||
* @param current the "current" server that the player is on, useful as an override
|
||||
*
|
||||
* @return the next server to try
|
||||
*/
|
||||
private Optional<RegisteredServer> getNextServerToTry(@Nullable RegisteredServer current) {
|
||||
if (serversToTry == null) {
|
||||
String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString).orElse("");
|
||||
serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(virtualHostStr,
|
||||
@ -432,17 +448,24 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
serversToTry = server.getConfiguration().getAttemptConnectionOrder();
|
||||
}
|
||||
|
||||
for (; tryIndex < serversToTry.size(); tryIndex++) {
|
||||
String toTryName = serversToTry.get(tryIndex);
|
||||
if (connectedServer != null && toTryName.equals(connectedServer.getServerInfo().getName())) {
|
||||
for (int i = tryIndex; i < serversToTry.size(); i++) {
|
||||
String toTryName = serversToTry.get(i);
|
||||
if ((connectedServer != null && hasSameName(connectedServer.getServer(), toTryName))
|
||||
|| (connectionInFlight != null && hasSameName(connectionInFlight.getServer(), toTryName))
|
||||
|| (current != null && hasSameName(current, toTryName))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tryIndex = i;
|
||||
return server.getServer(toTryName);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static boolean hasSameName(RegisteredServer server, String name) {
|
||||
return server.getServerInfo().getName().equalsIgnoreCase(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player's new connected server and clears the in-flight connection.
|
||||
*
|
||||
|
@ -38,7 +38,7 @@ public class TabCompleteRequest implements MinecraftPacket {
|
||||
this.assumeCommand = assumeCommand;
|
||||
}
|
||||
|
||||
public boolean isHasPosition() {
|
||||
public boolean hasPosition() {
|
||||
return hasPosition;
|
||||
}
|
||||
|
||||
|
@ -112,6 +112,10 @@ public class TabCompleteResponse implements MinecraftPacket {
|
||||
@Nullable
|
||||
private final Component tooltip;
|
||||
|
||||
public Offer(String text) {
|
||||
this(text, null);
|
||||
}
|
||||
|
||||
public Offer(String text,
|
||||
@Nullable Component tooltip) {
|
||||
this.text = text;
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren