merge upstream

This commit is contained in:
Leymooo
2018-09-20 15:54:22 +03:00
80 changed files with 1001 additions and 728 deletions

View File

@@ -19,7 +19,8 @@ import javax.tools.StandardLocation;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.Objects;
import java.util.Set;
@SupportedAnnotationTypes({"com.velocitypowered.api.plugin.Plugin"})
public class PluginAnnotationProcessor extends AbstractProcessor {

View File

@@ -0,0 +1,105 @@
package com.velocitypowered.api.event.connection;
import com.google.common.base.Preconditions;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Arrays;
/**
* This event is fired when a plugin message is sent to the proxy, either from a client ({@link com.velocitypowered.api.proxy.Player})
* or a server ({@link com.velocitypowered.api.proxy.ServerConnection}).
*/
public class PluginMessageEvent implements ResultedEvent<PluginMessageEvent.ForwardResult> {
private final ChannelMessageSource source;
private final ChannelMessageSink target;
private final ChannelIdentifier identifier;
private final byte[] data;
private ForwardResult result;
public PluginMessageEvent(ChannelMessageSource source, ChannelMessageSink target, ChannelIdentifier identifier, byte[] data) {
this.source = Preconditions.checkNotNull(source, "source");
this.target = Preconditions.checkNotNull(target, "target");
this.identifier = Preconditions.checkNotNull(identifier, "identifier");
this.data = Preconditions.checkNotNull(data, "data");
this.result = ForwardResult.forward();
}
@Override
public ForwardResult getResult() {
return result;
}
@Override
public void setResult(@NonNull ForwardResult result) {
this.result = Preconditions.checkNotNull(result, "result");
}
public ChannelMessageSource getSource() {
return source;
}
public ChannelMessageSink getTarget() {
return target;
}
public ChannelIdentifier getIdentifier() {
return identifier;
}
public byte[] getData() {
return Arrays.copyOf(data, data.length);
}
public ByteArrayDataInput dataAsDataStream() {
return ByteStreams.newDataInput(data);
}
@Override
public String toString() {
return "PluginMessageEvent{" +
"source=" + source +
", target=" + target +
", identifier=" + identifier +
", data=" + Arrays.toString(data) +
", result=" + result +
'}';
}
/**
* A result determining whether or not to forward this message on.
*/
public static class ForwardResult implements ResultedEvent.Result {
private static final ForwardResult ALLOWED = new ForwardResult(true);
private static final ForwardResult DENIED = new ForwardResult(false);
private final boolean allowed;
private ForwardResult(boolean b) {
this.allowed = b;
}
@Override
public boolean isAllowed() {
return allowed;
}
@Override
public String toString() {
return allowed ? "forward to sink" : "handled message at proxy";
}
public static ForwardResult forward() {
return ALLOWED;
}
public static ForwardResult handled() {
return DENIED;
}
}
}

View File

@@ -0,0 +1,28 @@
package com.velocitypowered.api.event.connection;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.Player;
/**
* This event is fired once the player has been successfully authenticated and
* fully initialized and player will be connected to server after this event
*/
public class PostLoginEvent {
private final Player player;
public PostLoginEvent(Player player) {
this.player = Preconditions.checkNotNull(player, "player");
}
public Player getPlayer() {
return player;
}
@Override
public String toString() {
return "PostLoginEvent{"
+ "player=" + player
+ '}';
}
}

View File

@@ -3,12 +3,13 @@ package com.velocitypowered.api.event.connection;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.proxy.InboundConnection;
import net.kyori.text.Component;
import net.kyori.text.serializer.ComponentSerializers;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Optional;
/**
* This event is fired when a player has initiated a connection with the proxy but before the proxy authenticates the
* player with Mojang or before the player's proxy connection is fully established (for offline mode).
@@ -52,44 +53,59 @@ public class PreLoginEvent implements ResultedEvent<PreLoginEvent.PreLoginCompon
}
/**
* Represents an "allowed/allowed with online mode/denied" result with a reason allowed for denial.
* Represents an "allowed/allowed with forced online\offline mode/denied" result with a reason allowed for denial.
*/
public static class PreLoginComponentResult extends ResultedEvent.ComponentResult {
private static final PreLoginComponentResult ALLOWED = new PreLoginComponentResult((Component) null);
private static final PreLoginComponentResult FORCE_ONLINEMODE = new PreLoginComponentResult(true);
public static class PreLoginComponentResult implements ResultedEvent.Result {
private final boolean onlineMode;
private static final PreLoginComponentResult ALLOWED = new PreLoginComponentResult(Result.ALLOWED, null);
private static final PreLoginComponentResult FORCE_ONLINEMODE = new PreLoginComponentResult(Result.FORCE_ONLINE, null);
private static final PreLoginComponentResult FORCE_OFFLINEMODE = new PreLoginComponentResult(Result.FORCE_OFFLINE, null);
/**
* Allows online mode to be enabled for the player connection, if Velocity is running in offline mode.
* @param allowedOnlineMode if true, online mode will be used for the connection
*/
private PreLoginComponentResult(boolean allowedOnlineMode) {
super(true, null);
this.onlineMode = allowedOnlineMode;
private final Result result;
private final Optional<Component> reason;
private PreLoginComponentResult(Result result, @Nullable Component reason) {
this.result = result;
this.reason = Optional.ofNullable(reason);
}
private PreLoginComponentResult(@Nullable Component reason) {
super(reason == null, reason);
// Don't care about this
this.onlineMode = false;
@Override
public boolean isAllowed() {
return result != Result.DISALLOWED;
}
public Optional<Component> getReason() {
return reason;
}
public boolean isOnlineModeAllowed() {
return this.onlineMode;
return result == Result.FORCE_ONLINE;
}
public boolean isForceOfflineMode() {
return result == Result.FORCE_OFFLINE;
}
@Override
public String toString() {
if (isForceOfflineMode()) {
return "allowed with force offline mode";
}
if (isOnlineModeAllowed()) {
return "allowed with online mode";
}
return super.toString();
if (isAllowed()) {
return "allowed";
}
if (reason.isPresent()) {
return "denied: " + ComponentSerializers.PLAIN.serialize(reason.get());
}
return "denied";
}
/**
* Returns a result indicating the connection will be allowed through the proxy.
* Returns a result indicating the connection will be allowed through
* the proxy.
* @return the allowed result
*/
public static PreLoginComponentResult allowed() {
@@ -97,23 +113,41 @@ public class PreLoginEvent implements ResultedEvent<PreLoginEvent.PreLoginCompon
}
/**
* Returns a result indicating the connection will be allowed through the proxy, but the connection will be
* forced to use online mode provided that the proxy is in offline mode. This acts similarly to {@link #allowed()}
* on an online-mode proxy.
* Returns a result indicating the connection will be allowed through
* the proxy, but the connection will be forced to use online mode
* provided that the proxy is in offline mode. This acts similarly to
* {@link #allowed()} on an online-mode proxy.
* @return the result
*/
public static PreLoginComponentResult forceOnlineMode() {
return FORCE_ONLINEMODE;
}
/**
* Returns a result indicating the connection will be allowed through
* the proxy, but the connection will be forced to use offline mode even
* when proxy running in online mode
* @return the result
*/
public static PreLoginComponentResult forceOfflineMode() {
return FORCE_OFFLINEMODE;
}
/**
* Denies the login with the specified reason.
* @param reason the reason for disallowing the connection
* @return a new result
*/
public static PreLoginComponentResult denied(@NonNull Component reason) {
public static PreLoginComponentResult denied(Component reason) {
Preconditions.checkNotNull(reason, "reason");
return new PreLoginComponentResult(reason);
return new PreLoginComponentResult(Result.DISALLOWED, reason);
}
private enum Result {
ALLOWED,
FORCE_ONLINE,
FORCE_OFFLINE,
DISALLOWED
}
}
}

View File

@@ -1,10 +1,9 @@
package com.velocitypowered.api.event.player;
import com.velocitypowered.api.proxy.InboundConnection;
import org.checkerframework.checker.nullness.qual.Nullable;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.util.GameProfile;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* This event is fired after the {@link com.velocitypowered.api.event.connection.PreLoginEvent} in order to set up the

View File

@@ -3,7 +3,7 @@ package com.velocitypowered.api.event.player;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import net.kyori.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -13,12 +13,12 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEvent.ServerKickResult> {
private final Player player;
private final ServerInfo server;
private final RegisteredServer server;
private final Component originalReason;
private final boolean duringLogin;
private ServerKickResult result;
public KickedFromServerEvent(Player player, ServerInfo server, Component originalReason, boolean duringLogin, Component fancyReason) {
public KickedFromServerEvent(Player player, RegisteredServer server, Component originalReason, boolean duringLogin, Component fancyReason) {
this.player = Preconditions.checkNotNull(player, "player");
this.server = Preconditions.checkNotNull(server, "server");
this.originalReason = Preconditions.checkNotNull(originalReason, "originalReason");
@@ -40,7 +40,7 @@ public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEven
return player;
}
public ServerInfo getServer() {
public RegisteredServer getServer() {
return server;
}
@@ -91,9 +91,9 @@ public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEven
* when this result is used.
*/
public static class RedirectPlayer implements ServerKickResult {
private final ServerInfo server;
private final RegisteredServer server;
private RedirectPlayer(ServerInfo server) {
private RedirectPlayer(RegisteredServer server) {
this.server = Preconditions.checkNotNull(server, "server");
}
@@ -102,7 +102,7 @@ public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEven
return false;
}
public ServerInfo getServer() {
public RegisteredServer getServer() {
return server;
}
@@ -111,7 +111,7 @@ public class KickedFromServerEvent implements ResultedEvent<KickedFromServerEven
* @param server the server to send the player to
* @return the redirect result
*/
public static RedirectPlayer create(ServerInfo server) {
public static RedirectPlayer create(RegisteredServer server) {
return new RedirectPlayer(server);
}
}

View File

@@ -1,8 +1,8 @@
package com.velocitypowered.api.event.player;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.player.PlayerSettings;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.player.PlayerSettings;
public class PlayerSettingsChangedEvent {
private final Player player;

View File

@@ -2,7 +2,7 @@ package com.velocitypowered.api.event.player;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.proxy.server.RegisteredServer;
/**
* This event is fired once the player has successfully connected to the target server and the connection to the previous
@@ -10,9 +10,9 @@ import com.velocitypowered.api.proxy.server.ServerInfo;
*/
public class ServerConnectedEvent {
private final Player player;
private final ServerInfo server;
private final RegisteredServer server;
public ServerConnectedEvent(Player player, ServerInfo server) {
public ServerConnectedEvent(Player player, RegisteredServer server) {
this.player = Preconditions.checkNotNull(player, "player");
this.server = Preconditions.checkNotNull(server, "server");
}
@@ -21,7 +21,7 @@ public class ServerConnectedEvent {
return player;
}
public ServerInfo getServer() {
public RegisteredServer getServer() {
return server;
}

View File

@@ -3,7 +3,7 @@ package com.velocitypowered.api.event.player;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -14,11 +14,13 @@ import java.util.Optional;
*/
public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEvent.ServerResult> {
private final Player player;
private final RegisteredServer originalServer;
private ServerResult result;
public ServerPreConnectEvent(Player player, ServerResult result) {
public ServerPreConnectEvent(Player player, RegisteredServer originalServer) {
this.player = Preconditions.checkNotNull(player, "player");
this.result = Preconditions.checkNotNull(result, "result");
this.originalServer = Preconditions.checkNotNull(originalServer, "originalServer");
this.result = ServerResult.allowed(originalServer);
}
public Player getPlayer() {
@@ -35,10 +37,15 @@ public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEven
this.result = Preconditions.checkNotNull(result, "result");
}
public RegisteredServer getOriginalServer() {
return originalServer;
}
@Override
public String toString() {
return "ServerPreConnectEvent{" +
"player=" + player +
", originalServer=" + originalServer +
", result=" + result +
'}';
}
@@ -50,11 +57,11 @@ public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEven
private static final ServerResult DENIED = new ServerResult(false, null);
private final boolean allowed;
private final ServerInfo info;
private final RegisteredServer server;
private ServerResult(boolean allowed, @Nullable ServerInfo info) {
private ServerResult(boolean allowed, @Nullable RegisteredServer server) {
this.allowed = allowed;
this.info = info;
this.server = server;
}
@Override
@@ -62,8 +69,8 @@ public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEven
return allowed;
}
public Optional<ServerInfo> getInfo() {
return Optional.ofNullable(info);
public Optional<RegisteredServer> getServer() {
return Optional.ofNullable(server);
}
@Override
@@ -71,14 +78,14 @@ public class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEven
if (!allowed) {
return "denied";
}
return "allowed: connect to " + info.getName();
return "allowed: connect to " + server.getServerInfo().getName();
}
public static ServerResult denied() {
return DENIED;
}
public static ServerResult allowed(ServerInfo server) {
public static ServerResult allowed(RegisteredServer server) {
Preconditions.checkNotNull(server, "server");
return new ServerResult(true, server);
}

View File

@@ -1,7 +1,6 @@
package com.velocitypowered.api.plugin.meta;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.Optional;

View File

@@ -1,29 +1,28 @@
package com.velocitypowered.api.proxy;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import net.kyori.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
/**
* Provides a fluent interface to compose and send a connection request to another server behind the proxy. A connection
* request is created using {@link Player#createConnectionRequest(ServerInfo)}.
* request is created using {@link Player#createConnectionRequest(RegisteredServer)}.
*/
public interface ConnectionRequestBuilder {
/**
* Returns the server that this connection request represents.
* @return the server this request will connect to
*/
@NonNull ServerInfo getServer();
RegisteredServer getServer();
/**
* Initiates the connection to the remote server and emits a result on the {@link CompletableFuture} after the user
* has logged on. No messages will be communicated to the client: the user is responsible for all error handling.
* @return a {@link CompletableFuture} representing the status of this connection
*/
@NonNull CompletableFuture<Result> connect();
CompletableFuture<Result> connect();
/**
* Initiates the connection to the remote server without waiting for a result. Velocity will use generic error

View File

@@ -1,11 +1,11 @@
package com.velocitypowered.api.proxy;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.player.PlayerSettings;
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.util.GameProfile;
import com.velocitypowered.api.proxy.player.PlayerSettings;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.MessagePosition;
import java.util.List;
import net.kyori.text.Component;
@@ -65,10 +65,10 @@ public interface Player extends CommandSource, InboundConnection, ChannelMessage
/**
* Creates a new connection request so that the player can connect to another server.
* @param info the server to connect to
* @param server the server to connect to
* @return a new connection request
*/
ConnectionRequestBuilder createConnectionRequest(@NonNull ServerInfo info);
ConnectionRequestBuilder createConnectionRequest(@NonNull RegisteredServer server);
/**
* Gets a game profile properties of player

View File

@@ -1,12 +1,13 @@
package com.velocitypowered.api.proxy;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.plugin.PluginManager;
import com.velocitypowered.api.proxy.messages.ChannelRegistrar;
import com.velocitypowered.api.scheduler.Scheduler;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.velocitypowered.api.scheduler.Scheduler;
import java.net.InetSocketAddress;
import java.util.Collection;
@@ -45,23 +46,24 @@ public interface ProxyServer {
int getPlayerCount();
/**
* Retrieves a registered {@link ServerInfo} instance by its name. The search is case-insensitive.
* Retrieves a registered {@link RegisteredServer} instance by its name. The search is case-insensitive.
* @param name the name of the server
* @return the registered server, which may be empty
*/
Optional<ServerInfo> getServerInfo(String name);
Optional<RegisteredServer> getServer(String name);
/**
* Retrieves all {@link ServerInfo}s registered with this proxy.
* Retrieves all {@link RegisteredServer}s registered with this proxy.
* @return the servers registered with this proxy
*/
Collection<ServerInfo> getAllServers();
Collection<RegisteredServer> getAllServers();
/**
* Registers a server with this proxy. A server with this name should not already exist.
* @param server the server to register
* @return the newly registered server
*/
void registerServer(ServerInfo server);
RegisteredServer registerServer(ServerInfo server);
/**
* Unregisters this server from the proxy.

View File

@@ -2,6 +2,7 @@ package com.velocitypowered.api.proxy;
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
/**
@@ -12,6 +13,12 @@ public interface ServerConnection extends ChannelMessageSource, ChannelMessageSi
* Returns the server that this connection is connected to.
* @return the server this connection is connected to
*/
RegisteredServer getServer();
/**
* Returns the server info for this connection.
* @return the server info for this connection
*/
ServerInfo getServerInfo();
/**

View File

@@ -8,6 +8,7 @@ public interface ChannelMessageSink {
* Sends a plugin message to this target.
* @param identifier the channel identifier to send the message on
* @param data the data to send
* @return whether or not the message could be sent
*/
void sendPluginMessage(ChannelIdentifier identifier, byte[] data);
boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data);
}

View File

@@ -1,16 +1,14 @@
package com.velocitypowered.api.proxy.messages;
/**
* Represents an interface to register and unregister {@link MessageHandler} instances for handling plugin messages from
* the client or the server.
* Represents an interface to register and unregister {@link ChannelIdentifier}s for the proxy to listen on.
*/
public interface ChannelRegistrar {
/**
* Registers the specified message handler to listen for plugin messages on the specified channels.
* @param handler the handler to register
* Registers the specified message identifiers to listen on for the
* @param identifiers the channel identifiers to register
*/
void register(MessageHandler handler, ChannelIdentifier... identifiers);
void register(ChannelIdentifier... identifiers);
/**
* Unregisters the handler for the specified channel.

View File

@@ -1,15 +0,0 @@
package com.velocitypowered.api.proxy.messages;
/**
* Represents from "which side" of the proxy the plugin message came from.
*/
public enum ChannelSide {
/**
* The plugin message came from a server that a client was connected to.
*/
FROM_SERVER,
/**
* The plugin message came from the client.
*/
FROM_CLIENT
}

View File

@@ -1,28 +0,0 @@
package com.velocitypowered.api.proxy.messages;
/**
* Represents a handler for handling plugin messages.
*/
public interface MessageHandler {
/**
* Handles an incoming plugin message.
* @param source the source of the plugin message
* @param side from where the plugin message originated
* @param identifier the channel on which the message was sent
* @param data the data inside the plugin message
* @return a {@link ForwardStatus} indicating whether or not to forward this plugin message on
*/
ForwardStatus handle(ChannelMessageSource source, ChannelSide side, ChannelIdentifier identifier, byte[] data);
enum ForwardStatus {
/**
* Forwards this plugin message on to the client or server, depending on the {@link ChannelSide} it originated
* from.
*/
FORWARD,
/**
* Discard the plugin message and do not forward it on.
*/
HANDLED
}
}

View File

@@ -10,7 +10,7 @@ import java.util.regex.Pattern;
* Represents a Minecraft 1.13+ channel identifier. This class is immutable and safe for multi-threaded use.
*/
public final class MinecraftChannelIdentifier implements ChannelIdentifier {
private static final Pattern VALID_IDENTIFIER_REGEX = Pattern.compile("[a-z0-9\\-_]+", Pattern.CASE_INSENSITIVE);
private static final Pattern VALID_IDENTIFIER_REGEX = Pattern.compile("[a-z0-9\\-_]+");
private final String namespace;
private final String name;

View File

@@ -0,0 +1,30 @@
package com.velocitypowered.api.proxy.server;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
/**
* Represents a server that has been registered with the proxy.
*/
public interface RegisteredServer extends ChannelMessageSink {
/**
* Returns the {@link ServerInfo} for this server.
* @return the server info
*/
ServerInfo getServerInfo();
/**
* Returns a list of all the players currently connected to this server on this proxy.
* @return the players on this proxy
*/
Collection<Player> getPlayersConnected();
/**
* Attempts to ping the remote server and return the server list ping result.
* @return the server ping result from the server
*/
CompletableFuture<ServerPing> ping();
}

View File

@@ -74,6 +74,7 @@ public class ServerPing {
builder.favicon = favicon;
builder.nullOutModinfo = modinfo == null;
if (modinfo != null) {
builder.modType = modinfo.type;
builder.mods.addAll(modinfo.modList);
}
return builder;
@@ -91,6 +92,7 @@ public class ServerPing {
private int onlinePlayers;
private int maximumPlayers;
private final List<SamplePlayer> samplePlayers = new ArrayList<>();
private String modType;
private final List<Mod> mods = new ArrayList<>();
private Component description;
private Favicon favicon;
@@ -121,6 +123,11 @@ public class ServerPing {
return this;
}
public Builder modType(String modType) {
this.modType = Preconditions.checkNotNull(modType, "modType");
return this;
}
public Builder mods(Mod... mods) {
this.mods.addAll(Arrays.asList(mods));
return this;
@@ -158,7 +165,7 @@ public class ServerPing {
public ServerPing build() {
return new ServerPing(version, nullOutPlayers ? null : new Players(onlinePlayers, maximumPlayers, samplePlayers), description, favicon,
nullOutModinfo ? null : new Modinfo(mods));
nullOutModinfo ? null : new Modinfo(modType, mods));
}
public Version getVersion() {
@@ -185,6 +192,10 @@ public class ServerPing {
return favicon;
}
public String getModType() {
return modType;
}
public List<Mod> getMods() {
return mods;
}
@@ -196,6 +207,7 @@ public class ServerPing {
", onlinePlayers=" + onlinePlayers +
", maximumPlayers=" + maximumPlayers +
", samplePlayers=" + samplePlayers +
", modType=" + modType +
", mods=" + mods +
", description=" + description +
", favicon=" + favicon +
@@ -291,14 +303,23 @@ public class ServerPing {
}
public static class Modinfo {
public static final Modinfo DEFAULT = new Modinfo(ImmutableList.of());
public static final Modinfo DEFAULT = new Modinfo("FML", ImmutableList.of());
private final String type = "FML";
private final String type;
private final List<Mod> modList;
public Modinfo(List<Mod> modList) {
public Modinfo(String type, List<Mod> modList) {
this.type = Preconditions.checkNotNull(type, "type");
this.modList = ImmutableList.copyOf(modList);
}
public String getType() {
return type;
}
public List<Mod> getMods() {
return modList;
}
}
public static class Mod {

View File

@@ -24,7 +24,7 @@ public interface Scheduler {
* @param unit the unit of time for {@code time}
* @return this builder, for chaining
*/
TaskBuilder delay(int time, TimeUnit unit);
TaskBuilder delay(long time, TimeUnit unit);
/**
* Specifies that the task should continue running after waiting for the specified amount, until it is cancelled.
@@ -32,7 +32,7 @@ public interface Scheduler {
* @param unit the unit of time for {@code time}
* @return this builder, for chaining
*/
TaskBuilder repeat(int time, TimeUnit unit);
TaskBuilder repeat(long time, TimeUnit unit);
/**
* Clears the delay on this task.

View File

@@ -1,66 +0,0 @@
package com.velocitypowered.api.util;
import com.google.common.base.Preconditions;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.regex.Pattern;
/**
* LegacyChatColorUtils contains utilities for handling legacy Minecraft color codes. Generally, you should prefer
* JSON-based components, but for convenience Velocity provides a limited set of tools to handle Minecraft color codes.
*/
public class LegacyChatColorUtils {
private LegacyChatColorUtils() {
throw new AssertionError();
}
/**
* Represents the legacy Minecraft format character, the section symbol.
*/
public static final char FORMAT_CHAR = '\u00a7';
/**
* Translates a string with Minecraft color codes prefixed with a different character than the section symbol into
* a string that uses the section symbol.
* @param originalChar the char the color codes are prefixed by
* @param text the text to translate
* @return the translated text
*/
public static String translate(char originalChar, @NonNull String text) {
Preconditions.checkNotNull(text, "text");
char[] textChars = text.toCharArray();
int foundSectionIdx = -1;
for (int i = 0; i < textChars.length; i++) {
char textChar = textChars[i];
if (textChar == originalChar) {
foundSectionIdx = i;
continue;
}
if (foundSectionIdx >= 0) {
textChar = Character.toLowerCase(textChar);
if ((textChar >= 'a' && textChar <= 'f') || (textChar >= '0' && textChar <= '9') ||
(textChar >= 'l' && textChar <= 'o' || textChar == 'r')) {
textChars[foundSectionIdx] = FORMAT_CHAR;
}
foundSectionIdx = -1;
}
}
return new String(textChars);
}
/**
* A regex that matches all Minecraft color codes and removes them.
*/
private static final Pattern CHAT_COLOR_MATCHER = Pattern.compile("(?i)" + Character.toString(FORMAT_CHAR) + "[0-9A-FL-OR]");
/**
* Removes all Minecraft color codes from the string.
* @param text the text to remove color codes from
* @return a new String without Minecraft color codes
*/
public static String removeFormatting(@NonNull String text) {
Preconditions.checkNotNull(text, "text");
return CHAT_COLOR_MATCHER.matcher(text).replaceAll("");
}
}

View File

@@ -1,62 +0,0 @@
package com.velocitypowered.api.util;
import com.velocitypowered.api.util.LegacyChatColorUtils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class LegacyChatColorUtilsTest {
private static final String NON_FORMATTED = "Velocity";
private static final String FORMATTED = "\u00a7cVelocity";
private static final String FORMATTED_MULTIPLE = "\u00a7c\u00a7lVelocity";
private static final String FORMATTED_MULTIPLE_VARIED = "\u00a7c\u00a7lVelo\u00a7a\u00a7mcity";
private static final String INVALID = "\u00a7gVelocity";
private static final String RAW_SECTION = "\u00a7";
@Test
void removeFormattingNonFormatted() {
assertEquals(NON_FORMATTED, LegacyChatColorUtils.removeFormatting(NON_FORMATTED));
}
@Test
void removeFormattingFormatted() {
assertEquals(NON_FORMATTED, LegacyChatColorUtils.removeFormatting(FORMATTED));
}
@Test
void removeFormattingFormattedMultiple() {
assertEquals(NON_FORMATTED, LegacyChatColorUtils.removeFormatting(FORMATTED_MULTIPLE));
}
@Test
void removeFormattingFormattedMultipleVaried() {
assertEquals(NON_FORMATTED, LegacyChatColorUtils.removeFormatting(FORMATTED_MULTIPLE_VARIED));
}
@Test
void removeFormattingInvalidFormat() {
assertEquals(INVALID, LegacyChatColorUtils.removeFormatting(INVALID));
}
@Test
void removeFormattingRawSection() {
assertEquals(RAW_SECTION, LegacyChatColorUtils.removeFormatting(RAW_SECTION));
}
@Test
void translate() {
assertEquals(FORMATTED, LegacyChatColorUtils.translate('&', "&cVelocity"));
}
@Test
void translateMultiple() {
assertEquals(FORMATTED_MULTIPLE, LegacyChatColorUtils.translate('&', "&c&lVelocity"));
assertEquals(FORMATTED_MULTIPLE_VARIED, LegacyChatColorUtils.translate('&', "&c&lVelo&a&mcity"));
}
@Test
void translateDifferentChar() {
assertEquals(FORMATTED, LegacyChatColorUtils.translate('$', "$cVelocity"));
assertEquals(FORMATTED_MULTIPLE_VARIED, LegacyChatColorUtils.translate('$', "$c$lVelo$a$mcity"));
}
}