Merge branch 'dev/3.0.0' into netease/dev
Some checks failed
Java CI with Gradle / build (push) Failing after 6m42s
Some checks failed
Java CI with Gradle / build (push) Failing after 6m42s
# Conflicts: # api/src/main/java/com/velocitypowered/api/proxy/config/ProxyConfig.java # proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java
This commit is contained in:
@@ -61,6 +61,7 @@ tasks {
|
||||
o.encoding = "UTF-8"
|
||||
o.source = "17"
|
||||
|
||||
o.use()
|
||||
o.links(
|
||||
"https://www.slf4j.org/apidocs/",
|
||||
"https://guava.dev/releases/${libs.guava.get().version}/api/docs/",
|
||||
|
@@ -7,8 +7,10 @@
|
||||
|
||||
package com.velocitypowered.api.command;
|
||||
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@@ -116,6 +118,27 @@ public interface CommandManager {
|
||||
*/
|
||||
CompletableFuture<Boolean> executeImmediatelyAsync(CommandSource source, String cmdLine);
|
||||
|
||||
/**
|
||||
* Asynchronously collects suggestions to fill in the given command {@code cmdLine}.
|
||||
* Returns only the raw completion suggestions without tooltips.
|
||||
*
|
||||
* @param source the source to execute the command for
|
||||
* @param cmdLine the partially completed command
|
||||
* @return a {@link CompletableFuture} eventually completed with a {@link List}, possibly empty
|
||||
*/
|
||||
CompletableFuture<List<String>> offerSuggestions(CommandSource source, String cmdLine);
|
||||
|
||||
/**
|
||||
* Asynchronously collects suggestions to fill in the given command {@code cmdLine}.
|
||||
* Returns the brigadier {@link Suggestions} with tooltips for each result.
|
||||
*
|
||||
* @param source the source to execute the command for
|
||||
* @param cmdLine the partially completed command
|
||||
* @return a {@link CompletableFuture} eventually completed with {@link Suggestions}, possibly
|
||||
* empty
|
||||
*/
|
||||
CompletableFuture<Suggestions> offerBrigadierSuggestions(CommandSource source, String cmdLine);
|
||||
|
||||
/**
|
||||
* Returns an immutable collection of the case-insensitive aliases registered
|
||||
* on this manager.
|
||||
|
@@ -27,7 +27,7 @@ public interface CommandSource extends Audience, PermissionSubject {
|
||||
* for more information on the format.
|
||||
**/
|
||||
default void sendRichMessage(final @NotNull String message) {
|
||||
this.sendMessage(MiniMessage.miniMessage().deserialize(message));
|
||||
this.sendMessage(MiniMessage.miniMessage().deserialize(message, this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +43,7 @@ public interface CommandSource extends Audience, PermissionSubject {
|
||||
final @NotNull String message,
|
||||
final @NotNull TagResolver @NotNull... resolvers
|
||||
) {
|
||||
this.sendMessage(MiniMessage.miniMessage().deserialize(message, resolvers));
|
||||
this.sendMessage(MiniMessage.miniMessage().deserialize(message, this, resolvers));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,6 @@ package com.velocitypowered.api.event.command;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.mojang.brigadier.tree.RootCommandNode;
|
||||
import com.velocitypowered.api.event.annotation.AwaitingEvent;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
@@ -21,7 +20,6 @@ import com.velocitypowered.api.proxy.Player;
|
||||
* client.
|
||||
*/
|
||||
@AwaitingEvent
|
||||
@Beta
|
||||
public class PlayerAvailableCommandsEvent {
|
||||
|
||||
private final Player player;
|
||||
|
@@ -7,7 +7,6 @@
|
||||
|
||||
package com.velocitypowered.api.event.player;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
@@ -18,7 +17,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
* available in {@link Player#getCurrentServer()}. Velocity will not wait on this event to finish
|
||||
* firing.
|
||||
*/
|
||||
@Beta
|
||||
public class ServerPostConnectEvent {
|
||||
private final Player player;
|
||||
private final RegisteredServer previousServer;
|
||||
|
@@ -7,7 +7,6 @@
|
||||
|
||||
package com.velocitypowered.api.event.proxy.server;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
@@ -23,7 +22,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @param registeredServer A {@link RegisteredServer} that has been registered.
|
||||
* @since 3.3.0
|
||||
*/
|
||||
@Beta
|
||||
public record ServerRegisteredEvent(@NotNull RegisteredServer registeredServer) {
|
||||
public ServerRegisteredEvent {
|
||||
Preconditions.checkNotNull(registeredServer, "registeredServer");
|
||||
|
@@ -7,7 +7,6 @@
|
||||
|
||||
package com.velocitypowered.api.event.proxy.server;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
@@ -23,7 +22,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @param unregisteredServer A {@link RegisteredServer} that has been unregistered.
|
||||
* @since 3.3.0
|
||||
*/
|
||||
@Beta
|
||||
public record ServerUnregisteredEvent(@NotNull RegisteredServer unregisteredServer) {
|
||||
public ServerUnregisteredEvent {
|
||||
Preconditions.checkNotNull(unregisteredServer, "unregisteredServer");
|
||||
|
@@ -89,7 +89,10 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
|
||||
MINECRAFT_1_20_5(766, "1.20.5", "1.20.6"),
|
||||
MINECRAFT_1_21(767, "1.21", "1.21.1"),
|
||||
MINECRAFT_1_21_2(768, "1.21.2", "1.21.3"),
|
||||
MINECRAFT_1_21_4(769, "1.21.4");
|
||||
MINECRAFT_1_21_4(769, "1.21.4"),
|
||||
MINECRAFT_1_21_5(770, "1.21.5"),
|
||||
MINECRAFT_1_21_6(771, "1.21.6"),
|
||||
MINECRAFT_1_21_7(772, "1.21.7", "1.21.8");
|
||||
|
||||
private static final int SNAPSHOT_BIT = 30;
|
||||
|
||||
|
@@ -41,6 +41,13 @@ public interface ProxyServer extends Audience {
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* Returns whether the proxy is currently shutting down.
|
||||
*
|
||||
* @return {@code true} if the proxy is shutting down, {@code false} otherwise
|
||||
*/
|
||||
boolean isShuttingDown();
|
||||
|
||||
/**
|
||||
* Closes all listening endpoints for this server.
|
||||
* This includes the main minecraft listener and query channel.
|
||||
|
@@ -149,6 +149,61 @@ public interface ProxyConfig {
|
||||
*/
|
||||
int getReadTimeout();
|
||||
|
||||
/**
|
||||
* Get the rate limit for how fast a player can execute commands.
|
||||
*
|
||||
* @return the command rate limit (in milliseconds)
|
||||
*/
|
||||
int getCommandRatelimit();
|
||||
|
||||
/**
|
||||
* Get whether we should forward commands to the backend if the player is rate limited.
|
||||
*
|
||||
* @return whether to forward commands if rate limited
|
||||
*/
|
||||
boolean isForwardCommandsIfRateLimited();
|
||||
|
||||
/**
|
||||
* Get the kick limit for commands that are rate limited.
|
||||
* If this limit is 0 or less, the player will be not be kicked.
|
||||
*
|
||||
* @return the rate limited command rate limit
|
||||
*/
|
||||
int getKickAfterRateLimitedCommands();
|
||||
|
||||
/**
|
||||
* Get whether the proxy should kick players who are command rate limited.
|
||||
*
|
||||
* @return whether to kick players who are rate limited
|
||||
*/
|
||||
default boolean isKickOnCommandRateLimit() {
|
||||
return getKickAfterRateLimitedCommands() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rate limit for how fast a player can tab complete.
|
||||
*
|
||||
* @return the tab complete rate limit (in milliseconds)
|
||||
*/
|
||||
int getTabCompleteRatelimit();
|
||||
|
||||
/**
|
||||
* Get the kick limit for tab completes that are rate limited.
|
||||
* If this limit is 0 or less, the player will be not be kicked.
|
||||
*
|
||||
* @return the rate limited command rate limit
|
||||
*/
|
||||
int getKickAfterRateLimitedTabCompletes();
|
||||
|
||||
/**
|
||||
* Get whether the proxy should kick players who are tab complete rate limited.
|
||||
*
|
||||
* @return whether to kick players who are rate limited
|
||||
*/
|
||||
default boolean isKickOnTabCompleteRateLimit() {
|
||||
return getKickAfterRateLimitedTabCompletes() > 0;
|
||||
}
|
||||
|
||||
String getNeteaseAuthUrl();
|
||||
|
||||
String getNeteaseGameId();
|
||||
|
@@ -11,7 +11,6 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
@@ -21,8 +20,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*/
|
||||
public final class MinecraftChannelIdentifier implements ChannelIdentifier {
|
||||
|
||||
private static final Pattern VALID_IDENTIFIER_REGEX = Pattern.compile("[a-z0-9/\\-_]*");
|
||||
|
||||
private final String namespace;
|
||||
private final String name;
|
||||
|
||||
@@ -39,7 +36,7 @@ public final class MinecraftChannelIdentifier implements ChannelIdentifier {
|
||||
* @return a new channel identifier
|
||||
*/
|
||||
public static MinecraftChannelIdentifier forDefaultNamespace(String name) {
|
||||
return new MinecraftChannelIdentifier("minecraft", name);
|
||||
return new MinecraftChannelIdentifier(Key.MINECRAFT_NAMESPACE, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,14 +49,10 @@ public final class MinecraftChannelIdentifier implements ChannelIdentifier {
|
||||
public static MinecraftChannelIdentifier create(String namespace, String name) {
|
||||
checkArgument(!Strings.isNullOrEmpty(namespace), "namespace is null or empty");
|
||||
checkArgument(name != null, "namespace is null or empty");
|
||||
checkArgument(VALID_IDENTIFIER_REGEX.matcher(namespace).matches(),
|
||||
"namespace is not valid, must match: %s got %s",
|
||||
VALID_IDENTIFIER_REGEX.toString(),
|
||||
namespace);
|
||||
checkArgument(VALID_IDENTIFIER_REGEX.matcher(name).matches(),
|
||||
"name is not valid, must match: %s got %s",
|
||||
VALID_IDENTIFIER_REGEX.toString(),
|
||||
name);
|
||||
checkArgument(Key.parseableNamespace(namespace),
|
||||
"namespace is not valid, must match: [a-z0-9_.-] got %s", namespace);
|
||||
checkArgument(Key.parseableValue(name),
|
||||
"name is not valid, must match: [a-z0-9/._-] got %s", name);
|
||||
return new MinecraftChannelIdentifier(namespace, name);
|
||||
}
|
||||
|
||||
@@ -72,10 +65,9 @@ public final class MinecraftChannelIdentifier implements ChannelIdentifier {
|
||||
public static MinecraftChannelIdentifier from(String identifier) {
|
||||
int colonPos = identifier.indexOf(':');
|
||||
if (colonPos == -1) {
|
||||
throw new IllegalArgumentException("Identifier does not contain a colon.");
|
||||
}
|
||||
if (colonPos + 1 == identifier.length()) {
|
||||
throw new IllegalArgumentException("Identifier is empty.");
|
||||
return create(Key.MINECRAFT_NAMESPACE, identifier);
|
||||
} else if (colonPos == 0) {
|
||||
return create(Key.MINECRAFT_NAMESPACE, identifier.substring(1));
|
||||
}
|
||||
String namespace = identifier.substring(0, colonPos);
|
||||
String name = identifier.substring(colonPos + 1);
|
||||
|
@@ -40,6 +40,7 @@ public interface TabList {
|
||||
* Adds a {@link TabListEntry} to the {@link Player}'s tab list.
|
||||
*
|
||||
* @param entry to add to the tab list
|
||||
* @throws IllegalArgumentException on versions below 1.19.3, if an entry with the same UUID already exists
|
||||
*/
|
||||
void addEntry(TabListEntry entry);
|
||||
|
||||
@@ -47,6 +48,7 @@ public interface TabList {
|
||||
* Adds a {@link Iterable} of {@link TabListEntry}'s to the {@link Player}'s tab list.
|
||||
*
|
||||
* @param entries to add to the tab list
|
||||
* @throws IllegalArgumentException on versions below 1.19.3, if an entry with the same UUID already exists
|
||||
*/
|
||||
default void addEntries(Iterable<TabListEntry> entries) {
|
||||
for (TabListEntry entry : entries) {
|
||||
@@ -58,6 +60,7 @@ public interface TabList {
|
||||
* Adds an array of {@link TabListEntry}'s to the {@link Player}'s tab list.
|
||||
*
|
||||
* @param entries to add to the tab list
|
||||
* @throws IllegalArgumentException on versions below 1.19.3, if an entry with the same UUID already exists
|
||||
*/
|
||||
default void addEntries(TabListEntry... entries) {
|
||||
for (TabListEntry entry : entries) {
|
||||
@@ -187,6 +190,26 @@ public interface TabList {
|
||||
* @deprecated Internal usage. Use {@link TabListEntry.Builder} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
||||
int gameMode, @Nullable ChatSession chatSession, boolean listed, int listOrder) {
|
||||
return buildEntry(profile, displayName, latency, gameMode, chatSession, listed, listOrder, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an entry in a {@link Player}'s tab list.
|
||||
*
|
||||
* @param profile the profile
|
||||
* @param displayName the display name
|
||||
* @param latency the latency
|
||||
* @param gameMode the game mode
|
||||
* @param chatSession the chat session
|
||||
* @param listed the visible status of entry
|
||||
* @param listOrder the order/priority of entry in the tab list
|
||||
* @param showHat the visibility of this entry's hat layer
|
||||
* @return the entry
|
||||
* @deprecated Internal usage. Use {@link TabListEntry.Builder} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
||||
int gameMode, @Nullable ChatSession chatSession, boolean listed, int listOrder);
|
||||
int gameMode, @Nullable ChatSession chatSession, boolean listed, int listOrder, boolean showHat);
|
||||
}
|
||||
|
@@ -160,6 +160,27 @@ public interface TabListEntry extends KeyIdentifiable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this entry's hat layer is shown in the tab list.
|
||||
*
|
||||
* @return whether to show this entry's hat layer
|
||||
* @sinceMinecraft 1.21.4
|
||||
*/
|
||||
default boolean isShowHat() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to show this entry's hat layer in the tab list.
|
||||
*
|
||||
* @param showHat whether to show this entry's hat layer
|
||||
* @return {@code this}, for chaining
|
||||
* @sinceMinecraft 1.21.4
|
||||
*/
|
||||
default TabListEntry setShowHat(boolean showHat) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Builder} to create a {@link TabListEntry}.
|
||||
*
|
||||
@@ -183,6 +204,7 @@ public interface TabListEntry extends KeyIdentifiable {
|
||||
private int gameMode = 0;
|
||||
private boolean listed = true;
|
||||
private int listOrder = 0;
|
||||
private boolean showHat;
|
||||
|
||||
private @Nullable ChatSession chatSession;
|
||||
|
||||
@@ -268,7 +290,7 @@ public interface TabListEntry extends KeyIdentifiable {
|
||||
* Sets whether this entry should be visible.
|
||||
*
|
||||
* @param listed to set
|
||||
* @return ${code this}, for chaining
|
||||
* @return {@code this}, for chaining
|
||||
* @see TabListEntry#isListed()
|
||||
*/
|
||||
public Builder listed(boolean listed) {
|
||||
@@ -280,7 +302,7 @@ public interface TabListEntry extends KeyIdentifiable {
|
||||
* Sets the order/priority of this entry in the tab list.
|
||||
*
|
||||
* @param order to set
|
||||
* @return ${code this}, for chaining
|
||||
* @return {@code this}, for chaining
|
||||
* @sinceMinecraft 1.21.2
|
||||
* @see TabListEntry#getListOrder()
|
||||
*/
|
||||
@@ -289,6 +311,18 @@ public interface TabListEntry extends KeyIdentifiable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this entry's hat layer should be shown in the tab list.
|
||||
*
|
||||
* @param showHat to set
|
||||
* @return {@code this}, for chaining
|
||||
* @see TabListEntry#isShowHat()
|
||||
*/
|
||||
public Builder showHat(boolean showHat) {
|
||||
this.showHat = showHat;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the {@link TabListEntry} specified by {@code this} {@link Builder}.
|
||||
*
|
||||
@@ -301,7 +335,7 @@ public interface TabListEntry extends KeyIdentifiable {
|
||||
if (profile == null) {
|
||||
throw new IllegalStateException("The GameProfile must be set when building a TabListEntry");
|
||||
}
|
||||
return tabList.buildEntry(profile, displayName, latency, gameMode, chatSession, listed, listOrder);
|
||||
return tabList.buildEntry(profile, displayName, latency, gameMode, chatSession, listed, listOrder, showHat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.kyori.adventure.builder.AbstractBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Contains the parameters used to ping a {@link RegisteredServer}.
|
||||
@@ -30,10 +31,12 @@ public final class PingOptions {
|
||||
public static final PingOptions DEFAULT = PingOptions.builder().build();
|
||||
private final ProtocolVersion protocolVersion;
|
||||
private final long timeout;
|
||||
private final String virtualHost;
|
||||
|
||||
private PingOptions(final Builder builder) {
|
||||
this.protocolVersion = builder.protocolVersion;
|
||||
this.timeout = builder.timeout;
|
||||
this.virtualHost = builder.virtualHost;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,6 +57,16 @@ public final class PingOptions {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* The virtual host to pass to the server for the ping.
|
||||
*
|
||||
* @return the virtual hostname to pass to the server for the ping
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public @Nullable String getVirtualHost() {
|
||||
return this.virtualHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new builder to assign values to a new PingOptions.
|
||||
*
|
||||
@@ -68,10 +81,9 @@ public final class PingOptions {
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(o instanceof PingOptions)) {
|
||||
if (!(o instanceof final PingOptions other)) {
|
||||
return false;
|
||||
}
|
||||
final PingOptions other = (PingOptions) o;
|
||||
return Objects.equals(this.protocolVersion, other.protocolVersion)
|
||||
&& Objects.equals(this.timeout, other.timeout);
|
||||
}
|
||||
@@ -97,6 +109,7 @@ public final class PingOptions {
|
||||
public static final class Builder implements AbstractBuilder<PingOptions> {
|
||||
private ProtocolVersion protocolVersion = ProtocolVersion.UNKNOWN;
|
||||
private long timeout = 0;
|
||||
private String virtualHost = null;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
@@ -146,6 +159,18 @@ public final class PingOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the virtual host to pass to the server for the ping.
|
||||
*
|
||||
* @param virtualHost the virtual hostname to pass to the server for the ping
|
||||
* @return this builder
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public Builder virtualHost(final @Nullable String virtualHost) {
|
||||
this.virtualHost = virtualHost;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link PingOptions} with the values of this Builder.
|
||||
*
|
||||
|
@@ -14,6 +14,7 @@ import com.velocitypowered.api.util.Favicon;
|
||||
import com.velocitypowered.api.util.ModInfo;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -159,31 +160,79 @@ public final class ServerPing {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the modified {@code version} info in the response.
|
||||
*
|
||||
* @param version version info to set
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder version(Version version) {
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the modified {@code onlinePlayers} number in the response.
|
||||
*
|
||||
* @param onlinePlayers number for online players to set
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder onlinePlayers(int onlinePlayers) {
|
||||
this.onlinePlayers = onlinePlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the modified {@code maximumPlayers} number in the response.
|
||||
* <b>This will not modify the actual maximum players that can join the server.</b>
|
||||
*
|
||||
* @param maximumPlayers number for maximum players to set
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder maximumPlayers(int maximumPlayers) {
|
||||
this.maximumPlayers = maximumPlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the modified {@code players} array in the response.
|
||||
*
|
||||
* @param players array of SamplePlayers to add
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder samplePlayers(SamplePlayer... players) {
|
||||
this.samplePlayers.addAll(Arrays.asList(players));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the modified {@code players} collection in the response.
|
||||
*
|
||||
* @param players collection of SamplePlayers to add
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder samplePlayers(Collection<SamplePlayer> players) {
|
||||
this.samplePlayers.addAll(players);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the modified {@code modType} in the response.
|
||||
*
|
||||
* @param modType the mod type to set
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder modType(String modType) {
|
||||
this.modType = Preconditions.checkNotNull(modType, "modType");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the modified {@code mods} array in the response.
|
||||
*
|
||||
* @param mods array of mods to use
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder mods(ModInfo.Mod... mods) {
|
||||
this.mods.addAll(Arrays.asList(mods));
|
||||
return this;
|
||||
@@ -193,7 +242,7 @@ public final class ServerPing {
|
||||
* Uses the modified {@code mods} list in the response.
|
||||
*
|
||||
* @param mods the mods list to use
|
||||
* @return this build, for chaining
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder mods(ModInfo mods) {
|
||||
Preconditions.checkNotNull(mods, "mods");
|
||||
@@ -203,36 +252,74 @@ public final class ServerPing {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the current list of mods to use in the response.
|
||||
*
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder clearMods() {
|
||||
this.mods.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the current list of PlayerSamples to use in the response.
|
||||
*
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder clearSamplePlayers() {
|
||||
this.samplePlayers.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the server as mod incompatible in the response.
|
||||
*
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder notModCompatible() {
|
||||
this.nullOutModinfo = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables nulling Players in the response.
|
||||
* This will display the player count as {@code ???}.
|
||||
*
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder nullPlayers() {
|
||||
this.nullOutPlayers = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the {@code description} Component in the response.
|
||||
*
|
||||
* @param description Component to use as the description.
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder description(net.kyori.adventure.text.Component description) {
|
||||
this.description = Preconditions.checkNotNull(description, "description");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the {@code favicon} in the response.
|
||||
*
|
||||
* @param favicon Favicon instance to use.
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder favicon(Favicon favicon) {
|
||||
this.favicon = Preconditions.checkNotNull(favicon, "favicon");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the current favicon used in the response.
|
||||
*
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public Builder clearFavicon() {
|
||||
this.favicon = null;
|
||||
return this;
|
||||
@@ -429,6 +516,10 @@ public final class ServerPing {
|
||||
*/
|
||||
public static final class SamplePlayer {
|
||||
|
||||
public static final SamplePlayer ANONYMOUS = new SamplePlayer(
|
||||
"Anonymous Player",
|
||||
new UUID(0L, 0L)
|
||||
);
|
||||
private final String name;
|
||||
private final UUID id;
|
||||
|
||||
|
@@ -76,9 +76,17 @@ public final class ModInfo {
|
||||
private final String id;
|
||||
private final String version;
|
||||
|
||||
/**
|
||||
* Creates a new mod info.
|
||||
*
|
||||
* @param id the mod identifier
|
||||
* @param version the mod version
|
||||
*/
|
||||
public Mod(String id, String version) {
|
||||
this.id = Preconditions.checkNotNull(id, "id");
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
Preconditions.checkArgument(id.length() < 128, "mod id is too long");
|
||||
Preconditions.checkArgument(version.length() < 128, "mod version is too long");
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@@ -47,17 +47,25 @@ class MinecraftChannelIdentifierTest {
|
||||
create("velocity", "test/test2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromIdentifierDefaultNamespace() {
|
||||
assertEquals("minecraft", from("test").getNamespace());
|
||||
assertEquals("minecraft", from(":test").getNamespace());
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromIdentifierAllowsEmptyName() {
|
||||
from("minecraft:");
|
||||
from(":");
|
||||
from("");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromIdentifierThrowsOnBadValues() {
|
||||
assertAll(
|
||||
() -> assertThrows(IllegalArgumentException.class, () -> from("")),
|
||||
() -> assertThrows(IllegalArgumentException.class, () -> from(":")),
|
||||
() -> assertThrows(IllegalArgumentException.class, () -> from(":a")),
|
||||
() -> assertThrows(IllegalArgumentException.class, () -> from("a:")),
|
||||
() -> assertThrows(IllegalArgumentException.class, () -> from("hello:$$$$$$")),
|
||||
() -> assertThrows(IllegalArgumentException.class, () -> from("he/llo:wor/ld")),
|
||||
() -> assertThrows(IllegalArgumentException.class, () -> from("hello::"))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user