Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-12-23 23:00:35 +01:00
Ursprung
53aa92db92
Commit
25b5e00125
@ -2,9 +2,11 @@ plugins {
|
||||
id 'java'
|
||||
id 'com.github.johnrengelman.shadow' version '2.0.4'
|
||||
id 'maven-publish'
|
||||
id 'checkstyle'
|
||||
}
|
||||
|
||||
apply from: '../gradle/checkerframework.gradle'
|
||||
apply from: '../gradle/checkstyle.gradle'
|
||||
|
||||
sourceSets {
|
||||
ap {
|
||||
|
@ -3,7 +3,11 @@ package com.velocitypowered.api.plugin.ap;
|
||||
import com.google.gson.Gson;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.plugin.PluginDescription;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
@ -16,73 +20,76 @@ import javax.lang.model.element.TypeElement;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@SupportedAnnotationTypes({"com.velocitypowered.api.plugin.Plugin"})
|
||||
public class PluginAnnotationProcessor extends AbstractProcessor {
|
||||
private ProcessingEnvironment environment;
|
||||
private String pluginClassFound;
|
||||
private boolean warnedAboutMultiplePlugins;
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
this.environment = processingEnv;
|
||||
private ProcessingEnvironment environment;
|
||||
private String pluginClassFound;
|
||||
private boolean warnedAboutMultiplePlugins;
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
this.environment = processingEnv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (roundEnv.processingOver()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (roundEnv.processingOver()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(Plugin.class)) {
|
||||
if (element.getKind() != ElementKind.CLASS) {
|
||||
environment.getMessager().printMessage(Diagnostic.Kind.ERROR, "Only classes can be annotated with "
|
||||
+ Plugin.class.getCanonicalName());
|
||||
return false;
|
||||
}
|
||||
|
||||
Name qualifiedName = ((TypeElement) element).getQualifiedName();
|
||||
|
||||
if (Objects.equals(pluginClassFound, qualifiedName.toString())) {
|
||||
if (!warnedAboutMultiplePlugins) {
|
||||
environment.getMessager().printMessage(Diagnostic.Kind.WARNING, "Velocity does not yet currently support " +
|
||||
"multiple plugins. We are using " + pluginClassFound + " for your plugin's main class.");
|
||||
warnedAboutMultiplePlugins = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Plugin plugin = element.getAnnotation(Plugin.class);
|
||||
if (!PluginDescription.ID_PATTERN.matcher(plugin.id()).matches()) {
|
||||
environment.getMessager().printMessage(Diagnostic.Kind.ERROR, "Invalid ID for plugin "
|
||||
+ qualifiedName + ". IDs must start alphabetically, have alphanumeric characters, and can " +
|
||||
"contain dashes or underscores.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// All good, generate the velocity-plugin.json.
|
||||
SerializedPluginDescription description = SerializedPluginDescription.from(plugin, qualifiedName.toString());
|
||||
try {
|
||||
FileObject object = environment.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "velocity-plugin.json");
|
||||
try (Writer writer = new BufferedWriter(object.openWriter())) {
|
||||
new Gson().toJson(description, writer);
|
||||
}
|
||||
pluginClassFound = qualifiedName.toString();
|
||||
} catch (IOException e) {
|
||||
environment.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate plugin file");
|
||||
}
|
||||
}
|
||||
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(Plugin.class)) {
|
||||
if (element.getKind() != ElementKind.CLASS) {
|
||||
environment.getMessager()
|
||||
.printMessage(Diagnostic.Kind.ERROR, "Only classes can be annotated with "
|
||||
+ Plugin.class.getCanonicalName());
|
||||
return false;
|
||||
}
|
||||
|
||||
Name qualifiedName = ((TypeElement) element).getQualifiedName();
|
||||
|
||||
if (Objects.equals(pluginClassFound, qualifiedName.toString())) {
|
||||
if (!warnedAboutMultiplePlugins) {
|
||||
environment.getMessager()
|
||||
.printMessage(Diagnostic.Kind.WARNING, "Velocity does not yet currently support " +
|
||||
"multiple plugins. We are using " + pluginClassFound
|
||||
+ " for your plugin's main class.");
|
||||
warnedAboutMultiplePlugins = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Plugin plugin = element.getAnnotation(Plugin.class);
|
||||
if (!PluginDescription.ID_PATTERN.matcher(plugin.id()).matches()) {
|
||||
environment.getMessager().printMessage(Diagnostic.Kind.ERROR, "Invalid ID for plugin "
|
||||
+ qualifiedName
|
||||
+ ". IDs must start alphabetically, have alphanumeric characters, and can " +
|
||||
"contain dashes or underscores.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// All good, generate the velocity-plugin.json.
|
||||
SerializedPluginDescription description = SerializedPluginDescription
|
||||
.from(plugin, qualifiedName.toString());
|
||||
try {
|
||||
FileObject object = environment.getFiler()
|
||||
.createResource(StandardLocation.CLASS_OUTPUT, "", "velocity-plugin.json");
|
||||
try (Writer writer = new BufferedWriter(object.openWriter())) {
|
||||
new Gson().toJson(description, writer);
|
||||
}
|
||||
pluginClassFound = qualifiedName.toString();
|
||||
} catch (IOException e) {
|
||||
environment.getMessager()
|
||||
.printMessage(Diagnostic.Kind.ERROR, "Unable to generate plugin file");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -4,149 +4,162 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class SerializedPluginDescription {
|
||||
// @Nullable is used here to make GSON skip these in the serialized file
|
||||
private final String id;
|
||||
private final @Nullable String name;
|
||||
private final @Nullable String version;
|
||||
private final @Nullable String description;
|
||||
private final @Nullable String url;
|
||||
private final @Nullable List<String> authors;
|
||||
private final @Nullable List<Dependency> dependencies;
|
||||
private final String main;
|
||||
|
||||
public SerializedPluginDescription(String id, String name, String version, String description, String url,
|
||||
List<String> authors, List<Dependency> dependencies, String main) {
|
||||
this.id = Preconditions.checkNotNull(id, "id");
|
||||
this.name = Strings.emptyToNull(name);
|
||||
this.version = Strings.emptyToNull(version);
|
||||
this.description = Strings.emptyToNull(description);
|
||||
this.url = Strings.emptyToNull(url);
|
||||
this.authors = authors == null || authors.isEmpty() ? ImmutableList.of() : authors;
|
||||
this.dependencies = dependencies == null || dependencies.isEmpty() ? ImmutableList.of() : dependencies;
|
||||
this.main = Preconditions.checkNotNull(main, "main");
|
||||
// @Nullable is used here to make GSON skip these in the serialized file
|
||||
private final String id;
|
||||
private final @Nullable String name;
|
||||
private final @Nullable String version;
|
||||
private final @Nullable String description;
|
||||
private final @Nullable String url;
|
||||
private final @Nullable List<String> authors;
|
||||
private final @Nullable List<Dependency> dependencies;
|
||||
private final String main;
|
||||
|
||||
public SerializedPluginDescription(String id, String name, String version, String description,
|
||||
String url,
|
||||
List<String> authors, List<Dependency> dependencies, String main) {
|
||||
this.id = Preconditions.checkNotNull(id, "id");
|
||||
this.name = Strings.emptyToNull(name);
|
||||
this.version = Strings.emptyToNull(version);
|
||||
this.description = Strings.emptyToNull(description);
|
||||
this.url = Strings.emptyToNull(url);
|
||||
this.authors = authors == null || authors.isEmpty() ? ImmutableList.of() : authors;
|
||||
this.dependencies =
|
||||
dependencies == null || dependencies.isEmpty() ? ImmutableList.of() : dependencies;
|
||||
this.main = Preconditions.checkNotNull(main, "main");
|
||||
}
|
||||
|
||||
public static SerializedPluginDescription from(Plugin plugin, String qualifiedName) {
|
||||
List<Dependency> dependencies = new ArrayList<>();
|
||||
for (com.velocitypowered.api.plugin.Dependency dependency : plugin.dependencies()) {
|
||||
dependencies.add(new Dependency(dependency.id(), dependency.optional()));
|
||||
}
|
||||
return new SerializedPluginDescription(plugin.id(), plugin.name(), plugin.version(),
|
||||
plugin.description(), plugin.url(),
|
||||
Arrays.stream(plugin.authors()).filter(author -> !author.isEmpty())
|
||||
.collect(Collectors.toList()), dependencies, qualifiedName);
|
||||
}
|
||||
|
||||
public static SerializedPluginDescription from(Plugin plugin, String qualifiedName) {
|
||||
List<Dependency> dependencies = new ArrayList<>();
|
||||
for (com.velocitypowered.api.plugin.Dependency dependency : plugin.dependencies()) {
|
||||
dependencies.add(new Dependency(dependency.id(), dependency.optional()));
|
||||
}
|
||||
return new SerializedPluginDescription(plugin.id(), plugin.name(), plugin.version(), plugin.description(), plugin.url(),
|
||||
Arrays.stream(plugin.authors()).filter(author -> !author.isEmpty()).collect(Collectors.toList()), dependencies, qualifiedName);
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @Nullable String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public @Nullable String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public @Nullable String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public @Nullable String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public List<String> getAuthors() {
|
||||
return authors == null ? ImmutableList.of() : authors;
|
||||
}
|
||||
|
||||
public List<Dependency> getDependencies() {
|
||||
return dependencies == null ? ImmutableList.of() : dependencies;
|
||||
}
|
||||
|
||||
public String getMain() {
|
||||
return main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SerializedPluginDescription that = (SerializedPluginDescription) o;
|
||||
return Objects.equals(id, that.id) &&
|
||||
Objects.equals(name, that.name) &&
|
||||
Objects.equals(version, that.version) &&
|
||||
Objects.equals(description, that.description) &&
|
||||
Objects.equals(url, that.url) &&
|
||||
Objects.equals(authors, that.authors) &&
|
||||
Objects.equals(dependencies, that.dependencies) &&
|
||||
Objects.equals(main, that.main);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name, version, description, url, authors, dependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SerializedPluginDescription{" +
|
||||
"id='" + id + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", url='" + url + '\'' +
|
||||
", authors=" + authors +
|
||||
", dependencies=" + dependencies +
|
||||
", main='" + main + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static class Dependency {
|
||||
|
||||
private final String id;
|
||||
private final boolean optional;
|
||||
|
||||
public Dependency(String id, boolean optional) {
|
||||
this.id = id;
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
return id;
|
||||
}
|
||||
|
||||
public @Nullable String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public @Nullable String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public @Nullable String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public @Nullable String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public List<String> getAuthors() {
|
||||
return authors == null ? ImmutableList.of() : authors;
|
||||
}
|
||||
|
||||
public List<Dependency> getDependencies() {
|
||||
return dependencies == null ? ImmutableList.of() : dependencies;
|
||||
}
|
||||
|
||||
public String getMain() {
|
||||
return main;
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SerializedPluginDescription that = (SerializedPluginDescription) o;
|
||||
return Objects.equals(id, that.id) &&
|
||||
Objects.equals(name, that.name) &&
|
||||
Objects.equals(version, that.version) &&
|
||||
Objects.equals(description, that.description) &&
|
||||
Objects.equals(url, that.url) &&
|
||||
Objects.equals(authors, that.authors) &&
|
||||
Objects.equals(dependencies, that.dependencies) &&
|
||||
Objects.equals(main, that.main);
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Dependency that = (Dependency) o;
|
||||
return optional == that.optional &&
|
||||
Objects.equals(id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name, version, description, url, authors, dependencies);
|
||||
return Objects.hash(id, optional);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SerializedPluginDescription{" +
|
||||
"id='" + id + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", url='" + url + '\'' +
|
||||
", authors=" + authors +
|
||||
", dependencies=" + dependencies +
|
||||
", main='" + main + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static class Dependency {
|
||||
private final String id;
|
||||
private final boolean optional;
|
||||
|
||||
public Dependency(String id, boolean optional) {
|
||||
this.id = id;
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Dependency that = (Dependency) o;
|
||||
return optional == that.optional &&
|
||||
Objects.equals(id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, optional);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Dependency{" +
|
||||
"id='" + id + '\'' +
|
||||
", optional=" + optional +
|
||||
'}';
|
||||
}
|
||||
return "Dependency{" +
|
||||
"id='" + id + '\'' +
|
||||
", optional=" + optional +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +1,46 @@
|
||||
package com.velocitypowered.api.command;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a command that can be executed by a {@link CommandSource}, such as a {@link com.velocitypowered.api.proxy.Player}
|
||||
* or the console.
|
||||
* Represents a command that can be executed by a {@link CommandSource}, such as a {@link
|
||||
* com.velocitypowered.api.proxy.Player} or the console.
|
||||
*/
|
||||
public interface Command {
|
||||
/**
|
||||
* Executes the command for the specified {@link CommandSource}.
|
||||
* @param source the source of this command
|
||||
* @param args the arguments for this command
|
||||
*/
|
||||
void execute(CommandSource source, String @NonNull [] args);
|
||||
|
||||
/**
|
||||
* Provides tab complete suggestions for a command for a specified {@link CommandSource}.
|
||||
* @param source the source to run the command for
|
||||
* @param currentArgs the current, partial arguments for this command
|
||||
* @return tab complete suggestions
|
||||
*/
|
||||
default List<String> suggest(CommandSource source, String @NonNull [] currentArgs) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
/**
|
||||
* Executes the command for the specified {@link CommandSource}.
|
||||
*
|
||||
* @param source the source of this command
|
||||
* @param args the arguments for this command
|
||||
*/
|
||||
void execute(CommandSource source, String @NonNull [] args);
|
||||
|
||||
/**
|
||||
* Tests to check if the {@code source} has permission to use this command
|
||||
* with the provided {@code args}.
|
||||
*
|
||||
* <p>If this method returns false, the handling will be forwarded onto
|
||||
* the players current server.</p>
|
||||
*
|
||||
* @param source the source of the command
|
||||
* @param args the arguments for this command
|
||||
* @return whether the source has permission
|
||||
*/
|
||||
default boolean hasPermission(CommandSource source, String @NonNull [] args) {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Provides tab complete suggestions for a command for a specified {@link CommandSource}.
|
||||
*
|
||||
* @param source the source to run the command for
|
||||
* @param currentArgs the current, partial arguments for this command
|
||||
* @return tab complete suggestions
|
||||
*/
|
||||
default List<String> suggest(CommandSource source, String @NonNull [] currentArgs) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to check if the {@code source} has permission to use this command with the provided
|
||||
* {@code args}.
|
||||
*
|
||||
* <p>If this method returns false, the handling will be forwarded onto
|
||||
* the players current server.</p>
|
||||
*
|
||||
* @param source the source of the command
|
||||
* @param args the arguments for this command
|
||||
* @return whether the source has permission
|
||||
*/
|
||||
default boolean hasPermission(CommandSource source, String @NonNull [] args) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -4,24 +4,28 @@ package com.velocitypowered.api.command;
|
||||
* Represents an interface to register a command executor with the proxy.
|
||||
*/
|
||||
public interface CommandManager {
|
||||
/**
|
||||
* Registers the specified command with the manager with the specified aliases.
|
||||
* @param command the command to register
|
||||
* @param aliases the alias to use
|
||||
*/
|
||||
void register(Command command, String... aliases);
|
||||
|
||||
/**
|
||||
* Unregisters a command.
|
||||
* @param alias the command alias to unregister
|
||||
*/
|
||||
void unregister(String alias);
|
||||
/**
|
||||
* Registers the specified command with the manager with the specified aliases.
|
||||
*
|
||||
* @param command the command to register
|
||||
* @param aliases the alias to use
|
||||
*/
|
||||
void register(Command command, String... aliases);
|
||||
|
||||
/**
|
||||
* Attempts to execute a command from the specified {@code cmdLine}.
|
||||
* @param source the command's source
|
||||
* @param cmdLine the command to run
|
||||
* @return true if the command was found and executed, false if it was not
|
||||
*/
|
||||
boolean execute(CommandSource source, String cmdLine);
|
||||
/**
|
||||
* Unregisters a command.
|
||||
*
|
||||
* @param alias the command alias to unregister
|
||||
*/
|
||||
void unregister(String alias);
|
||||
|
||||
/**
|
||||
* Attempts to execute a command from the specified {@code cmdLine}.
|
||||
*
|
||||
* @param source the command's source
|
||||
* @param cmdLine the command to run
|
||||
* @return true if the command was found and executed, false if it was not
|
||||
*/
|
||||
boolean execute(CommandSource source, String cmdLine);
|
||||
}
|
||||
|
@ -7,9 +7,11 @@ import net.kyori.text.Component;
|
||||
* Represents something that can be used to run a {@link Command}.
|
||||
*/
|
||||
public interface CommandSource extends PermissionSubject {
|
||||
/**
|
||||
* Sends the specified {@code component} to the invoker.
|
||||
* @param component the text component to send
|
||||
*/
|
||||
void sendMessage(Component component);
|
||||
|
||||
/**
|
||||
* Sends the specified {@code component} to the invoker.
|
||||
*
|
||||
* @param component the text component to send
|
||||
*/
|
||||
void sendMessage(Component component);
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package com.velocitypowered.api.event;
|
||||
|
||||
/**
|
||||
* Represents an interface to perform direct dispatch of an event. This makes integration easier to achieve with platforms
|
||||
* such as RxJava.
|
||||
* Represents an interface to perform direct dispatch of an event. This makes integration easier to
|
||||
* achieve with platforms such as RxJava.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface EventHandler<E> {
|
||||
void execute(E event);
|
||||
|
||||
void execute(E event);
|
||||
}
|
||||
|
@ -6,68 +6,82 @@ import java.util.concurrent.CompletableFuture;
|
||||
* Allows plugins to register and deregister listeners for event handlers.
|
||||
*/
|
||||
public interface EventManager {
|
||||
/**
|
||||
* Requests that the specified {@code listener} listen for events and associate it with the {@code plugin}.
|
||||
* @param plugin the plugin to associate with the listener
|
||||
* @param listener the listener to register
|
||||
*/
|
||||
void register(Object plugin, Object listener);
|
||||
|
||||
/**
|
||||
* Requests that the specified {@code handler} listen for events and associate it with the {@code plugin}.
|
||||
* @param plugin the plugin to associate with the handler
|
||||
* @param eventClass the class for the event handler to register
|
||||
* @param handler the handler to register
|
||||
* @param <E> the event type to handle
|
||||
*/
|
||||
default <E> void register(Object plugin, Class<E> eventClass, EventHandler<E> handler) {
|
||||
register(plugin, eventClass, PostOrder.NORMAL, handler);
|
||||
}
|
||||
/**
|
||||
* Requests that the specified {@code listener} listen for events and associate it with the {@code
|
||||
* plugin}.
|
||||
*
|
||||
* @param plugin the plugin to associate with the listener
|
||||
* @param listener the listener to register
|
||||
*/
|
||||
void register(Object plugin, Object listener);
|
||||
|
||||
/**
|
||||
* Requests that the specified {@code handler} listen for events and associate it with the {@code plugin}.
|
||||
* @param plugin the plugin to associate with the handler
|
||||
* @param eventClass the class for the event handler to register
|
||||
* @param postOrder the order in which events should be posted to the handler
|
||||
* @param handler the handler to register
|
||||
* @param <E> the event type to handle
|
||||
*/
|
||||
<E> void register(Object plugin, Class<E> eventClass, PostOrder postOrder, EventHandler<E> handler);
|
||||
/**
|
||||
* Requests that the specified {@code handler} listen for events and associate it with the {@code
|
||||
* plugin}.
|
||||
*
|
||||
* @param plugin the plugin to associate with the handler
|
||||
* @param eventClass the class for the event handler to register
|
||||
* @param handler the handler to register
|
||||
* @param <E> the event type to handle
|
||||
*/
|
||||
default <E> void register(Object plugin, Class<E> eventClass, EventHandler<E> handler) {
|
||||
register(plugin, eventClass, PostOrder.NORMAL, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires the specified event to the event bus asynchronously. This allows Velocity to continue servicing connections
|
||||
* while a plugin handles a potentially long-running operation such as a database query.
|
||||
* @param event the event to fire
|
||||
* @return a {@link CompletableFuture} representing the posted event
|
||||
*/
|
||||
<E> CompletableFuture<E> fire(E event);
|
||||
/**
|
||||
* Requests that the specified {@code handler} listen for events and associate it with the {@code
|
||||
* plugin}.
|
||||
*
|
||||
* @param plugin the plugin to associate with the handler
|
||||
* @param eventClass the class for the event handler to register
|
||||
* @param postOrder the order in which events should be posted to the handler
|
||||
* @param handler the handler to register
|
||||
* @param <E> the event type to handle
|
||||
*/
|
||||
<E> void register(Object plugin, Class<E> eventClass, PostOrder postOrder,
|
||||
EventHandler<E> handler);
|
||||
|
||||
/**
|
||||
* Posts the specified event to the event bus and discards the result.
|
||||
* @param event the event to fire
|
||||
*/
|
||||
default void fireAndForget(Object event) {
|
||||
fire(event);
|
||||
}
|
||||
/**
|
||||
* Fires the specified event to the event bus asynchronously. This allows Velocity to continue
|
||||
* servicing connections while a plugin handles a potentially long-running operation such as a
|
||||
* database query.
|
||||
*
|
||||
* @param event the event to fire
|
||||
* @return a {@link CompletableFuture} representing the posted event
|
||||
*/
|
||||
<E> CompletableFuture<E> fire(E event);
|
||||
|
||||
/**
|
||||
* Unregisters all listeners for the specified {@code plugin}.
|
||||
* @param plugin the plugin to deregister listeners for
|
||||
*/
|
||||
void unregisterListeners(Object plugin);
|
||||
/**
|
||||
* Posts the specified event to the event bus and discards the result.
|
||||
*
|
||||
* @param event the event to fire
|
||||
*/
|
||||
default void fireAndForget(Object event) {
|
||||
fire(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a specific listener for a specific plugin.
|
||||
* @param plugin the plugin associated with the listener
|
||||
* @param listener the listener to deregister
|
||||
*/
|
||||
void unregisterListener(Object plugin, Object listener);
|
||||
/**
|
||||
* Unregisters all listeners for the specified {@code plugin}.
|
||||
*
|
||||
* @param plugin the plugin to deregister listeners for
|
||||
*/
|
||||
void unregisterListeners(Object plugin);
|
||||
|
||||
/**
|
||||
* Unregisters a specific event handler for a specific plugin.
|
||||
* @param plugin the plugin to associate with the handler
|
||||
* @param handler the handler to register
|
||||
* @param <E> the event type to handle
|
||||
*/
|
||||
<E> void unregister(Object plugin, EventHandler<E> handler);
|
||||
/**
|
||||
* Unregisters a specific listener for a specific plugin.
|
||||
*
|
||||
* @param plugin the plugin associated with the listener
|
||||
* @param listener the listener to deregister
|
||||
*/
|
||||
void unregisterListener(Object plugin, Object listener);
|
||||
|
||||
/**
|
||||
* Unregisters a specific event handler for a specific plugin.
|
||||
*
|
||||
* @param plugin the plugin to associate with the handler
|
||||
* @param handler the handler to register
|
||||
* @param <E> the event type to handle
|
||||
*/
|
||||
<E> void unregister(Object plugin, EventHandler<E> handler);
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package com.velocitypowered.api.event;
|
||||
|
||||
/**
|
||||
* Represents the order an event will be posted to a listener method, relative
|
||||
* to other listeners.
|
||||
* Represents the order an event will be posted to a listener method, relative to other listeners.
|
||||
*/
|
||||
public enum PostOrder {
|
||||
|
||||
FIRST, EARLY, NORMAL, LATE, LAST;
|
||||
FIRST, EARLY, NORMAL, LATE, LAST;
|
||||
|
||||
}
|
||||
|
@ -1,114 +1,119 @@
|
||||
package com.velocitypowered.api.event;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.Optional;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Indicates an event that has a result attached to it.
|
||||
*/
|
||||
public interface ResultedEvent<R extends ResultedEvent.Result> {
|
||||
/**
|
||||
* Returns the result associated with this event.
|
||||
* @return the result of this event
|
||||
*/
|
||||
R getResult();
|
||||
|
||||
/**
|
||||
* Returns the result associated with this event.
|
||||
*
|
||||
* @return the result of this event
|
||||
*/
|
||||
R getResult();
|
||||
|
||||
/**
|
||||
* Sets the result of this event. The result must be non-null.
|
||||
*
|
||||
* @param result the new result
|
||||
*/
|
||||
void setResult(R result);
|
||||
|
||||
/**
|
||||
* Represents a result for an event.
|
||||
*/
|
||||
interface Result {
|
||||
|
||||
/**
|
||||
* Sets the result of this event. The result must be non-null.
|
||||
* @param result the new result
|
||||
* Returns whether or not the event is allowed to proceed. Plugins may choose to skip denied
|
||||
* events, and the proxy will respect the result of this method.
|
||||
*
|
||||
* @return whether or not the event is allowed to proceed
|
||||
*/
|
||||
void setResult(R result);
|
||||
boolean isAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a result for an event.
|
||||
*/
|
||||
interface Result {
|
||||
/**
|
||||
* Returns whether or not the event is allowed to proceed. Plugins may choose to skip denied events, and the
|
||||
* proxy will respect the result of this method.
|
||||
* @return whether or not the event is allowed to proceed
|
||||
*/
|
||||
boolean isAllowed();
|
||||
/**
|
||||
* A generic "allowed/denied" result.
|
||||
*/
|
||||
final class GenericResult implements Result {
|
||||
|
||||
private static final GenericResult ALLOWED = new GenericResult(true);
|
||||
private static final GenericResult DENIED = new GenericResult(false);
|
||||
|
||||
private final boolean status;
|
||||
|
||||
private GenericResult(boolean b) {
|
||||
this.status = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic "allowed/denied" result.
|
||||
*/
|
||||
final class GenericResult implements Result {
|
||||
private static final GenericResult ALLOWED = new GenericResult(true);
|
||||
private static final GenericResult DENIED = new GenericResult(false);
|
||||
|
||||
private final boolean status;
|
||||
|
||||
private GenericResult(boolean b) {
|
||||
this.status = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return status ? "allowed" : "denied";
|
||||
}
|
||||
|
||||
public static GenericResult allowed() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
public static GenericResult denied() {
|
||||
return DENIED;
|
||||
}
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an "allowed/denied" result with a reason allowed for denial.
|
||||
*/
|
||||
final class ComponentResult implements Result {
|
||||
private static final ComponentResult ALLOWED = new ComponentResult(true, null);
|
||||
|
||||
private final boolean status;
|
||||
private final @Nullable Component reason;
|
||||
|
||||
protected ComponentResult(boolean status, @Nullable Component reason) {
|
||||
this.status = status;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public Optional<Component> getReason() {
|
||||
return Optional.ofNullable(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (status) {
|
||||
return "allowed";
|
||||
}
|
||||
if (reason != null) {
|
||||
return "denied: " + ComponentSerializers.PLAIN.serialize(reason);
|
||||
}
|
||||
return "denied";
|
||||
}
|
||||
|
||||
public static ComponentResult allowed() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
public static ComponentResult denied(Component reason) {
|
||||
Preconditions.checkNotNull(reason, "reason");
|
||||
return new ComponentResult(false, reason);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return status ? "allowed" : "denied";
|
||||
}
|
||||
|
||||
public static GenericResult allowed() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
public static GenericResult denied() {
|
||||
return DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an "allowed/denied" result with a reason allowed for denial.
|
||||
*/
|
||||
final class ComponentResult implements Result {
|
||||
|
||||
private static final ComponentResult ALLOWED = new ComponentResult(true, null);
|
||||
|
||||
private final boolean status;
|
||||
private final @Nullable Component reason;
|
||||
|
||||
protected ComponentResult(boolean status, @Nullable Component reason) {
|
||||
this.status = status;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public Optional<Component> getReason() {
|
||||
return Optional.ofNullable(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (status) {
|
||||
return "allowed";
|
||||
}
|
||||
if (reason != null) {
|
||||
return "denied: " + ComponentSerializers.PLAIN.serialize(reason);
|
||||
}
|
||||
return "denied";
|
||||
}
|
||||
|
||||
public static ComponentResult allowed() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
public static ComponentResult denied(Component reason) {
|
||||
Preconditions.checkNotNull(reason, "reason");
|
||||
return new ComponentResult(false, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Subscribe {
|
||||
|
||||
/**
|
||||
* The order events will be posted to this listener.
|
||||
*
|
||||
* @return the order
|
||||
*/
|
||||
PostOrder order() default PostOrder.NORMAL;
|
||||
/**
|
||||
* The order events will be posted to this listener.
|
||||
*
|
||||
* @return the order
|
||||
*/
|
||||
PostOrder order() default PostOrder.NORMAL;
|
||||
|
||||
}
|
||||
|
@ -7,20 +7,21 @@ import com.velocitypowered.api.proxy.InboundConnection;
|
||||
* This event is fired when a handshake is established between a client and Velocity.
|
||||
*/
|
||||
public final class ConnectionHandshakeEvent {
|
||||
private final InboundConnection connection;
|
||||
|
||||
public ConnectionHandshakeEvent(InboundConnection connection) {
|
||||
this.connection = Preconditions.checkNotNull(connection, "connection");
|
||||
}
|
||||
private final InboundConnection connection;
|
||||
|
||||
public InboundConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
public ConnectionHandshakeEvent(InboundConnection connection) {
|
||||
this.connection = Preconditions.checkNotNull(connection, "connection");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectionHandshakeEvent{" +
|
||||
"connection=" + connection +
|
||||
'}';
|
||||
}
|
||||
public InboundConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectionHandshakeEvent{" +
|
||||
"connection=" + connection +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -4,24 +4,25 @@ import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
/**
|
||||
* This event is fired when a player disconnects from the proxy. Operations on the provided player, aside from basic
|
||||
* data retrieval operations, may behave in undefined ways.
|
||||
* This event is fired when a player disconnects from the proxy. Operations on the provided player,
|
||||
* aside from basic data retrieval operations, may behave in undefined ways.
|
||||
*/
|
||||
public final class DisconnectEvent {
|
||||
private final Player player;
|
||||
|
||||
public DisconnectEvent(Player player) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
}
|
||||
private final Player player;
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
public DisconnectEvent(Player player) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DisconnectEvent{" +
|
||||
"player=" + player +
|
||||
'}';
|
||||
}
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DisconnectEvent{" +
|
||||
"player=" + player +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -5,36 +5,38 @@ import com.velocitypowered.api.event.ResultedEvent;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
/**
|
||||
* This event is fired once the player has been authenticated but before they connect to a server on the proxy.
|
||||
* This event is fired once the player has been authenticated but before they connect to a server on
|
||||
* the proxy.
|
||||
*/
|
||||
public final class LoginEvent implements ResultedEvent<ResultedEvent.ComponentResult> {
|
||||
private final Player player;
|
||||
private ComponentResult result;
|
||||
|
||||
public LoginEvent(Player player) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.result = ComponentResult.allowed();
|
||||
}
|
||||
private final Player player;
|
||||
private ComponentResult result;
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
public LoginEvent(Player player) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.result = ComponentResult.allowed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentResult getResult() {
|
||||
return result;
|
||||
}
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(ComponentResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
}
|
||||
@Override
|
||||
public ComponentResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LoginEvent{" +
|
||||
"player=" + player +
|
||||
", result=" + result +
|
||||
'}';
|
||||
}
|
||||
@Override
|
||||
public void setResult(ComponentResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LoginEvent{" +
|
||||
"player=" + player +
|
||||
", result=" + result +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -7,99 +7,100 @@ 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}).
|
||||
* 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 final 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();
|
||||
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(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 final class ForwardResult implements ResultedEvent.Result {
|
||||
|
||||
private static final ForwardResult ALLOWED = new ForwardResult(true);
|
||||
private static final ForwardResult DENIED = new ForwardResult(false);
|
||||
|
||||
private final boolean status;
|
||||
|
||||
private ForwardResult(boolean b) {
|
||||
this.status = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForwardResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(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);
|
||||
public boolean isAllowed() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PluginMessageEvent{" +
|
||||
"source=" + source +
|
||||
", target=" + target +
|
||||
", identifier=" + identifier +
|
||||
", data=" + Arrays.toString(data) +
|
||||
", result=" + result +
|
||||
'}';
|
||||
return status ? "forward to sink" : "handled message at proxy";
|
||||
}
|
||||
|
||||
/**
|
||||
* A result determining whether or not to forward this message on.
|
||||
*/
|
||||
public static final class ForwardResult implements ResultedEvent.Result {
|
||||
private static final ForwardResult ALLOWED = new ForwardResult(true);
|
||||
private static final ForwardResult DENIED = new ForwardResult(false);
|
||||
|
||||
private final boolean status;
|
||||
|
||||
private ForwardResult(boolean b) {
|
||||
this.status = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return status ? "forward to sink" : "handled message at proxy";
|
||||
}
|
||||
|
||||
public static ForwardResult forward() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
public static ForwardResult handled() {
|
||||
return DENIED;
|
||||
}
|
||||
public static ForwardResult forward() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
public static ForwardResult handled() {
|
||||
return DENIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,25 +4,25 @@ 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
|
||||
* 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 final class PostLoginEvent {
|
||||
|
||||
private final Player player;
|
||||
private final Player player;
|
||||
|
||||
public PostLoginEvent(Player player) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
}
|
||||
public PostLoginEvent(Player player) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PostLoginEvent{"
|
||||
+ "player=" + player
|
||||
+ '}';
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PostLoginEvent{"
|
||||
+ "player=" + player
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
@ -3,147 +3,153 @@ 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 java.util.Optional;
|
||||
import net.kyori.text.Component;
|
||||
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).
|
||||
* 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).
|
||||
*/
|
||||
public final class PreLoginEvent implements ResultedEvent<PreLoginEvent.PreLoginComponentResult> {
|
||||
private final InboundConnection connection;
|
||||
private final String username;
|
||||
private PreLoginComponentResult result;
|
||||
|
||||
public PreLoginEvent(InboundConnection connection, String username) {
|
||||
this.connection = Preconditions.checkNotNull(connection, "connection");
|
||||
this.username = Preconditions.checkNotNull(username, "username");
|
||||
this.result = PreLoginComponentResult.allowed();
|
||||
}
|
||||
private final InboundConnection connection;
|
||||
private final String username;
|
||||
private PreLoginComponentResult result;
|
||||
|
||||
public InboundConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
public PreLoginEvent(InboundConnection connection, String username) {
|
||||
this.connection = Preconditions.checkNotNull(connection, "connection");
|
||||
this.username = Preconditions.checkNotNull(username, "username");
|
||||
this.result = PreLoginComponentResult.allowed();
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
public InboundConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreLoginComponentResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(@NonNull PreLoginComponentResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PreLoginEvent{" +
|
||||
"connection=" + connection +
|
||||
", username='" + username + '\'' +
|
||||
", result=" + result +
|
||||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an "allowed/allowed with forced online\offline mode/denied" result with a reason
|
||||
* allowed for denial.
|
||||
*/
|
||||
public static final class PreLoginComponentResult implements ResultedEvent.Result {
|
||||
|
||||
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);
|
||||
|
||||
private final Result result;
|
||||
private final @Nullable Component reason;
|
||||
|
||||
private PreLoginComponentResult(Result result, @Nullable Component reason) {
|
||||
this.result = result;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreLoginComponentResult getResult() {
|
||||
return result;
|
||||
public boolean isAllowed() {
|
||||
return result != Result.DISALLOWED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(@NonNull PreLoginComponentResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
public Optional<Component> getReason() {
|
||||
return Optional.ofNullable(reason);
|
||||
}
|
||||
|
||||
public boolean isOnlineModeAllowed() {
|
||||
return result == Result.FORCE_ONLINE;
|
||||
}
|
||||
|
||||
public boolean isForceOfflineMode() {
|
||||
return result == Result.FORCE_OFFLINE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PreLoginEvent{" +
|
||||
"connection=" + connection +
|
||||
", username='" + username + '\'' +
|
||||
", result=" + result +
|
||||
'}';
|
||||
switch (result) {
|
||||
case ALLOWED:
|
||||
return "allowed";
|
||||
case FORCE_OFFLINE:
|
||||
return "allowed with force offline mode";
|
||||
case FORCE_ONLINE:
|
||||
return "allowed with online mode";
|
||||
default:
|
||||
return "denied";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an "allowed/allowed with forced online\offline mode/denied" result with a reason allowed for denial.
|
||||
* Returns a result indicating the connection will be allowed through the proxy.
|
||||
*
|
||||
* @return the allowed result
|
||||
*/
|
||||
public static final class PreLoginComponentResult implements ResultedEvent.Result {
|
||||
|
||||
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);
|
||||
|
||||
private final Result result;
|
||||
private final @Nullable Component reason;
|
||||
|
||||
private PreLoginComponentResult(Result result, @Nullable Component reason) {
|
||||
this.result = result;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return result != Result.DISALLOWED;
|
||||
}
|
||||
|
||||
public Optional<Component> getReason() {
|
||||
return Optional.ofNullable(reason);
|
||||
}
|
||||
|
||||
public boolean isOnlineModeAllowed() {
|
||||
return result == Result.FORCE_ONLINE;
|
||||
}
|
||||
|
||||
public boolean isForceOfflineMode() {
|
||||
return result == Result.FORCE_OFFLINE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (result) {
|
||||
case ALLOWED:
|
||||
return "allowed";
|
||||
case FORCE_OFFLINE:
|
||||
return "allowed with force offline mode";
|
||||
case FORCE_ONLINE:
|
||||
return "allowed with online mode";
|
||||
default:
|
||||
return "denied";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a result indicating the connection will be allowed through
|
||||
* the proxy.
|
||||
* @return the allowed result
|
||||
*/
|
||||
public static PreLoginComponentResult allowed() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(Component reason) {
|
||||
Preconditions.checkNotNull(reason, "reason");
|
||||
return new PreLoginComponentResult(Result.DISALLOWED, reason);
|
||||
}
|
||||
|
||||
private enum Result {
|
||||
ALLOWED,
|
||||
FORCE_ONLINE,
|
||||
FORCE_OFFLINE,
|
||||
DISALLOWED
|
||||
}
|
||||
public static PreLoginComponentResult allowed() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(Component reason) {
|
||||
Preconditions.checkNotNull(reason, "reason");
|
||||
return new PreLoginComponentResult(Result.DISALLOWED, reason);
|
||||
}
|
||||
|
||||
private enum Result {
|
||||
ALLOWED,
|
||||
FORCE_ONLINE,
|
||||
FORCE_OFFLINE,
|
||||
DISALLOWED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,52 +12,52 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
* <p>This event is only called once per subject, on initialisation.</p>
|
||||
*/
|
||||
public final class PermissionsSetupEvent {
|
||||
private final PermissionSubject subject;
|
||||
private final PermissionProvider defaultProvider;
|
||||
private PermissionProvider provider;
|
||||
|
||||
public PermissionsSetupEvent(PermissionSubject subject, PermissionProvider provider) {
|
||||
this.subject = Preconditions.checkNotNull(subject, "subject");
|
||||
this.provider = this.defaultProvider = Preconditions.checkNotNull(provider, "provider");
|
||||
}
|
||||
private final PermissionSubject subject;
|
||||
private final PermissionProvider defaultProvider;
|
||||
private PermissionProvider provider;
|
||||
|
||||
public PermissionSubject getSubject() {
|
||||
return this.subject;
|
||||
}
|
||||
public PermissionsSetupEvent(PermissionSubject subject, PermissionProvider provider) {
|
||||
this.subject = Preconditions.checkNotNull(subject, "subject");
|
||||
this.provider = this.defaultProvider = Preconditions.checkNotNull(provider, "provider");
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the provider function to obtain a {@link PermissionFunction} for
|
||||
* the subject.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @return the obtained permission function
|
||||
*/
|
||||
public PermissionFunction createFunction(PermissionSubject subject) {
|
||||
return this.provider.createFunction(subject);
|
||||
}
|
||||
public PermissionSubject getSubject() {
|
||||
return this.subject;
|
||||
}
|
||||
|
||||
public PermissionProvider getProvider() {
|
||||
return this.provider;
|
||||
}
|
||||
/**
|
||||
* Uses the provider function to obtain a {@link PermissionFunction} for the subject.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @return the obtained permission function
|
||||
*/
|
||||
public PermissionFunction createFunction(PermissionSubject subject) {
|
||||
return this.provider.createFunction(subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link PermissionFunction} that should be used for the subject.
|
||||
*
|
||||
* <p>Specifying <code>null</code> will reset the provider to the default
|
||||
* instance given when the event was posted.</p>
|
||||
*
|
||||
* @param provider the provider
|
||||
*/
|
||||
public void setProvider(@Nullable PermissionProvider provider) {
|
||||
this.provider = provider == null ? this.defaultProvider : provider;
|
||||
}
|
||||
public PermissionProvider getProvider() {
|
||||
return this.provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PermissionsSetupEvent{" +
|
||||
"subject=" + subject +
|
||||
", defaultProvider=" + defaultProvider +
|
||||
", provider=" + provider +
|
||||
'}';
|
||||
}
|
||||
/**
|
||||
* Sets the {@link PermissionFunction} that should be used for the subject.
|
||||
*
|
||||
* <p>Specifying <code>null</code> will reset the provider to the default
|
||||
* instance given when the event was posted.</p>
|
||||
*
|
||||
* @param provider the provider
|
||||
*/
|
||||
public void setProvider(@Nullable PermissionProvider provider) {
|
||||
this.provider = provider == null ? this.defaultProvider : provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PermissionsSetupEvent{" +
|
||||
"subject=" + subject +
|
||||
", defaultProvider=" + defaultProvider +
|
||||
", provider=" + provider +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -6,65 +6,73 @@ 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
|
||||
* game profile for the user. This can be used to configure a custom profile for a user, i.e. skin replacement.
|
||||
* This event is fired after the {@link com.velocitypowered.api.event.connection.PreLoginEvent} in
|
||||
* order to set up the game profile for the user. This can be used to configure a custom profile for
|
||||
* a user, i.e. skin replacement.
|
||||
*/
|
||||
public final class GameProfileRequestEvent {
|
||||
private final String username;
|
||||
private final InboundConnection connection;
|
||||
private final GameProfile originalProfile;
|
||||
private final boolean onlineMode;
|
||||
private @Nullable GameProfile gameProfile;
|
||||
|
||||
public GameProfileRequestEvent(InboundConnection connection, GameProfile originalProfile, boolean onlineMode) {
|
||||
this.connection = Preconditions.checkNotNull(connection, "connection");
|
||||
this.originalProfile = Preconditions.checkNotNull(originalProfile, "originalProfile");
|
||||
this.username = originalProfile.getName();
|
||||
this.onlineMode = onlineMode;
|
||||
}
|
||||
private final String username;
|
||||
private final InboundConnection connection;
|
||||
private final GameProfile originalProfile;
|
||||
private final boolean onlineMode;
|
||||
private @Nullable GameProfile gameProfile;
|
||||
|
||||
public InboundConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
public GameProfileRequestEvent(InboundConnection connection, GameProfile originalProfile,
|
||||
boolean onlineMode) {
|
||||
this.connection = Preconditions.checkNotNull(connection, "connection");
|
||||
this.originalProfile = Preconditions.checkNotNull(originalProfile, "originalProfile");
|
||||
this.username = originalProfile.getName();
|
||||
this.onlineMode = onlineMode;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public GameProfile getOriginalProfile() {
|
||||
return originalProfile;
|
||||
}
|
||||
|
||||
public boolean isOnlineMode() {
|
||||
return onlineMode;
|
||||
}
|
||||
public InboundConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the game profile that will be used to initialize the connection with. Should no profile be currently
|
||||
* specified, the one generated by the proxy (for offline mode) or retrieved from the Mojang session servers (for
|
||||
* online mode) will be returned instead.
|
||||
* @return the user's {@link GameProfile}
|
||||
*/
|
||||
public GameProfile getGameProfile() {
|
||||
return gameProfile == null ? originalProfile : gameProfile;
|
||||
}
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public GameProfile getOriginalProfile() {
|
||||
return originalProfile;
|
||||
}
|
||||
|
||||
public boolean isOnlineMode() {
|
||||
return onlineMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the game profile that will be used to initialize the connection with. Should no profile
|
||||
* be currently specified, the one generated by the proxy (for offline mode) or retrieved from the
|
||||
* Mojang session servers (for online mode) will be returned instead.
|
||||
*
|
||||
* @return the user's {@link GameProfile}
|
||||
*/
|
||||
public GameProfile getGameProfile() {
|
||||
return gameProfile == null ? originalProfile : gameProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the game profile to use for this connection. It is invalid to use this method on an
|
||||
* online-mode connection.
|
||||
*
|
||||
* @param gameProfile the profile to use for the connection, {@code null} uses the original
|
||||
* profile
|
||||
*/
|
||||
public void setGameProfile(@Nullable GameProfile gameProfile) {
|
||||
Preconditions
|
||||
.checkState(!onlineMode, "Connection is in online mode, profiles can not be faked");
|
||||
this.gameProfile = gameProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GameProfileRequestEvent{" +
|
||||
"username=" + username +
|
||||
", gameProfile=" + gameProfile +
|
||||
"}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the game profile to use for this connection. It is invalid to use this method on an online-mode connection.
|
||||
* @param gameProfile the profile to use for the connection, {@code null} uses the original profile
|
||||
*/
|
||||
public void setGameProfile(@Nullable GameProfile gameProfile) {
|
||||
Preconditions.checkState(!onlineMode, "Connection is in online mode, profiles can not be faked");
|
||||
this.gameProfile = gameProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GameProfileRequestEvent{"+
|
||||
"username=" + username +
|
||||
", gameProfile=" + gameProfile +
|
||||
"}";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -8,111 +8,120 @@ import net.kyori.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
* Fired when a player is kicked from a server. You may either allow Velocity to kick the player (with an optional reason
|
||||
* override) or redirect the player to a separate server.
|
||||
* Fired when a player is kicked from a server. You may either allow Velocity to kick the player
|
||||
* (with an optional reason override) or redirect the player to a separate server.
|
||||
*/
|
||||
public final class KickedFromServerEvent implements ResultedEvent<KickedFromServerEvent.ServerKickResult> {
|
||||
private final Player player;
|
||||
public final class KickedFromServerEvent implements
|
||||
ResultedEvent<KickedFromServerEvent.ServerKickResult> {
|
||||
|
||||
private final Player player;
|
||||
private final RegisteredServer server;
|
||||
private final Component originalReason;
|
||||
private final boolean duringLogin;
|
||||
private ServerKickResult result;
|
||||
|
||||
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");
|
||||
this.duringLogin = duringLogin;
|
||||
this.result = new DisconnectPlayer(fancyReason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerKickResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(@NonNull ServerKickResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public RegisteredServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public Component getOriginalReason() {
|
||||
return originalReason;
|
||||
}
|
||||
|
||||
public boolean kickedDuringLogin() {
|
||||
return duringLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the base interface for {@link KickedFromServerEvent} results.
|
||||
*/
|
||||
public interface ServerKickResult extends ResultedEvent.Result {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the proxy to disconnect the player with the specified reason.
|
||||
*/
|
||||
public static final class DisconnectPlayer implements ServerKickResult {
|
||||
|
||||
private final Component component;
|
||||
|
||||
private DisconnectPlayer(Component component) {
|
||||
this.component = Preconditions.checkNotNull(component, "component");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Component getReason() {
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DisconnectPlayer} with the specified reason.
|
||||
*
|
||||
* @param reason the reason to use when disconnecting the player
|
||||
* @return the disconnect result
|
||||
*/
|
||||
public static DisconnectPlayer create(Component reason) {
|
||||
return new DisconnectPlayer(reason);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the proxy to redirect the player to another server. No messages will be sent from the
|
||||
* proxy when this result is used.
|
||||
*/
|
||||
public static final class RedirectPlayer implements ServerKickResult {
|
||||
|
||||
private final RegisteredServer server;
|
||||
private final Component originalReason;
|
||||
private final boolean duringLogin;
|
||||
private ServerKickResult result;
|
||||
|
||||
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");
|
||||
this.duringLogin = duringLogin;
|
||||
this.result = new DisconnectPlayer(fancyReason);
|
||||
private RedirectPlayer(RegisteredServer server) {
|
||||
this.server = Preconditions.checkNotNull(server, "server");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerKickResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(@NonNull ServerKickResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
public boolean isAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public RegisteredServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public Component getOriginalReason() {
|
||||
return originalReason;
|
||||
}
|
||||
|
||||
public boolean kickedDuringLogin() {
|
||||
return duringLogin;
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the base interface for {@link KickedFromServerEvent} results.
|
||||
* Creates a new redirect result to forward the player to the specified {@code server}.
|
||||
*
|
||||
* @param server the server to send the player to
|
||||
* @return the redirect result
|
||||
*/
|
||||
public interface ServerKickResult extends ResultedEvent.Result {}
|
||||
|
||||
/**
|
||||
* Tells the proxy to disconnect the player with the specified reason.
|
||||
*/
|
||||
public static final class DisconnectPlayer implements ServerKickResult {
|
||||
private final Component component;
|
||||
|
||||
private DisconnectPlayer(Component component) {
|
||||
this.component = Preconditions.checkNotNull(component, "component");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Component getReason() {
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DisconnectPlayer} with the specified reason.
|
||||
* @param reason the reason to use when disconnecting the player
|
||||
* @return the disconnect result
|
||||
*/
|
||||
public static DisconnectPlayer create(Component reason) {
|
||||
return new DisconnectPlayer(reason);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the proxy to redirect the player to another server. No messages will be sent from the proxy
|
||||
* when this result is used.
|
||||
*/
|
||||
public static final class RedirectPlayer implements ServerKickResult {
|
||||
private final RegisteredServer server;
|
||||
|
||||
private RedirectPlayer(RegisteredServer server) {
|
||||
this.server = Preconditions.checkNotNull(server, "server");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public RegisteredServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new redirect result to forward the player to the specified {@code server}.
|
||||
* @param server the server to send the player to
|
||||
* @return the redirect result
|
||||
*/
|
||||
public static RedirectPlayer create(RegisteredServer server) {
|
||||
return new RedirectPlayer(server);
|
||||
}
|
||||
public static RedirectPlayer create(RegisteredServer server) {
|
||||
return new RedirectPlayer(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,95 +3,96 @@ 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 java.util.Optional;
|
||||
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 types in a chat message.
|
||||
*/
|
||||
public final class PlayerChatEvent implements ResultedEvent<PlayerChatEvent.ChatResult> {
|
||||
private final Player player;
|
||||
private final String message;
|
||||
private ChatResult result;
|
||||
|
||||
public PlayerChatEvent(Player player, String message) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.message = Preconditions.checkNotNull(message, "message");
|
||||
this.result = ChatResult.allowed();
|
||||
}
|
||||
private final Player player;
|
||||
private final String message;
|
||||
private ChatResult result;
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
public PlayerChatEvent(Player player, String message) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.message = Preconditions.checkNotNull(message, "message");
|
||||
this.result = ChatResult.allowed();
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(ChatResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlayerChatEvent{" +
|
||||
"player=" + player +
|
||||
", message=" + message +
|
||||
", result=" + result +
|
||||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the result of the {@link PlayerChatEvent}.
|
||||
*/
|
||||
public static final class ChatResult implements ResultedEvent.Result {
|
||||
|
||||
private static final ChatResult ALLOWED = new ChatResult(true, null);
|
||||
private static final ChatResult DENIED = new ChatResult(false, null);
|
||||
|
||||
// The server can not accept formatted text from clients!
|
||||
private @Nullable String message;
|
||||
private final boolean status;
|
||||
|
||||
protected ChatResult(boolean status, @Nullable String message) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(ChatResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
public boolean isAllowed() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlayerChatEvent{" +
|
||||
"player=" + player +
|
||||
", message=" + message +
|
||||
", result=" + result +
|
||||
'}';
|
||||
return status ? "allowed" : "denied";
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the result of the {@link PlayerChatEvent}.
|
||||
*/
|
||||
public static final class ChatResult implements ResultedEvent.Result {
|
||||
private static final ChatResult ALLOWED = new ChatResult(true, null);
|
||||
private static final ChatResult DENIED = new ChatResult(false, null);
|
||||
|
||||
// The server can not accept formatted text from clients!
|
||||
private @Nullable String message;
|
||||
private final boolean status;
|
||||
|
||||
protected ChatResult(boolean status, @Nullable String message) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return status ? "allowed" : "denied";
|
||||
}
|
||||
|
||||
public static ChatResult allowed() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
public static ChatResult denied() {
|
||||
return DENIED;
|
||||
}
|
||||
|
||||
public Optional<String> getMessage() {
|
||||
return Optional.ofNullable(message);
|
||||
}
|
||||
|
||||
public static ChatResult message(@NonNull String message) {
|
||||
Preconditions.checkNotNull(message, "message");
|
||||
return new ChatResult(true, message);
|
||||
}
|
||||
public static ChatResult allowed() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
public static ChatResult denied() {
|
||||
return DENIED;
|
||||
}
|
||||
|
||||
public Optional<String> getMessage() {
|
||||
return Optional.ofNullable(message);
|
||||
}
|
||||
|
||||
public static ChatResult message(@NonNull String message) {
|
||||
Preconditions.checkNotNull(message, "message");
|
||||
return new ChatResult(true, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -8,19 +8,20 @@ import com.velocitypowered.api.util.ModInfo;
|
||||
* This event is fired when the players ModInfo is changed.
|
||||
*/
|
||||
public final class PlayerModInfoEvent {
|
||||
private final Player player;
|
||||
private final ModInfo modInfo;
|
||||
|
||||
public PlayerModInfoEvent(Player player, ModInfo modInfo) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.modInfo = Preconditions.checkNotNull(modInfo, "modInfo");
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public ModInfo getModInfo() {
|
||||
return modInfo;
|
||||
}
|
||||
|
||||
private final Player player;
|
||||
private final ModInfo modInfo;
|
||||
|
||||
public PlayerModInfoEvent(Player player, ModInfo modInfo) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.modInfo = Preconditions.checkNotNull(modInfo, "modInfo");
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public ModInfo getModInfo() {
|
||||
return modInfo;
|
||||
}
|
||||
}
|
||||
|
@ -5,19 +5,20 @@ import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.player.PlayerSettings;
|
||||
|
||||
public final class PlayerSettingsChangedEvent {
|
||||
private final Player player;
|
||||
private final PlayerSettings playerSettings;
|
||||
|
||||
public PlayerSettingsChangedEvent(Player player, PlayerSettings playerSettings) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.playerSettings = Preconditions.checkNotNull(playerSettings, "playerSettings");
|
||||
}
|
||||
private final Player player;
|
||||
private final PlayerSettings playerSettings;
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
public PlayerSettingsChangedEvent(Player player, PlayerSettings playerSettings) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.playerSettings = Preconditions.checkNotNull(playerSettings, "playerSettings");
|
||||
}
|
||||
|
||||
public PlayerSettings getPlayerSettings() {
|
||||
return playerSettings;
|
||||
}
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public PlayerSettings getPlayerSettings() {
|
||||
return playerSettings;
|
||||
}
|
||||
}
|
||||
|
@ -5,31 +5,32 @@ import com.velocitypowered.api.proxy.Player;
|
||||
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
|
||||
* server has been de-established.
|
||||
* This event is fired once the player has successfully connected to the target server and the
|
||||
* connection to the previous server has been de-established.
|
||||
*/
|
||||
public final class ServerConnectedEvent {
|
||||
private final Player player;
|
||||
private final RegisteredServer server;
|
||||
|
||||
public ServerConnectedEvent(Player player, RegisteredServer server) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.server = Preconditions.checkNotNull(server, "server");
|
||||
}
|
||||
private final Player player;
|
||||
private final RegisteredServer server;
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
public ServerConnectedEvent(Player player, RegisteredServer server) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.server = Preconditions.checkNotNull(server, "server");
|
||||
}
|
||||
|
||||
public RegisteredServer getServer() {
|
||||
return server;
|
||||
}
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerConnectedEvent{" +
|
||||
"player=" + player +
|
||||
", server=" + server +
|
||||
'}';
|
||||
}
|
||||
public RegisteredServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerConnectedEvent{" +
|
||||
"player=" + player +
|
||||
", server=" + server +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -4,87 +4,89 @@ import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.event.ResultedEvent;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* This event is fired before the player connects to a server.
|
||||
*/
|
||||
public final class ServerPreConnectEvent implements ResultedEvent<ServerPreConnectEvent.ServerResult> {
|
||||
private final Player player;
|
||||
private final RegisteredServer originalServer;
|
||||
private ServerResult result;
|
||||
public final class ServerPreConnectEvent implements
|
||||
ResultedEvent<ServerPreConnectEvent.ServerResult> {
|
||||
|
||||
public ServerPreConnectEvent(Player player, RegisteredServer originalServer) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.originalServer = Preconditions.checkNotNull(originalServer, "originalServer");
|
||||
this.result = ServerResult.allowed(originalServer);
|
||||
}
|
||||
private final Player player;
|
||||
private final RegisteredServer originalServer;
|
||||
private ServerResult result;
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
public ServerPreConnectEvent(Player player, RegisteredServer originalServer) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.originalServer = Preconditions.checkNotNull(originalServer, "originalServer");
|
||||
this.result = ServerResult.allowed(originalServer);
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(ServerResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
}
|
||||
|
||||
public RegisteredServer getOriginalServer() {
|
||||
return originalServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerPreConnectEvent{" +
|
||||
"player=" + player +
|
||||
", originalServer=" + originalServer +
|
||||
", result=" + result +
|
||||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the result of the {@link ServerPreConnectEvent}.
|
||||
*/
|
||||
public static class ServerResult implements ResultedEvent.Result {
|
||||
|
||||
private static final ServerResult DENIED = new ServerResult(null);
|
||||
|
||||
private final @Nullable RegisteredServer server;
|
||||
|
||||
private ServerResult(@Nullable RegisteredServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerResult getResult() {
|
||||
return result;
|
||||
public boolean isAllowed() {
|
||||
return server != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(ServerResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
}
|
||||
|
||||
public RegisteredServer getOriginalServer() {
|
||||
return originalServer;
|
||||
public Optional<RegisteredServer> getServer() {
|
||||
return Optional.ofNullable(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerPreConnectEvent{" +
|
||||
"player=" + player +
|
||||
", originalServer=" + originalServer +
|
||||
", result=" + result +
|
||||
'}';
|
||||
if (server != null) {
|
||||
return "allowed: connect to " + server.getServerInfo().getName();
|
||||
}
|
||||
return "denied";
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the result of the {@link ServerPreConnectEvent}.
|
||||
*/
|
||||
public static class ServerResult implements ResultedEvent.Result {
|
||||
private static final ServerResult DENIED = new ServerResult(null);
|
||||
|
||||
private final @Nullable RegisteredServer server;
|
||||
|
||||
private ServerResult(@Nullable RegisteredServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return server != null;
|
||||
}
|
||||
|
||||
public Optional<RegisteredServer> getServer() {
|
||||
return Optional.ofNullable(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (server != null) {
|
||||
return "allowed: connect to " + server.getServerInfo().getName();
|
||||
}
|
||||
return "denied";
|
||||
}
|
||||
|
||||
public static ServerResult denied() {
|
||||
return DENIED;
|
||||
}
|
||||
|
||||
public static ServerResult allowed(RegisteredServer server) {
|
||||
Preconditions.checkNotNull(server, "server");
|
||||
return new ServerResult(server);
|
||||
}
|
||||
public static ServerResult denied() {
|
||||
return DENIED;
|
||||
}
|
||||
|
||||
public static ServerResult allowed(RegisteredServer server) {
|
||||
Preconditions.checkNotNull(server, "server");
|
||||
return new ServerResult(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
package com.velocitypowered.api.event.proxy;
|
||||
|
||||
/**
|
||||
* This event is fired by the proxy after plugins have been loaded but before the proxy starts accepting connections.
|
||||
* This event is fired by the proxy after plugins have been loaded but before the proxy starts
|
||||
* accepting connections.
|
||||
*/
|
||||
public final class ProxyInitializeEvent {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyInitializeEvent";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyInitializeEvent";
|
||||
}
|
||||
}
|
||||
|
@ -8,31 +8,32 @@ import com.velocitypowered.api.proxy.server.ServerPing;
|
||||
* This event is fired when a server list ping request is sent by a remote client.
|
||||
*/
|
||||
public final class ProxyPingEvent {
|
||||
private final InboundConnection connection;
|
||||
private ServerPing ping;
|
||||
|
||||
public ProxyPingEvent(InboundConnection connection, ServerPing ping) {
|
||||
this.connection = Preconditions.checkNotNull(connection, "connection");
|
||||
this.ping = Preconditions.checkNotNull(ping, "ping");
|
||||
}
|
||||
private final InboundConnection connection;
|
||||
private ServerPing ping;
|
||||
|
||||
public InboundConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
public ProxyPingEvent(InboundConnection connection, ServerPing ping) {
|
||||
this.connection = Preconditions.checkNotNull(connection, "connection");
|
||||
this.ping = Preconditions.checkNotNull(ping, "ping");
|
||||
}
|
||||
|
||||
public ServerPing getPing() {
|
||||
return ping;
|
||||
}
|
||||
public InboundConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
public void setPing(ServerPing ping) {
|
||||
this.ping = Preconditions.checkNotNull(ping, "ping");
|
||||
}
|
||||
public ServerPing getPing() {
|
||||
return ping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyPingEvent{" +
|
||||
"connection=" + connection +
|
||||
", ping=" + ping +
|
||||
'}';
|
||||
}
|
||||
public void setPing(ServerPing ping) {
|
||||
this.ping = Preconditions.checkNotNull(ping, "ping");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyPingEvent{" +
|
||||
"connection=" + connection +
|
||||
", ping=" + ping +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
package com.velocitypowered.api.event.proxy;
|
||||
|
||||
/**
|
||||
* This event is fired by the proxy after the proxy has stopped accepting connections but before the proxy process
|
||||
* exits.
|
||||
* This event is fired by the proxy after the proxy has stopped accepting connections but before the
|
||||
* proxy process exits.
|
||||
*/
|
||||
public final class ProxyShutdownEvent {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyShutdownEvent";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyShutdownEvent";
|
||||
}
|
||||
}
|
||||
|
@ -2,82 +2,86 @@ package com.velocitypowered.api.event.query;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.proxy.server.QueryResponse;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
* This event is fired if proxy is getting queried over GS4 Query protocol
|
||||
*/
|
||||
public final class ProxyQueryEvent {
|
||||
private final QueryType queryType;
|
||||
private final InetAddress querierAddress;
|
||||
private QueryResponse response;
|
||||
|
||||
public ProxyQueryEvent(QueryType queryType, InetAddress querierAddress, QueryResponse response) {
|
||||
this.queryType = Preconditions.checkNotNull(queryType, "queryType");
|
||||
this.querierAddress = Preconditions.checkNotNull(querierAddress, "querierAddress");
|
||||
this.response = Preconditions.checkNotNull(response, "response");
|
||||
}
|
||||
private final QueryType queryType;
|
||||
private final InetAddress querierAddress;
|
||||
private QueryResponse response;
|
||||
|
||||
public ProxyQueryEvent(QueryType queryType, InetAddress querierAddress, QueryResponse response) {
|
||||
this.queryType = Preconditions.checkNotNull(queryType, "queryType");
|
||||
this.querierAddress = Preconditions.checkNotNull(querierAddress, "querierAddress");
|
||||
this.response = Preconditions.checkNotNull(response, "response");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query type
|
||||
*
|
||||
* @return query type
|
||||
*/
|
||||
@NonNull
|
||||
public QueryType getQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get querier address
|
||||
*
|
||||
* @return querier address
|
||||
*/
|
||||
@NonNull
|
||||
public InetAddress getQuerierAddress() {
|
||||
return querierAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query response
|
||||
*
|
||||
* @return query response
|
||||
*/
|
||||
@NonNull
|
||||
public QueryResponse getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set query response
|
||||
*
|
||||
* @param response query response
|
||||
*/
|
||||
public void setResponse(@NonNull QueryResponse response) {
|
||||
this.response = Preconditions.checkNotNull(response, "response");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyQueryEvent{" +
|
||||
"queryType=" + queryType +
|
||||
", querierAddress=" + querierAddress +
|
||||
", response=" + response +
|
||||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of query
|
||||
*/
|
||||
public enum QueryType {
|
||||
/**
|
||||
* Basic query asks only a subset of information, such as hostname, game type (hardcoded to
|
||||
* <pre>MINECRAFT</pre>), map, current players, max players, proxy port and proxy hostname
|
||||
*/
|
||||
BASIC,
|
||||
|
||||
/**
|
||||
* Get query type
|
||||
* @return query type
|
||||
* Full query asks pretty much everything present on this event (only hardcoded values cannot be
|
||||
* modified here).
|
||||
*/
|
||||
@NonNull
|
||||
public QueryType getQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get querier address
|
||||
* @return querier address
|
||||
*/
|
||||
@NonNull
|
||||
public InetAddress getQuerierAddress() {
|
||||
return querierAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query response
|
||||
* @return query response
|
||||
*/
|
||||
@NonNull
|
||||
public QueryResponse getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set query response
|
||||
* @param response query response
|
||||
*/
|
||||
public void setResponse(@NonNull QueryResponse response) {
|
||||
this.response = Preconditions.checkNotNull(response, "response");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyQueryEvent{" +
|
||||
"queryType=" + queryType +
|
||||
", querierAddress=" + querierAddress +
|
||||
", response=" + response +
|
||||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of query
|
||||
*/
|
||||
public enum QueryType {
|
||||
/**
|
||||
* Basic query asks only a subset of information, such as hostname, game type (hardcoded to <pre>MINECRAFT</pre>), map,
|
||||
* current players, max players, proxy port and proxy hostname
|
||||
*/
|
||||
BASIC,
|
||||
|
||||
/**
|
||||
* Full query asks pretty much everything present on this event (only hardcoded values cannot be modified here).
|
||||
*/
|
||||
FULL
|
||||
;
|
||||
}
|
||||
FULL;
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
package com.velocitypowered.api.permission;
|
||||
|
||||
/**
|
||||
* Function that calculates the permission settings for a given
|
||||
* {@link PermissionSubject}.
|
||||
* Function that calculates the permission settings for a given {@link PermissionSubject}.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PermissionFunction {
|
||||
/**
|
||||
* A permission function that always returns {@link Tristate#TRUE}.
|
||||
*/
|
||||
PermissionFunction ALWAYS_TRUE = p -> Tristate.TRUE;
|
||||
|
||||
/**
|
||||
* A permission function that always returns {@link Tristate#FALSE}.
|
||||
*/
|
||||
PermissionFunction ALWAYS_FALSE = p -> Tristate.FALSE;
|
||||
/**
|
||||
* A permission function that always returns {@link Tristate#TRUE}.
|
||||
*/
|
||||
PermissionFunction ALWAYS_TRUE = p -> Tristate.TRUE;
|
||||
|
||||
/**
|
||||
* A permission function that always returns {@link Tristate#UNDEFINED}.
|
||||
*/
|
||||
PermissionFunction ALWAYS_UNDEFINED = p -> Tristate.UNDEFINED;
|
||||
/**
|
||||
* A permission function that always returns {@link Tristate#FALSE}.
|
||||
*/
|
||||
PermissionFunction ALWAYS_FALSE = p -> Tristate.FALSE;
|
||||
|
||||
/**
|
||||
* Gets the subjects setting for a particular permission.
|
||||
*
|
||||
* @param permission the permission
|
||||
* @return the value the permission is set to
|
||||
*/
|
||||
Tristate getPermissionValue(String permission);
|
||||
/**
|
||||
* A permission function that always returns {@link Tristate#UNDEFINED}.
|
||||
*/
|
||||
PermissionFunction ALWAYS_UNDEFINED = p -> Tristate.UNDEFINED;
|
||||
|
||||
/**
|
||||
* Gets the subjects setting for a particular permission.
|
||||
*
|
||||
* @param permission the permission
|
||||
* @return the value the permission is set to
|
||||
*/
|
||||
Tristate getPermissionValue(String permission);
|
||||
}
|
||||
|
@ -5,11 +5,12 @@ package com.velocitypowered.api.permission;
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PermissionProvider {
|
||||
/**
|
||||
* Creates a {@link PermissionFunction} for the subject.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @return the function
|
||||
*/
|
||||
PermissionFunction createFunction(PermissionSubject subject);
|
||||
|
||||
/**
|
||||
* Creates a {@link PermissionFunction} for the subject.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @return the function
|
||||
*/
|
||||
PermissionFunction createFunction(PermissionSubject subject);
|
||||
}
|
||||
|
@ -4,21 +4,22 @@ package com.velocitypowered.api.permission;
|
||||
* Represents a object that has a set of queryable permissions.
|
||||
*/
|
||||
public interface PermissionSubject {
|
||||
/**
|
||||
* Determines whether or not the subject has a particular permission.
|
||||
*
|
||||
* @param permission the permission to check for
|
||||
* @return whether or not the subject has the permission
|
||||
*/
|
||||
default boolean hasPermission(String permission) {
|
||||
return getPermissionValue(permission).asBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subjects setting for a particular permission.
|
||||
*
|
||||
* @param permission the permission
|
||||
* @return the value the permission is set to
|
||||
*/
|
||||
Tristate getPermissionValue(String permission);
|
||||
/**
|
||||
* Determines whether or not the subject has a particular permission.
|
||||
*
|
||||
* @param permission the permission to check for
|
||||
* @return whether or not the subject has the permission
|
||||
*/
|
||||
default boolean hasPermission(String permission) {
|
||||
return getPermissionValue(permission).asBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subjects setting for a particular permission.
|
||||
*
|
||||
* @param permission the permission
|
||||
* @return the value the permission is set to
|
||||
*/
|
||||
Tristate getPermissionValue(String permission);
|
||||
}
|
||||
|
@ -8,69 +8,70 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
* <p>Possible values:</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link #TRUE} - a positive setting</li>
|
||||
* <li>{@link #FALSE} - a negative (negated) setting</li>
|
||||
* <li>{@link #UNDEFINED} - a non-existent setting</li>
|
||||
* <li>{@link #TRUE} - a positive setting</li>
|
||||
* <li>{@link #FALSE} - a negative (negated) setting</li>
|
||||
* <li>{@link #UNDEFINED} - a non-existent setting</li>
|
||||
* </ul>
|
||||
*/
|
||||
public enum Tristate {
|
||||
|
||||
/**
|
||||
* A value indicating a positive setting
|
||||
*/
|
||||
TRUE(true),
|
||||
/**
|
||||
* A value indicating a positive setting
|
||||
*/
|
||||
TRUE(true),
|
||||
|
||||
/**
|
||||
* A value indicating a negative (negated) setting
|
||||
*/
|
||||
FALSE(false),
|
||||
/**
|
||||
* A value indicating a negative (negated) setting
|
||||
*/
|
||||
FALSE(false),
|
||||
|
||||
/**
|
||||
* A value indicating a non-existent setting
|
||||
*/
|
||||
UNDEFINED(false);
|
||||
/**
|
||||
* A value indicating a non-existent setting
|
||||
*/
|
||||
UNDEFINED(false);
|
||||
|
||||
/**
|
||||
* Returns a {@link Tristate} from a boolean
|
||||
*
|
||||
* @param val the boolean value
|
||||
* @return {@link #TRUE} or {@link #FALSE}, if the value is <code>true</code> or <code>false</code>, respectively.
|
||||
*/
|
||||
public static Tristate fromBoolean(boolean val) {
|
||||
return val ? TRUE : FALSE;
|
||||
/**
|
||||
* Returns a {@link Tristate} from a boolean
|
||||
*
|
||||
* @param val the boolean value
|
||||
* @return {@link #TRUE} or {@link #FALSE}, if the value is <code>true</code> or
|
||||
* <code>false</code>, respectively.
|
||||
*/
|
||||
public static Tristate fromBoolean(boolean val) {
|
||||
return val ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Tristate} from a nullable boolean.
|
||||
*
|
||||
* <p>Unlike {@link #fromBoolean(boolean)}, this method returns {@link #UNDEFINED}
|
||||
* if the value is null.</p>
|
||||
*
|
||||
* @param val the boolean value
|
||||
* @return {@link #UNDEFINED}, {@link #TRUE} or {@link #FALSE}, if the value is <code>null</code>,
|
||||
* <code>true</code> or <code>false</code>, respectively.
|
||||
*/
|
||||
public static Tristate fromNullableBoolean(@Nullable Boolean val) {
|
||||
if (val == null) {
|
||||
return UNDEFINED;
|
||||
}
|
||||
return val ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Tristate} from a nullable boolean.
|
||||
*
|
||||
* <p>Unlike {@link #fromBoolean(boolean)}, this method returns {@link #UNDEFINED}
|
||||
* if the value is null.</p>
|
||||
*
|
||||
* @param val the boolean value
|
||||
* @return {@link #UNDEFINED}, {@link #TRUE} or {@link #FALSE}, if the value
|
||||
* is <code>null</code>, <code>true</code> or <code>false</code>, respectively.
|
||||
*/
|
||||
public static Tristate fromNullableBoolean(@Nullable Boolean val) {
|
||||
if (val == null) {
|
||||
return UNDEFINED;
|
||||
}
|
||||
return val ? TRUE : FALSE;
|
||||
}
|
||||
private final boolean booleanValue;
|
||||
|
||||
private final boolean booleanValue;
|
||||
Tristate(boolean booleanValue) {
|
||||
this.booleanValue = booleanValue;
|
||||
}
|
||||
|
||||
Tristate(boolean booleanValue) {
|
||||
this.booleanValue = booleanValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the Tristate as a boolean.
|
||||
*
|
||||
* <p>A value of {@link #UNDEFINED} converts to false.</p>
|
||||
*
|
||||
* @return a boolean representation of the Tristate.
|
||||
*/
|
||||
public boolean asBoolean() {
|
||||
return this.booleanValue;
|
||||
}
|
||||
/**
|
||||
* Returns the value of the Tristate as a boolean.
|
||||
*
|
||||
* <p>A value of {@link #UNDEFINED} converts to false.</p>
|
||||
*
|
||||
* @return a boolean representation of the Tristate.
|
||||
*/
|
||||
public boolean asBoolean() {
|
||||
return this.booleanValue;
|
||||
}
|
||||
}
|
||||
|
@ -10,19 +10,19 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({})
|
||||
public @interface Dependency {
|
||||
/**
|
||||
* The plugin ID of the dependency.
|
||||
*
|
||||
* @return The dependency plugin ID
|
||||
* @see Plugin#id()
|
||||
*/
|
||||
String id();
|
||||
|
||||
/**
|
||||
* If this dependency is optional for the plugin to work. By default
|
||||
* this is {@code false}.
|
||||
*
|
||||
* @return true if the dependency is optional for the plugin to work
|
||||
*/
|
||||
boolean optional() default false;
|
||||
/**
|
||||
* The plugin ID of the dependency.
|
||||
*
|
||||
* @return The dependency plugin ID
|
||||
* @see Plugin#id()
|
||||
*/
|
||||
String id();
|
||||
|
||||
/**
|
||||
* If this dependency is optional for the plugin to work. By default this is {@code false}.
|
||||
*
|
||||
* @return true if the dependency is optional for the plugin to work
|
||||
*/
|
||||
boolean optional() default false;
|
||||
}
|
||||
|
@ -1,19 +1,20 @@
|
||||
package com.velocitypowered.api.plugin;
|
||||
|
||||
public class InvalidPluginException extends Exception {
|
||||
public InvalidPluginException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InvalidPluginException(String message) {
|
||||
super(message);
|
||||
}
|
||||
public InvalidPluginException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InvalidPluginException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
public InvalidPluginException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidPluginException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
public InvalidPluginException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public InvalidPluginException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
@ -11,56 +11,55 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Plugin {
|
||||
/**
|
||||
* The ID of the plugin. This ID should be unique as to
|
||||
* not conflict with other plugins.
|
||||
*
|
||||
* The plugin ID must match the {@link PluginDescription#ID_PATTERN}.
|
||||
*
|
||||
* @return the ID for this plugin
|
||||
*/
|
||||
String id();
|
||||
|
||||
/**
|
||||
* The human readable name of the plugin as to be used in descriptions and
|
||||
* similar things.
|
||||
*
|
||||
* @return The plugin name, or an empty string if unknown
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* The ID of the plugin. This ID should be unique as to not conflict with other plugins.
|
||||
*
|
||||
* The plugin ID must match the {@link PluginDescription#ID_PATTERN}.
|
||||
*
|
||||
* @return the ID for this plugin
|
||||
*/
|
||||
String id();
|
||||
|
||||
/**
|
||||
* The version of the plugin.
|
||||
*
|
||||
* @return the version of the plugin, or an empty string if unknown
|
||||
*/
|
||||
String version() default "";
|
||||
/**
|
||||
* The human readable name of the plugin as to be used in descriptions and similar things.
|
||||
*
|
||||
* @return The plugin name, or an empty string if unknown
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* The description of the plugin, explaining what it can be used for.
|
||||
*
|
||||
* @return The plugin description, or an empty string if unknown
|
||||
*/
|
||||
String description() default "";
|
||||
/**
|
||||
* The version of the plugin.
|
||||
*
|
||||
* @return the version of the plugin, or an empty string if unknown
|
||||
*/
|
||||
String version() default "";
|
||||
|
||||
/**
|
||||
* The URL or website of the plugin.
|
||||
*
|
||||
* @return The plugin url, or an empty string if unknown
|
||||
*/
|
||||
String url() default "";
|
||||
/**
|
||||
* The description of the plugin, explaining what it can be used for.
|
||||
*
|
||||
* @return The plugin description, or an empty string if unknown
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* The author of the plugin.
|
||||
*
|
||||
* @return the plugin's author, or empty if unknown
|
||||
*/
|
||||
String[] authors() default "";
|
||||
/**
|
||||
* The URL or website of the plugin.
|
||||
*
|
||||
* @return The plugin url, or an empty string if unknown
|
||||
*/
|
||||
String url() default "";
|
||||
|
||||
/**
|
||||
* The dependencies required to load before this plugin.
|
||||
*
|
||||
* @return the plugin dependencies
|
||||
*/
|
||||
Dependency[] dependencies() default {};
|
||||
/**
|
||||
* The author of the plugin.
|
||||
*
|
||||
* @return the plugin's author, or empty if unknown
|
||||
*/
|
||||
String[] authors() default "";
|
||||
|
||||
/**
|
||||
* The dependencies required to load before this plugin.
|
||||
*
|
||||
* @return the plugin dependencies
|
||||
*/
|
||||
Dependency[] dependencies() default {};
|
||||
}
|
||||
|
@ -6,19 +6,20 @@ import java.util.Optional;
|
||||
* A wrapper around a plugin loaded by the proxy.
|
||||
*/
|
||||
public interface PluginContainer {
|
||||
/**
|
||||
* Returns the plugin's description.
|
||||
*
|
||||
* @return the plugin's description
|
||||
*/
|
||||
PluginDescription getDescription();
|
||||
|
||||
/**
|
||||
* Returns the created plugin if it is available.
|
||||
*
|
||||
* @return the instance if available
|
||||
*/
|
||||
default Optional<?> getInstance() {
|
||||
return Optional.empty();
|
||||
}
|
||||
/**
|
||||
* Returns the plugin's description.
|
||||
*
|
||||
* @return the plugin's description
|
||||
*/
|
||||
PluginDescription getDescription();
|
||||
|
||||
/**
|
||||
* Returns the created plugin if it is available.
|
||||
*
|
||||
* @return the instance if available
|
||||
*/
|
||||
default Optional<?> getInstance() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package com.velocitypowered.api.plugin;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.velocitypowered.api.plugin.meta.PluginDependency;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@ -14,93 +13,92 @@ import java.util.regex.Pattern;
|
||||
* Represents metadata for a specific version of a plugin.
|
||||
*/
|
||||
public interface PluginDescription {
|
||||
/**
|
||||
* The pattern plugin IDs must match. Plugin IDs may only contain
|
||||
* alphanumeric characters, dashes or underscores, must start with
|
||||
* an alphabetic character and cannot be longer than 64 characters.
|
||||
*/
|
||||
Pattern ID_PATTERN = Pattern.compile("[a-z][a-z0-9-_]{0,63}");
|
||||
|
||||
/**
|
||||
* Gets the qualified ID of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return the plugin ID
|
||||
* @see Plugin#id()
|
||||
*/
|
||||
String getId();
|
||||
/**
|
||||
* The pattern plugin IDs must match. Plugin IDs may only contain alphanumeric characters, dashes
|
||||
* or underscores, must start with an alphabetic character and cannot be longer than 64
|
||||
* characters.
|
||||
*/
|
||||
Pattern ID_PATTERN = Pattern.compile("[a-z][a-z0-9-_]{0,63}");
|
||||
|
||||
/**
|
||||
* Gets the name of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin name, may be empty
|
||||
* @see Plugin#name()
|
||||
*/
|
||||
default Optional<String> getName() {
|
||||
return Optional.empty();
|
||||
}
|
||||
/**
|
||||
* Gets the qualified ID of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return the plugin ID
|
||||
* @see Plugin#id()
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Gets the version of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin version, may be empty
|
||||
* @see Plugin#version()
|
||||
*/
|
||||
default Optional<String> getVersion() {
|
||||
return Optional.empty();
|
||||
}
|
||||
/**
|
||||
* Gets the name of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin name, may be empty
|
||||
* @see Plugin#name()
|
||||
*/
|
||||
default Optional<String> getName() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the description of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin description, may be empty
|
||||
* @see Plugin#description()
|
||||
*/
|
||||
default Optional<String> getDescription() {
|
||||
return Optional.empty();
|
||||
}
|
||||
/**
|
||||
* Gets the version of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin version, may be empty
|
||||
* @see Plugin#version()
|
||||
*/
|
||||
default Optional<String> getVersion() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the url or website of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin url, may be empty
|
||||
* @see Plugin#url()
|
||||
*/
|
||||
default Optional<String> getUrl() {
|
||||
return Optional.empty();
|
||||
}
|
||||
/**
|
||||
* Gets the description of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin description, may be empty
|
||||
* @see Plugin#description()
|
||||
*/
|
||||
default Optional<String> getDescription() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the authors of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return the plugin authors, may be empty
|
||||
* @see Plugin#authors()
|
||||
*/
|
||||
default List<String> getAuthors() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
/**
|
||||
* Gets the url or website of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin url, may be empty
|
||||
* @see Plugin#url()
|
||||
*/
|
||||
default Optional<String> getUrl() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link Collection} of all dependencies of the {@link Plugin} within
|
||||
* this container.
|
||||
*
|
||||
* @return the plugin dependencies, can be empty
|
||||
* @see Plugin#dependencies()
|
||||
*/
|
||||
default Collection<PluginDependency> getDependencies() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
/**
|
||||
* Gets the authors of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return the plugin authors, may be empty
|
||||
* @see Plugin#authors()
|
||||
*/
|
||||
default List<String> getAuthors() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
default Optional<PluginDependency> getDependency(String id) {
|
||||
return Optional.empty();
|
||||
}
|
||||
/**
|
||||
* Gets a {@link Collection} of all dependencies of the {@link Plugin} within this container.
|
||||
*
|
||||
* @return the plugin dependencies, can be empty
|
||||
* @see Plugin#dependencies()
|
||||
*/
|
||||
default Collection<PluginDependency> getDependencies() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source the plugin was loaded from.
|
||||
*
|
||||
* @return the source the plugin was loaded from or {@link Optional#empty()}
|
||||
* if unknown
|
||||
*/
|
||||
default Optional<Path> getSource() {
|
||||
return Optional.empty();
|
||||
}
|
||||
default Optional<PluginDependency> getDependency(String id) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source the plugin was loaded from.
|
||||
*
|
||||
* @return the source the plugin was loaded from or {@link Optional#empty()} if unknown
|
||||
*/
|
||||
default Optional<Path> getSource() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
@ -5,47 +5,49 @@ import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Manages plugins loaded on the proxy. This manager can retrieve {@link PluginContainer}s from plugin instances
|
||||
* and inject arbitrary JAR files into the plugin classpath with {@link #addToClasspath(Object, Path)}.
|
||||
* Manages plugins loaded on the proxy. This manager can retrieve {@link PluginContainer}s from
|
||||
* plugin instances and inject arbitrary JAR files into the plugin classpath with {@link
|
||||
* #addToClasspath(Object, Path)}.
|
||||
*/
|
||||
public interface PluginManager {
|
||||
/**
|
||||
* Gets the plugin container from an instance.
|
||||
*
|
||||
* @param instance the instance
|
||||
* @return the container
|
||||
*/
|
||||
Optional<PluginContainer> fromInstance(Object instance);
|
||||
|
||||
/**
|
||||
* Retrieves a {@link PluginContainer} based on its ID.
|
||||
*
|
||||
* @param id the plugin ID
|
||||
* @return the plugin, if available
|
||||
*/
|
||||
Optional<PluginContainer> getPlugin(String id);
|
||||
/**
|
||||
* Gets the plugin container from an instance.
|
||||
*
|
||||
* @param instance the instance
|
||||
* @return the container
|
||||
*/
|
||||
Optional<PluginContainer> fromInstance(Object instance);
|
||||
|
||||
/**
|
||||
* Gets a {@link Collection} of all {@link PluginContainer}s.
|
||||
*
|
||||
* @return the plugins
|
||||
*/
|
||||
Collection<PluginContainer> getPlugins();
|
||||
/**
|
||||
* Retrieves a {@link PluginContainer} based on its ID.
|
||||
*
|
||||
* @param id the plugin ID
|
||||
* @return the plugin, if available
|
||||
*/
|
||||
Optional<PluginContainer> getPlugin(String id);
|
||||
|
||||
/**
|
||||
* Checks if a plugin is loaded based on its ID.
|
||||
*
|
||||
* @param id the id of the plugin
|
||||
* @return {@code true} if loaded
|
||||
*/
|
||||
boolean isLoaded(String id);
|
||||
/**
|
||||
* Gets a {@link Collection} of all {@link PluginContainer}s.
|
||||
*
|
||||
* @return the plugins
|
||||
*/
|
||||
Collection<PluginContainer> getPlugins();
|
||||
|
||||
/**
|
||||
* Adds the specified {@code path} to the plugin classpath.
|
||||
*
|
||||
* @param plugin the plugin
|
||||
* @param path the path to the JAR you want to inject into the classpath
|
||||
* @throws UnsupportedOperationException if the operation is not applicable to this plugin
|
||||
*/
|
||||
void addToClasspath(Object plugin, Path path);
|
||||
/**
|
||||
* Checks if a plugin is loaded based on its ID.
|
||||
*
|
||||
* @param id the id of the plugin
|
||||
* @return {@code true} if loaded
|
||||
*/
|
||||
boolean isLoaded(String id);
|
||||
|
||||
/**
|
||||
* Adds the specified {@code path} to the plugin classpath.
|
||||
*
|
||||
* @param plugin the plugin
|
||||
* @param path the path to the JAR you want to inject into the classpath
|
||||
* @throws UnsupportedOperationException if the operation is not applicable to this plugin
|
||||
*/
|
||||
void addToClasspath(Object plugin, Path path);
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
package com.velocitypowered.api.plugin.annotation;
|
||||
|
||||
import com.google.inject.BindingAnnotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* This annotation requests that Velocity inject a {@link java.nio.file.Path} instance with a plugin-specific data
|
||||
* directory.
|
||||
* This annotation requests that Velocity inject a {@link java.nio.file.Path} instance with a
|
||||
* plugin-specific data directory.
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@BindingAnnotation
|
||||
public @interface DataDirectory {
|
||||
|
||||
}
|
||||
|
@ -1,80 +1,83 @@
|
||||
package com.velocitypowered.api.plugin.meta;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Strings.emptyToNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a dependency on another plugin.
|
||||
*/
|
||||
public final class PluginDependency {
|
||||
private final String id;
|
||||
@Nullable
|
||||
private final String version;
|
||||
|
||||
private final boolean optional;
|
||||
private final String id;
|
||||
@Nullable
|
||||
private final String version;
|
||||
|
||||
public PluginDependency(String id, @Nullable String version, boolean optional) {
|
||||
this.id = checkNotNull(id, "id");
|
||||
checkArgument(!id.isEmpty(), "id cannot be empty");
|
||||
this.version = emptyToNull(version);
|
||||
this.optional = optional;
|
||||
private final boolean optional;
|
||||
|
||||
public PluginDependency(String id, @Nullable String version, boolean optional) {
|
||||
this.id = checkNotNull(id, "id");
|
||||
checkArgument(!id.isEmpty(), "id cannot be empty");
|
||||
this.version = emptyToNull(version);
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin ID of this {@link PluginDependency}
|
||||
*
|
||||
* @return the plugin ID
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version this {@link PluginDependency} should match.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin version, may be empty
|
||||
*/
|
||||
public Optional<String> getVersion() {
|
||||
return Optional.ofNullable(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the dependency is optional for the plugin to work correctly.
|
||||
*
|
||||
* @return true if dependency is optional
|
||||
*/
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin ID of this {@link PluginDependency}
|
||||
*
|
||||
* @return the plugin ID
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
PluginDependency that = (PluginDependency) o;
|
||||
return optional == that.optional &&
|
||||
Objects.equals(id, that.id) &&
|
||||
Objects.equals(version, that.version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version this {@link PluginDependency} should match.
|
||||
*
|
||||
* @return an {@link Optional} with the plugin version, may be empty
|
||||
*/
|
||||
public Optional<String> getVersion() {
|
||||
return Optional.ofNullable(version);
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, version, optional);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the dependency is optional for the plugin to work
|
||||
* correctly.
|
||||
*
|
||||
* @return true if dependency is optional
|
||||
*/
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PluginDependency that = (PluginDependency) o;
|
||||
return optional == that.optional &&
|
||||
Objects.equals(id, that.id) &&
|
||||
Objects.equals(version, that.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, version, optional);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PluginDependency{" +
|
||||
"id='" + id + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
", optional=" + optional +
|
||||
'}';
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PluginDependency{" +
|
||||
"id='" + id + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
", optional=" + optional +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -1,91 +1,100 @@
|
||||
package com.velocitypowered.api.proxy;
|
||||
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import net.kyori.text.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import net.kyori.text.Component;
|
||||
|
||||
/**
|
||||
* 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(RegisteredServer)}.
|
||||
* 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(RegisteredServer)}.
|
||||
*/
|
||||
public interface ConnectionRequestBuilder {
|
||||
/**
|
||||
* Returns the server that this connection request represents.
|
||||
* @return the server this request will connect to
|
||||
*/
|
||||
RegisteredServer getServer();
|
||||
|
||||
/**
|
||||
* Returns the server that this connection request represents.
|
||||
*
|
||||
* @return the server this request will connect to
|
||||
*/
|
||||
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
|
||||
*/
|
||||
CompletableFuture<Result> connect();
|
||||
|
||||
/**
|
||||
* Initiates the connection to the remote server and emits a result on the {@link
|
||||
* CompletableFuture} after the user has logged on. Velocity's own built-in handling will be used
|
||||
* to provide errors to the client.
|
||||
*
|
||||
* @return a {@link CompletableFuture} representing the status of this connection
|
||||
*/
|
||||
CompletableFuture<Boolean> connectWithIndication();
|
||||
|
||||
/**
|
||||
* Initiates the connection to the remote server without waiting for a result. Velocity will use
|
||||
* generic error handling code to notify the user.
|
||||
*/
|
||||
void fireAndForget();
|
||||
|
||||
/**
|
||||
* Represents the result of a connection request.
|
||||
*/
|
||||
interface Result {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Determines whether or not the connection request was successful.
|
||||
*
|
||||
* @return whether or not the request succeeded
|
||||
*/
|
||||
CompletableFuture<Result> connect();
|
||||
|
||||
/**
|
||||
* Initiates the connection to the remote server and emits a result on the {@link CompletableFuture} after the user
|
||||
* has logged on. Velocity's own built-in handling will be used to provide errors to the client.
|
||||
* @return a {@link CompletableFuture} representing the status of this connection
|
||||
*/
|
||||
CompletableFuture<Boolean> connectWithIndication();
|
||||
|
||||
/**
|
||||
* Initiates the connection to the remote server without waiting for a result. Velocity will use generic error
|
||||
* handling code to notify the user.
|
||||
*/
|
||||
void fireAndForget();
|
||||
|
||||
/**
|
||||
* Represents the result of a connection request.
|
||||
*/
|
||||
interface Result {
|
||||
/**
|
||||
* Determines whether or not the connection request was successful.
|
||||
* @return whether or not the request succeeded
|
||||
*/
|
||||
default boolean isSuccessful() {
|
||||
return getStatus() == Status.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status associated with this result.
|
||||
* @return the status for this result
|
||||
*/
|
||||
Status getStatus();
|
||||
|
||||
/**
|
||||
* Returns an (optional) textual reason for the failure to connect to the server.
|
||||
* @return the reason why the user could not connect to the server
|
||||
*/
|
||||
Optional<Component> getReason();
|
||||
default boolean isSuccessful() {
|
||||
return getStatus() == Status.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the status of a connection request initiated by a {@link ConnectionRequestBuilder}.
|
||||
* Returns the status associated with this result.
|
||||
*
|
||||
* @return the status for this result
|
||||
*/
|
||||
enum Status {
|
||||
/**
|
||||
* The player was successfully connected to the server.
|
||||
*/
|
||||
SUCCESS,
|
||||
/**
|
||||
* The player is already connected to this server.
|
||||
*/
|
||||
ALREADY_CONNECTED,
|
||||
/**
|
||||
* The connection is already in progress.
|
||||
*/
|
||||
CONNECTION_IN_PROGRESS,
|
||||
/**
|
||||
* A plugin has cancelled this connection.
|
||||
*/
|
||||
CONNECTION_CANCELLED,
|
||||
/**
|
||||
* The server disconnected the user. A reason may be provided in the {@link Result} object.
|
||||
*/
|
||||
SERVER_DISCONNECTED
|
||||
}
|
||||
Status getStatus();
|
||||
|
||||
/**
|
||||
* Returns an (optional) textual reason for the failure to connect to the server.
|
||||
*
|
||||
* @return the reason why the user could not connect to the server
|
||||
*/
|
||||
Optional<Component> getReason();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the status of a connection request initiated by a {@link ConnectionRequestBuilder}.
|
||||
*/
|
||||
enum Status {
|
||||
/**
|
||||
* The player was successfully connected to the server.
|
||||
*/
|
||||
SUCCESS,
|
||||
/**
|
||||
* The player is already connected to this server.
|
||||
*/
|
||||
ALREADY_CONNECTED,
|
||||
/**
|
||||
* The connection is already in progress.
|
||||
*/
|
||||
CONNECTION_IN_PROGRESS,
|
||||
/**
|
||||
* A plugin has cancelled this connection.
|
||||
*/
|
||||
CONNECTION_CANCELLED,
|
||||
/**
|
||||
* The server disconnected the user. A reason may be provided in the {@link Result} object.
|
||||
*/
|
||||
SERVER_DISCONNECTED
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,27 +7,32 @@ import java.util.Optional;
|
||||
* Represents an incoming connection to the proxy.
|
||||
*/
|
||||
public interface InboundConnection {
|
||||
/**
|
||||
* Returns the player's IP address.
|
||||
* @return the player's IP
|
||||
*/
|
||||
InetSocketAddress getRemoteAddress();
|
||||
|
||||
/**
|
||||
* Returns the hostname that the user entered into the client, if applicable.
|
||||
* @return the hostname from the client
|
||||
*/
|
||||
Optional<InetSocketAddress> getVirtualHost();
|
||||
/**
|
||||
* Returns the player's IP address.
|
||||
*
|
||||
* @return the player's IP
|
||||
*/
|
||||
InetSocketAddress getRemoteAddress();
|
||||
|
||||
/**
|
||||
* Determine whether or not the player remains online.
|
||||
* @return whether or not the player active
|
||||
*/
|
||||
boolean isActive();
|
||||
/**
|
||||
* Returns the hostname that the user entered into the client, if applicable.
|
||||
*
|
||||
* @return the hostname from the client
|
||||
*/
|
||||
Optional<InetSocketAddress> getVirtualHost();
|
||||
|
||||
/**
|
||||
* Returns the current protocol version this connection uses.
|
||||
* @return the protocol version the connection uses
|
||||
*/
|
||||
int getProtocolVersion();
|
||||
/**
|
||||
* Determine whether or not the player remains online.
|
||||
*
|
||||
* @return whether or not the player active
|
||||
*/
|
||||
boolean isActive();
|
||||
|
||||
/**
|
||||
* Returns the current protocol version this connection uses.
|
||||
*
|
||||
* @return the protocol version the connection uses
|
||||
*/
|
||||
int getProtocolVersion();
|
||||
}
|
||||
|
@ -4,136 +4,150 @@ import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
|
||||
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
|
||||
import com.velocitypowered.api.proxy.player.PlayerSettings;
|
||||
import com.velocitypowered.api.proxy.player.TabList;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.api.proxy.player.TabList;
|
||||
import com.velocitypowered.api.util.MessagePosition;
|
||||
import com.velocitypowered.api.util.ModInfo;
|
||||
import com.velocitypowered.api.util.title.Title;
|
||||
import java.util.List;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import net.kyori.text.Component;
|
||||
|
||||
/**
|
||||
* Represents a player who is connected to the proxy.
|
||||
*/
|
||||
public interface Player extends CommandSource, InboundConnection, ChannelMessageSource, ChannelMessageSink {
|
||||
/**
|
||||
* Returns the player's current username.
|
||||
* @return the username
|
||||
*/
|
||||
String getUsername();
|
||||
public interface Player extends CommandSource, InboundConnection, ChannelMessageSource,
|
||||
ChannelMessageSink {
|
||||
|
||||
/**
|
||||
* Returns the player's UUID.
|
||||
* @return the UUID
|
||||
*/
|
||||
UUID getUniqueId();
|
||||
/**
|
||||
* Returns the player's current username.
|
||||
*
|
||||
* @return the username
|
||||
*/
|
||||
String getUsername();
|
||||
|
||||
/**
|
||||
* Returns the server that the player is currently connected to.
|
||||
* @return an {@link Optional} the server that the player is connected to, which may be empty
|
||||
*/
|
||||
Optional<ServerConnection> getCurrentServer();
|
||||
/**
|
||||
* Returns the player's UUID.
|
||||
*
|
||||
* @return the UUID
|
||||
*/
|
||||
UUID getUniqueId();
|
||||
|
||||
/**
|
||||
* Returns the player settings
|
||||
* @return the settings
|
||||
*/
|
||||
PlayerSettings getPlayerSettings();
|
||||
|
||||
/**
|
||||
* Returns the player's mod info if they have a modded client.
|
||||
* @return an {@link Optional} the mod info. which may be empty
|
||||
*/
|
||||
Optional<ModInfo> getModInfo();
|
||||
/**
|
||||
* Returns the server that the player is currently connected to.
|
||||
*
|
||||
* @return an {@link Optional} the server that the player is connected to, which may be empty
|
||||
*/
|
||||
Optional<ServerConnection> getCurrentServer();
|
||||
|
||||
/**
|
||||
* Returns the current player's ping
|
||||
* @return the player's ping or -1 if ping information is currently unknown
|
||||
*/
|
||||
long getPing();
|
||||
|
||||
/**
|
||||
* Sends a chat message to the player's client.
|
||||
* @param component the chat message to send
|
||||
*/
|
||||
default void sendMessage(Component component) {
|
||||
sendMessage(component, MessagePosition.CHAT);
|
||||
}
|
||||
/**
|
||||
* Returns the player settings
|
||||
*
|
||||
* @return the settings
|
||||
*/
|
||||
PlayerSettings getPlayerSettings();
|
||||
|
||||
/**
|
||||
* Sends a chat message to the player's client in the specified position.
|
||||
* @param component the chat message to send
|
||||
* @param position the position for the message
|
||||
*/
|
||||
void sendMessage(Component component, MessagePosition position);
|
||||
/**
|
||||
* Returns the player's mod info if they have a modded client.
|
||||
*
|
||||
* @return an {@link Optional} the mod info. which may be empty
|
||||
*/
|
||||
Optional<ModInfo> getModInfo();
|
||||
|
||||
/**
|
||||
* Creates a new connection request so that the player can connect to another server.
|
||||
* @param server the server to connect to
|
||||
* @return a new connection request
|
||||
*/
|
||||
ConnectionRequestBuilder createConnectionRequest(RegisteredServer server);
|
||||
/**
|
||||
* Returns the current player's ping
|
||||
*
|
||||
* @return the player's ping or -1 if ping information is currently unknown
|
||||
*/
|
||||
long getPing();
|
||||
|
||||
/**
|
||||
* Gets the player's profile properties.
|
||||
*
|
||||
* <p>The returned list may be unmodifiable.</p>
|
||||
*
|
||||
* @return the player's profile properties
|
||||
*/
|
||||
List<GameProfile.Property> getGameProfileProperties();
|
||||
|
||||
/**
|
||||
* Sets the player's profile properties.
|
||||
*
|
||||
* @param properties the properties
|
||||
*/
|
||||
void setGameProfileProperties(List<GameProfile.Property> properties);
|
||||
|
||||
/**
|
||||
* Sets the tab list header and footer for the player.
|
||||
* @param header the header component
|
||||
* @param footer the footer component
|
||||
* @deprecated Use {@link TabList#setHeaderAndFooter(Component, Component)}.
|
||||
*/
|
||||
@Deprecated
|
||||
void setHeaderAndFooter(Component header, Component footer);
|
||||
/**
|
||||
* Sends a chat message to the player's client.
|
||||
*
|
||||
* @param component the chat message to send
|
||||
*/
|
||||
default void sendMessage(Component component) {
|
||||
sendMessage(component, MessagePosition.CHAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the tab list header and footer for the player.
|
||||
* @deprecated Use {@link TabList#clearHeaderAndFooter()}.
|
||||
*/
|
||||
@Deprecated
|
||||
void clearHeaderAndFooter();
|
||||
|
||||
/**
|
||||
* Returns the player's tab list.
|
||||
* @return this player's tab list
|
||||
*/
|
||||
TabList getTabList();
|
||||
/**
|
||||
* Sends a chat message to the player's client in the specified position.
|
||||
*
|
||||
* @param component the chat message to send
|
||||
* @param position the position for the message
|
||||
*/
|
||||
void sendMessage(Component component, MessagePosition position);
|
||||
|
||||
/**
|
||||
* Disconnects the player with the specified reason. Once this method is called, further calls to other {@link Player}
|
||||
* methods will become undefined.
|
||||
* @param reason component with the reason
|
||||
*/
|
||||
void disconnect(Component reason);
|
||||
/**
|
||||
* Creates a new connection request so that the player can connect to another server.
|
||||
*
|
||||
* @param server the server to connect to
|
||||
* @return a new connection request
|
||||
*/
|
||||
ConnectionRequestBuilder createConnectionRequest(RegisteredServer server);
|
||||
|
||||
/**
|
||||
* Sends the specified title to the client.
|
||||
* @param title the title to send
|
||||
*/
|
||||
void sendTitle(Title title);
|
||||
/**
|
||||
* Gets the player's profile properties.
|
||||
*
|
||||
* <p>The returned list may be unmodifiable.</p>
|
||||
*
|
||||
* @return the player's profile properties
|
||||
*/
|
||||
List<GameProfile.Property> getGameProfileProperties();
|
||||
|
||||
/**
|
||||
* Sends chat input onto the players current server as if they typed it
|
||||
* into the client chat box.
|
||||
* @param input the chat input to send
|
||||
*/
|
||||
void spoofChatInput(String input);
|
||||
/**
|
||||
* Sets the player's profile properties.
|
||||
*
|
||||
* @param properties the properties
|
||||
*/
|
||||
void setGameProfileProperties(List<GameProfile.Property> properties);
|
||||
|
||||
/**
|
||||
* Sets the tab list header and footer for the player.
|
||||
*
|
||||
* @param header the header component
|
||||
* @param footer the footer component
|
||||
* @deprecated Use {@link TabList#setHeaderAndFooter(Component, Component)}.
|
||||
*/
|
||||
@Deprecated
|
||||
void setHeaderAndFooter(Component header, Component footer);
|
||||
|
||||
/**
|
||||
* Clears the tab list header and footer for the player.
|
||||
*
|
||||
* @deprecated Use {@link TabList#clearHeaderAndFooter()}.
|
||||
*/
|
||||
@Deprecated
|
||||
void clearHeaderAndFooter();
|
||||
|
||||
/**
|
||||
* Returns the player's tab list.
|
||||
*
|
||||
* @return this player's tab list
|
||||
*/
|
||||
TabList getTabList();
|
||||
|
||||
/**
|
||||
* Disconnects the player with the specified reason. Once this method is called, further calls to
|
||||
* other {@link Player} methods will become undefined.
|
||||
*
|
||||
* @param reason component with the reason
|
||||
*/
|
||||
void disconnect(Component reason);
|
||||
|
||||
/**
|
||||
* Sends the specified title to the client.
|
||||
*
|
||||
* @param title the title to send
|
||||
*/
|
||||
void sendTitle(Title title);
|
||||
|
||||
/**
|
||||
* Sends chat input onto the players current server as if they typed it into the client chat box.
|
||||
*
|
||||
* @param input the chat input to send
|
||||
*/
|
||||
void spoofChatInput(String input);
|
||||
}
|
||||
|
@ -10,132 +10,151 @@ import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import com.velocitypowered.api.scheduler.Scheduler;
|
||||
import com.velocitypowered.api.util.ProxyVersion;
|
||||
import net.kyori.text.Component;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import net.kyori.text.Component;
|
||||
|
||||
/**
|
||||
* Provides an interface to a Minecraft server proxy.
|
||||
*/
|
||||
public interface ProxyServer {
|
||||
/**
|
||||
* Retrieves the player currently connected to this proxy by their Minecraft username. The search is case-insensitive.
|
||||
* @param username the username to search for
|
||||
* @return an {@link Optional} with the player, which may be empty
|
||||
*/
|
||||
Optional<Player> getPlayer(String username);
|
||||
|
||||
/**
|
||||
* Retrieves the player currently connected to this proxy by their Minecraft UUID.
|
||||
* @param uuid the UUID
|
||||
* @return an {@link Optional} with the player, which may be empty
|
||||
*/
|
||||
Optional<Player> getPlayer(UUID uuid);
|
||||
/**
|
||||
* Retrieves the player currently connected to this proxy by their Minecraft username. The search
|
||||
* is case-insensitive.
|
||||
*
|
||||
* @param username the username to search for
|
||||
* @return an {@link Optional} with the player, which may be empty
|
||||
*/
|
||||
Optional<Player> getPlayer(String username);
|
||||
|
||||
/**
|
||||
* Broadcasts a message to all players currently online.
|
||||
* @param component the message to send
|
||||
*/
|
||||
void broadcast(Component component);
|
||||
/**
|
||||
* Retrieves the player currently connected to this proxy by their Minecraft UUID.
|
||||
*
|
||||
* @param uuid the UUID
|
||||
* @return an {@link Optional} with the player, which may be empty
|
||||
*/
|
||||
Optional<Player> getPlayer(UUID uuid);
|
||||
|
||||
/**
|
||||
* Retrieves all players currently connected to this proxy. This call may or may not be a snapshot of all players
|
||||
* online.
|
||||
* @return the players online on this proxy
|
||||
*/
|
||||
Collection<Player> getAllPlayers();
|
||||
/**
|
||||
* Broadcasts a message to all players currently online.
|
||||
*
|
||||
* @param component the message to send
|
||||
*/
|
||||
void broadcast(Component component);
|
||||
|
||||
/**
|
||||
* Returns the number of players currently connected to this proxy.
|
||||
* @return the players on this proxy
|
||||
*/
|
||||
int getPlayerCount();
|
||||
/**
|
||||
* Retrieves all players currently connected to this proxy. This call may or may not be a snapshot
|
||||
* of all players online.
|
||||
*
|
||||
* @return the players online on this proxy
|
||||
*/
|
||||
Collection<Player> getAllPlayers();
|
||||
|
||||
/**
|
||||
* 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<RegisteredServer> getServer(String name);
|
||||
/**
|
||||
* Returns the number of players currently connected to this proxy.
|
||||
*
|
||||
* @return the players on this proxy
|
||||
*/
|
||||
int getPlayerCount();
|
||||
|
||||
/**
|
||||
* Retrieves all {@link RegisteredServer}s registered with this proxy.
|
||||
* @return the servers registered with this proxy
|
||||
*/
|
||||
Collection<RegisteredServer> getAllServers();
|
||||
/**
|
||||
* 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<RegisteredServer> getServer(String name);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
RegisteredServer registerServer(ServerInfo server);
|
||||
/**
|
||||
* Retrieves all {@link RegisteredServer}s registered with this proxy.
|
||||
*
|
||||
* @return the servers registered with this proxy
|
||||
*/
|
||||
Collection<RegisteredServer> getAllServers();
|
||||
|
||||
/**
|
||||
* Unregisters this server from the proxy.
|
||||
* @param server the server to unregister
|
||||
*/
|
||||
void unregisterServer(ServerInfo server);
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
RegisteredServer registerServer(ServerInfo server);
|
||||
|
||||
/**
|
||||
* Returns an instance of {@link CommandSource} that can be used to determine if the command is being invoked by
|
||||
* the console or a console-like executor. Plugins that execute commands are strongly urged to implement their own
|
||||
* {@link CommandSource} instead of using the console invoker.
|
||||
* @return the console command invoker
|
||||
*/
|
||||
CommandSource getConsoleCommandSource();
|
||||
/**
|
||||
* Unregisters this server from the proxy.
|
||||
*
|
||||
* @param server the server to unregister
|
||||
*/
|
||||
void unregisterServer(ServerInfo server);
|
||||
|
||||
/**
|
||||
* Gets the {@link PluginManager} instance.
|
||||
*
|
||||
* @return the plugin manager instance
|
||||
*/
|
||||
PluginManager getPluginManager();
|
||||
/**
|
||||
* Returns an instance of {@link CommandSource} that can be used to determine if the command is
|
||||
* being invoked by the console or a console-like executor. Plugins that execute commands are
|
||||
* strongly urged to implement their own {@link CommandSource} instead of using the console
|
||||
* invoker.
|
||||
*
|
||||
* @return the console command invoker
|
||||
*/
|
||||
CommandSource getConsoleCommandSource();
|
||||
|
||||
/**
|
||||
* Gets the {@link EventManager} instance.
|
||||
*
|
||||
* @return the event manager instance
|
||||
*/
|
||||
EventManager getEventManager();
|
||||
/**
|
||||
* Gets the {@link PluginManager} instance.
|
||||
*
|
||||
* @return the plugin manager instance
|
||||
*/
|
||||
PluginManager getPluginManager();
|
||||
|
||||
/**
|
||||
* Gets the {@link CommandManager} instance.
|
||||
* @return the command manager
|
||||
*/
|
||||
CommandManager getCommandManager();
|
||||
/**
|
||||
* Gets the {@link EventManager} instance.
|
||||
*
|
||||
* @return the event manager instance
|
||||
*/
|
||||
EventManager getEventManager();
|
||||
|
||||
/**
|
||||
* Gets the {@link Scheduler} instance.
|
||||
* @return the scheduler instance
|
||||
*/
|
||||
Scheduler getScheduler();
|
||||
/**
|
||||
* Gets the {@link CommandManager} instance.
|
||||
*
|
||||
* @return the command manager
|
||||
*/
|
||||
CommandManager getCommandManager();
|
||||
|
||||
/**
|
||||
* Gets the {@link ChannelRegistrar} instance.
|
||||
* @return the channel registrar
|
||||
*/
|
||||
ChannelRegistrar getChannelRegistrar();
|
||||
/**
|
||||
* Gets the {@link Scheduler} instance.
|
||||
*
|
||||
* @return the scheduler instance
|
||||
*/
|
||||
Scheduler getScheduler();
|
||||
|
||||
/**
|
||||
* Gets the address that this proxy is bound to. This does not necessarily indicate the external IP address of the
|
||||
* proxy.
|
||||
* @return the address the proxy is bound to
|
||||
*/
|
||||
InetSocketAddress getBoundAddress();
|
||||
/**
|
||||
* Gets the {@link ChannelRegistrar} instance.
|
||||
*
|
||||
* @return the channel registrar
|
||||
*/
|
||||
ChannelRegistrar getChannelRegistrar();
|
||||
|
||||
/**
|
||||
* Gets the {@link ProxyConfig} instance.
|
||||
* @return the proxy config
|
||||
* */
|
||||
ProxyConfig getConfiguration();
|
||||
/**
|
||||
* Gets the address that this proxy is bound to. This does not necessarily indicate the external
|
||||
* IP address of the proxy.
|
||||
*
|
||||
* @return the address the proxy is bound to
|
||||
*/
|
||||
InetSocketAddress getBoundAddress();
|
||||
|
||||
/**
|
||||
* Returns the version of the proxy.
|
||||
* @return the proxy version
|
||||
*/
|
||||
ProxyVersion getVersion();
|
||||
/**
|
||||
* Gets the {@link ProxyConfig} instance.
|
||||
*
|
||||
* @return the proxy config
|
||||
*/
|
||||
ProxyConfig getConfiguration();
|
||||
|
||||
/**
|
||||
* Returns the version of the proxy.
|
||||
*
|
||||
* @return the proxy version
|
||||
*/
|
||||
ProxyVersion getVersion();
|
||||
}
|
||||
|
@ -9,21 +9,25 @@ import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
* Represents a connection to a backend server from the proxy for a client.
|
||||
*/
|
||||
public interface ServerConnection extends ChannelMessageSource, ChannelMessageSink {
|
||||
/**
|
||||
* 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();
|
||||
/**
|
||||
* Returns the server that this connection is connected to.
|
||||
*
|
||||
* @return the server this connection is connected to
|
||||
*/
|
||||
RegisteredServer getServer();
|
||||
|
||||
/**
|
||||
* Returns the player that this connection is associated with.
|
||||
* @return the player for this connection
|
||||
*/
|
||||
Player getPlayer();
|
||||
/**
|
||||
* Returns the server info for this connection.
|
||||
*
|
||||
* @return the server info for this connection
|
||||
*/
|
||||
ServerInfo getServerInfo();
|
||||
|
||||
/**
|
||||
* Returns the player that this connection is associated with.
|
||||
*
|
||||
* @return the player for this connection
|
||||
*/
|
||||
Player getPlayer();
|
||||
}
|
||||
|
@ -1,116 +1,133 @@
|
||||
package com.velocitypowered.api.proxy.config;
|
||||
|
||||
import com.velocitypowered.api.util.Favicon;
|
||||
import net.kyori.text.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import net.kyori.text.Component;
|
||||
|
||||
/**
|
||||
* Provides an interface to a proxy configuration
|
||||
*/
|
||||
public interface ProxyConfig {
|
||||
/**
|
||||
* Whether GameSpy 4 queries are accepted by the proxy
|
||||
* @return queries enabled
|
||||
*/
|
||||
boolean isQueryEnabled();
|
||||
|
||||
/**
|
||||
* Get the port GameSpy 4 queries are accepted on
|
||||
* @return the query port
|
||||
*/
|
||||
int getQueryPort();
|
||||
/**
|
||||
* Whether GameSpy 4 queries are accepted by the proxy
|
||||
*
|
||||
* @return queries enabled
|
||||
*/
|
||||
boolean isQueryEnabled();
|
||||
|
||||
/**
|
||||
* Get the map name reported to GameSpy 4 query services
|
||||
* @return the map name
|
||||
*/
|
||||
String getQueryMap();
|
||||
/**
|
||||
* Get the port GameSpy 4 queries are accepted on
|
||||
*
|
||||
* @return the query port
|
||||
*/
|
||||
int getQueryPort();
|
||||
|
||||
/**
|
||||
* Whether GameSpy 4 queries should show plugins installed on
|
||||
* Velocity by default
|
||||
* @return show plugins in query
|
||||
*/
|
||||
boolean shouldQueryShowPlugins();
|
||||
/**
|
||||
* Get the map name reported to GameSpy 4 query services
|
||||
*
|
||||
* @return the map name
|
||||
*/
|
||||
String getQueryMap();
|
||||
|
||||
/**
|
||||
* Get the MOTD component shown in the tab list
|
||||
* @return the motd component
|
||||
*/
|
||||
Component getMotdComponent();
|
||||
/**
|
||||
* Whether GameSpy 4 queries should show plugins installed on Velocity by default
|
||||
*
|
||||
* @return show plugins in query
|
||||
*/
|
||||
boolean shouldQueryShowPlugins();
|
||||
|
||||
/**
|
||||
* Get the maximum players shown in the tab list
|
||||
* @return max players
|
||||
*/
|
||||
int getShowMaxPlayers();
|
||||
/**
|
||||
* Get the MOTD component shown in the tab list
|
||||
*
|
||||
* @return the motd component
|
||||
*/
|
||||
Component getMotdComponent();
|
||||
|
||||
/**
|
||||
* Get whether the proxy is online mode. This determines if players are authenticated with Mojang servers.
|
||||
* @return online mode enabled
|
||||
*/
|
||||
boolean isOnlineMode();
|
||||
/**
|
||||
* Get the maximum players shown in the tab list
|
||||
*
|
||||
* @return max players
|
||||
*/
|
||||
int getShowMaxPlayers();
|
||||
|
||||
/**
|
||||
* Get a Map of all servers registered on this proxy
|
||||
* @return registered servers map
|
||||
*/
|
||||
Map<String, String> getServers();
|
||||
/**
|
||||
* Get whether the proxy is online mode. This determines if players are authenticated with Mojang
|
||||
* servers.
|
||||
*
|
||||
* @return online mode enabled
|
||||
*/
|
||||
boolean isOnlineMode();
|
||||
|
||||
/**
|
||||
* Get the order of servers that players will be connected to
|
||||
* @return connection order list
|
||||
*/
|
||||
List<String> getAttemptConnectionOrder();
|
||||
/**
|
||||
* Get a Map of all servers registered on this proxy
|
||||
*
|
||||
* @return registered servers map
|
||||
*/
|
||||
Map<String, String> getServers();
|
||||
|
||||
/**
|
||||
* Get forced servers mapped to given virtual host
|
||||
* @return list of server names
|
||||
*/
|
||||
Map<String, List<String>> getForcedHosts();
|
||||
/**
|
||||
* Get the order of servers that players will be connected to
|
||||
*
|
||||
* @return connection order list
|
||||
*/
|
||||
List<String> getAttemptConnectionOrder();
|
||||
|
||||
/**
|
||||
* Get the minimum compression threshold for packets
|
||||
* @return the compression threshold
|
||||
*/
|
||||
int getCompressionThreshold();
|
||||
/**
|
||||
* Get forced servers mapped to given virtual host
|
||||
*
|
||||
* @return list of server names
|
||||
*/
|
||||
Map<String, List<String>> getForcedHosts();
|
||||
|
||||
/**
|
||||
* Get the level of compression that packets will be compressed to
|
||||
* @return the compression level
|
||||
*/
|
||||
int getCompressionLevel();
|
||||
/**
|
||||
* Get the minimum compression threshold for packets
|
||||
*
|
||||
* @return the compression threshold
|
||||
*/
|
||||
int getCompressionThreshold();
|
||||
|
||||
/**
|
||||
* Get the limit for how long a player must wait to log back in
|
||||
* @return the login rate limit (in milliseconds)
|
||||
*/
|
||||
int getLoginRatelimit();
|
||||
/**
|
||||
* Get the level of compression that packets will be compressed to
|
||||
*
|
||||
* @return the compression level
|
||||
*/
|
||||
int getCompressionLevel();
|
||||
|
||||
/**
|
||||
* Get the proxy favicon shown in the tablist
|
||||
* @return optional favicon
|
||||
*/
|
||||
Optional<Favicon> getFavicon();
|
||||
/**
|
||||
* Get the limit for how long a player must wait to log back in
|
||||
*
|
||||
* @return the login rate limit (in milliseconds)
|
||||
*/
|
||||
int getLoginRatelimit();
|
||||
|
||||
/**
|
||||
* Get whether this proxy displays that it supports Forge/FML
|
||||
* @return forge announce enabled
|
||||
*/
|
||||
boolean isAnnounceForge();
|
||||
/**
|
||||
* Get the proxy favicon shown in the tablist
|
||||
*
|
||||
* @return optional favicon
|
||||
*/
|
||||
Optional<Favicon> getFavicon();
|
||||
|
||||
/**
|
||||
* Get how long this proxy will wait until performing a read timeout
|
||||
* @return connection timeout (in milliseconds)
|
||||
*/
|
||||
int getConnectTimeout();
|
||||
/**
|
||||
* Get whether this proxy displays that it supports Forge/FML
|
||||
*
|
||||
* @return forge announce enabled
|
||||
*/
|
||||
boolean isAnnounceForge();
|
||||
|
||||
/**
|
||||
* Get how long this proxy will wait until performing a read timeout
|
||||
* @return read timeout (in milliseconds)
|
||||
*/
|
||||
int getReadTimeout();
|
||||
/**
|
||||
* Get how long this proxy will wait until performing a read timeout
|
||||
*
|
||||
* @return connection timeout (in milliseconds)
|
||||
*/
|
||||
int getConnectTimeout();
|
||||
|
||||
/**
|
||||
* Get how long this proxy will wait until performing a read timeout
|
||||
*
|
||||
* @return read timeout (in milliseconds)
|
||||
*/
|
||||
int getReadTimeout();
|
||||
}
|
||||
|
@ -4,9 +4,11 @@ package com.velocitypowered.api.proxy.messages;
|
||||
* Represents a kind of channel identifier.
|
||||
*/
|
||||
public interface ChannelIdentifier {
|
||||
/**
|
||||
* Returns the textual representation of this identifier.
|
||||
* @return the textual representation of the identifier
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Returns the textual representation of this identifier.
|
||||
*
|
||||
* @return the textual representation of the identifier
|
||||
*/
|
||||
String getId();
|
||||
}
|
||||
|
@ -4,11 +4,13 @@ package com.velocitypowered.api.proxy.messages;
|
||||
* Represents something that can send plugin messages.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data);
|
||||
}
|
||||
|
@ -4,4 +4,5 @@ package com.velocitypowered.api.proxy.messages;
|
||||
* A marker interface that indicates a source of plugin messages.
|
||||
*/
|
||||
public interface ChannelMessageSource {
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,22 @@
|
||||
package com.velocitypowered.api.proxy.messages;
|
||||
|
||||
/**
|
||||
* Represents an interface to register and unregister {@link ChannelIdentifier}s for the proxy to listen on.
|
||||
* Represents an interface to register and unregister {@link ChannelIdentifier}s for the proxy to
|
||||
* listen on.
|
||||
*/
|
||||
public interface ChannelRegistrar {
|
||||
/**
|
||||
* Registers the specified message identifiers to listen on for the
|
||||
* @param identifiers the channel identifiers to register
|
||||
*/
|
||||
void register(ChannelIdentifier... identifiers);
|
||||
|
||||
/**
|
||||
* Unregisters the handler for the specified channel.
|
||||
* @param identifiers the identifiers to unregister
|
||||
*/
|
||||
void unregister(ChannelIdentifier... identifiers);
|
||||
/**
|
||||
* Registers the specified message identifiers to listen on for the
|
||||
*
|
||||
* @param identifiers the channel identifiers to register
|
||||
*/
|
||||
void register(ChannelIdentifier... identifiers);
|
||||
|
||||
/**
|
||||
* Unregisters the handler for the specified channel.
|
||||
*
|
||||
* @param identifiers the identifiers to unregister
|
||||
*/
|
||||
void unregister(ChannelIdentifier... identifiers);
|
||||
}
|
||||
|
@ -2,46 +2,51 @@ package com.velocitypowered.api.proxy.messages;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import java.util.Objects;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Reperesents a legacy channel identifier (for Minecraft 1.12 and below). For modern 1.13 plugin messages, please see
|
||||
* {@link MinecraftChannelIdentifier}. This class is immutable and safe for multi-threaded use.
|
||||
* Reperesents a legacy channel identifier (for Minecraft 1.12 and below). For modern 1.13 plugin
|
||||
* messages, please see {@link MinecraftChannelIdentifier}. This class is immutable and safe for
|
||||
* multi-threaded use.
|
||||
*/
|
||||
public final class LegacyChannelIdentifier implements ChannelIdentifier {
|
||||
private final String name;
|
||||
|
||||
public LegacyChannelIdentifier(String name) {
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "provided name is empty");
|
||||
this.name = name;
|
||||
}
|
||||
private final String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public LegacyChannelIdentifier(String name) {
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "provided name is empty");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " (legacy)";
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
LegacyChannelIdentifier that = (LegacyChannelIdentifier) o;
|
||||
return Objects.equals(name, that.name);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " (legacy)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
LegacyChannelIdentifier that = (LegacyChannelIdentifier) o;
|
||||
return Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.getName();
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.getName();
|
||||
}
|
||||
}
|
||||
|
@ -2,78 +2,87 @@ package com.velocitypowered.api.proxy.messages;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a Minecraft 1.13+ channel identifier. This class is immutable and safe for multi-threaded use.
|
||||
* 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\\-_]+");
|
||||
|
||||
private final String namespace;
|
||||
private final String name;
|
||||
private static final Pattern VALID_IDENTIFIER_REGEX = Pattern.compile("[a-z0-9\\-_]+");
|
||||
|
||||
private MinecraftChannelIdentifier(String namespace, String name) {
|
||||
this.namespace = namespace;
|
||||
this.name = name;
|
||||
private final String namespace;
|
||||
private final String name;
|
||||
|
||||
private MinecraftChannelIdentifier(String namespace, String name) {
|
||||
this.namespace = namespace;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identifier in the default namespace ({@code minecraft}). Plugins are strongly
|
||||
* encouraged to provide their own namespace.
|
||||
*
|
||||
* @param name the name in the default namespace to use
|
||||
* @return a new channel identifier
|
||||
*/
|
||||
public static MinecraftChannelIdentifier forDefaultNamespace(String name) {
|
||||
return new MinecraftChannelIdentifier("minecraft", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identifier in the specified namespace.
|
||||
*
|
||||
* @param namespace the namespace to use
|
||||
* @param name the channel name inside the specified namespace
|
||||
* @return a new channel identifier
|
||||
*/
|
||||
public static MinecraftChannelIdentifier create(String namespace, String name) {
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(namespace), "namespace is null or empty");
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "namespace is null or empty");
|
||||
Preconditions.checkArgument(VALID_IDENTIFIER_REGEX.matcher(namespace).matches(),
|
||||
"namespace is not valid");
|
||||
Preconditions
|
||||
.checkArgument(VALID_IDENTIFIER_REGEX.matcher(name).matches(), "name is not valid");
|
||||
return new MinecraftChannelIdentifier(namespace, name);
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return namespace + ":" + name + " (modern)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identifier in the default namespace ({@code minecraft}). Plugins are strongly encouraged to provide
|
||||
* their own namespace.
|
||||
* @param name the name in the default namespace to use
|
||||
* @return a new channel identifier
|
||||
*/
|
||||
public static MinecraftChannelIdentifier forDefaultNamespace(String name) {
|
||||
return new MinecraftChannelIdentifier("minecraft", name);
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
MinecraftChannelIdentifier that = (MinecraftChannelIdentifier) o;
|
||||
return Objects.equals(namespace, that.namespace) &&
|
||||
Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identifier in the specified namespace.
|
||||
* @param namespace the namespace to use
|
||||
* @param name the channel name inside the specified namespace
|
||||
* @return a new channel identifier
|
||||
*/
|
||||
public static MinecraftChannelIdentifier create(String namespace, String name) {
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(namespace), "namespace is null or empty");
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "namespace is null or empty");
|
||||
Preconditions.checkArgument(VALID_IDENTIFIER_REGEX.matcher(namespace).matches(), "namespace is not valid");
|
||||
Preconditions.checkArgument(VALID_IDENTIFIER_REGEX.matcher(name).matches(), "name is not valid");
|
||||
return new MinecraftChannelIdentifier(namespace, name);
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(namespace, name);
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return namespace + ":" + name + " (modern)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
MinecraftChannelIdentifier that = (MinecraftChannelIdentifier) o;
|
||||
return Objects.equals(namespace, that.namespace) &&
|
||||
Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(namespace, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return namespace + ":" + name;
|
||||
}
|
||||
@Override
|
||||
public String getId() {
|
||||
return namespace + ":" + name;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
/**
|
||||
* Provides an interface to receive, handle, and send plugin messages on the proxy from clients and servers.
|
||||
* Provides an interface to receive, handle, and send plugin messages on the proxy from clients and
|
||||
* servers.
|
||||
*/
|
||||
package com.velocitypowered.api.proxy.messages;
|
@ -6,51 +6,58 @@ import java.util.Locale;
|
||||
* Represents the client settings for the player.
|
||||
*/
|
||||
public interface PlayerSettings {
|
||||
/**
|
||||
* Returns the locale of the Minecraft client.
|
||||
* @return the client locale
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
/**
|
||||
* Returns the client's view distance. This does not guarantee the client will see this many chunks, since your
|
||||
* servers are responsible for sending the chunks.
|
||||
* @return the client view distance
|
||||
*/
|
||||
byte getViewDistance();
|
||||
/**
|
||||
* Returns the locale of the Minecraft client.
|
||||
*
|
||||
* @return the client locale
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
/**
|
||||
* Returns the chat setting for the client.
|
||||
* @return the chat setting
|
||||
*/
|
||||
ChatMode getChatMode();
|
||||
/**
|
||||
* Returns the client's view distance. This does not guarantee the client will see this many
|
||||
* chunks, since your servers are responsible for sending the chunks.
|
||||
*
|
||||
* @return the client view distance
|
||||
*/
|
||||
byte getViewDistance();
|
||||
|
||||
/**
|
||||
* Returns whether or not the client has chat colors disabled.
|
||||
* @return whether or not the client has chat colors disabled
|
||||
*/
|
||||
boolean hasChatColors();
|
||||
/**
|
||||
* Returns the chat setting for the client.
|
||||
*
|
||||
* @return the chat setting
|
||||
*/
|
||||
ChatMode getChatMode();
|
||||
|
||||
/**
|
||||
* Returns the parts of player skins the client will show.
|
||||
* @return the skin parts for the client
|
||||
*/
|
||||
SkinParts getSkinParts();
|
||||
/**
|
||||
* Returns whether or not the client has chat colors disabled.
|
||||
*
|
||||
* @return whether or not the client has chat colors disabled
|
||||
*/
|
||||
boolean hasChatColors();
|
||||
|
||||
/**
|
||||
* Returns the primary hand of the client.
|
||||
* @return the primary hand of the client
|
||||
*/
|
||||
MainHand getMainHand();
|
||||
/**
|
||||
* Returns the parts of player skins the client will show.
|
||||
*
|
||||
* @return the skin parts for the client
|
||||
*/
|
||||
SkinParts getSkinParts();
|
||||
|
||||
enum ChatMode {
|
||||
SHOWN,
|
||||
COMMANDS_ONLY,
|
||||
HIDDEN
|
||||
}
|
||||
/**
|
||||
* Returns the primary hand of the client.
|
||||
*
|
||||
* @return the primary hand of the client
|
||||
*/
|
||||
MainHand getMainHand();
|
||||
|
||||
enum MainHand {
|
||||
LEFT,
|
||||
RIGHT
|
||||
}
|
||||
enum ChatMode {
|
||||
SHOWN,
|
||||
COMMANDS_ONLY,
|
||||
HIDDEN
|
||||
}
|
||||
|
||||
enum MainHand {
|
||||
LEFT,
|
||||
RIGHT
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,38 @@
|
||||
package com.velocitypowered.api.proxy.player;
|
||||
|
||||
public final class SkinParts {
|
||||
private final byte bitmask;
|
||||
|
||||
public SkinParts(byte skinBitmask) {
|
||||
this.bitmask = skinBitmask;
|
||||
}
|
||||
private final byte bitmask;
|
||||
|
||||
public boolean hasCape() {
|
||||
return (bitmask & 1) == 1;
|
||||
}
|
||||
public SkinParts(byte skinBitmask) {
|
||||
this.bitmask = skinBitmask;
|
||||
}
|
||||
|
||||
public boolean hasJacket() {
|
||||
return ((bitmask >> 1) & 1) == 1;
|
||||
}
|
||||
public boolean hasCape() {
|
||||
return (bitmask & 1) == 1;
|
||||
}
|
||||
|
||||
public boolean hasLeftSleeve() {
|
||||
return ((bitmask >> 2) & 1) == 1;
|
||||
}
|
||||
public boolean hasJacket() {
|
||||
return ((bitmask >> 1) & 1) == 1;
|
||||
}
|
||||
|
||||
public boolean hasRightSleeve() {
|
||||
return ((bitmask >> 3) & 1) == 1;
|
||||
}
|
||||
public boolean hasLeftSleeve() {
|
||||
return ((bitmask >> 2) & 1) == 1;
|
||||
}
|
||||
|
||||
public boolean hasLeftPants() {
|
||||
return ((bitmask >> 4) & 1) == 1;
|
||||
}
|
||||
public boolean hasRightSleeve() {
|
||||
return ((bitmask >> 3) & 1) == 1;
|
||||
}
|
||||
|
||||
public boolean hasRightPants() {
|
||||
return ((bitmask >> 5) & 1) == 1;
|
||||
}
|
||||
public boolean hasLeftPants() {
|
||||
return ((bitmask >> 4) & 1) == 1;
|
||||
}
|
||||
|
||||
public boolean hasHat() {
|
||||
return ((bitmask >> 6) & 1) == 1;
|
||||
}
|
||||
public boolean hasRightPants() {
|
||||
return ((bitmask >> 5) & 1) == 1;
|
||||
}
|
||||
|
||||
public boolean hasHat() {
|
||||
return ((bitmask >> 6) & 1) == 1;
|
||||
}
|
||||
}
|
||||
|
@ -2,51 +2,56 @@ package com.velocitypowered.api.proxy.player;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import net.kyori.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import net.kyori.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the tab list of a {@link Player}.
|
||||
*/
|
||||
public interface TabList {
|
||||
/**
|
||||
* Sets the tab list header and footer for the player.
|
||||
* @param header the header component
|
||||
* @param footer the footer component
|
||||
*/
|
||||
void setHeaderAndFooter(Component header, Component footer);
|
||||
|
||||
/**
|
||||
* Clears the tab list header and footer for the player.
|
||||
*/
|
||||
void clearHeaderAndFooter();
|
||||
|
||||
/**
|
||||
* Adds a {@link TabListEntry} to the {@link Player}'s tab list.
|
||||
* @param entry to add to the tab list
|
||||
*/
|
||||
void addEntry(TabListEntry entry);
|
||||
|
||||
/**
|
||||
* Removes the {@link TabListEntry} from the tab list with the {@link GameProfile}
|
||||
* identified with the specified {@link UUID}.
|
||||
* @param uuid of the
|
||||
* @return {@link Optional} containing the removed {@link TabListEntry} if present,
|
||||
* otherwise {@link Optional#empty()}
|
||||
*/
|
||||
Optional<TabListEntry> removeEntry(UUID uuid);
|
||||
|
||||
/**
|
||||
* Returns an immutable {@link Collection} of the {@link TabListEntry}s in the tab list.
|
||||
* @return immutable {@link Collection} of tab list entries
|
||||
*/
|
||||
Collection<TabListEntry> getEntries();
|
||||
/**
|
||||
* Sets the tab list header and footer for the player.
|
||||
*
|
||||
* @param header the header component
|
||||
* @param footer the footer component
|
||||
*/
|
||||
void setHeaderAndFooter(Component header, Component footer);
|
||||
|
||||
// Necessary because the TabListEntry implementation isn't in the api
|
||||
@Deprecated
|
||||
TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency, int gameMode);
|
||||
/**
|
||||
* Clears the tab list header and footer for the player.
|
||||
*/
|
||||
void clearHeaderAndFooter();
|
||||
|
||||
/**
|
||||
* Adds a {@link TabListEntry} to the {@link Player}'s tab list.
|
||||
*
|
||||
* @param entry to add to the tab list
|
||||
*/
|
||||
void addEntry(TabListEntry entry);
|
||||
|
||||
/**
|
||||
* Removes the {@link TabListEntry} from the tab list with the {@link GameProfile} identified with
|
||||
* the specified {@link UUID}.
|
||||
*
|
||||
* @param uuid of the
|
||||
* @return {@link Optional} containing the removed {@link TabListEntry} if present, otherwise
|
||||
* {@link Optional#empty()}
|
||||
*/
|
||||
Optional<TabListEntry> removeEntry(UUID uuid);
|
||||
|
||||
/**
|
||||
* Returns an immutable {@link Collection} of the {@link TabListEntry}s in the tab list.
|
||||
*
|
||||
* @return immutable {@link Collection} of tab list entries
|
||||
*/
|
||||
Collection<TabListEntry> getEntries();
|
||||
|
||||
// Necessary because the TabListEntry implementation isn't in the api
|
||||
@Deprecated
|
||||
TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
||||
int gameMode);
|
||||
}
|
||||
|
@ -1,177 +1,195 @@
|
||||
package com.velocitypowered.api.proxy.player;
|
||||
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import java.util.Optional;
|
||||
import net.kyori.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a single entry in a {@link TabList}.
|
||||
*/
|
||||
public interface TabListEntry {
|
||||
/**
|
||||
* Returns the parent {@link TabList} of this {@code this} {@link TabListEntry}.
|
||||
* @return parent {@link TabList}
|
||||
*/
|
||||
TabList getTabList();
|
||||
|
||||
/**
|
||||
* Returns the {@link GameProfile} of the entry, which uniquely identifies the entry
|
||||
* with the containing {@link java.util.UUID}, as well as deciding what is shown
|
||||
* as the player head in the tab list.
|
||||
* @return {@link GameProfile} of the entry
|
||||
*/
|
||||
GameProfile getProfile();
|
||||
|
||||
/**
|
||||
* Returns {@link Optional} text {@link Component}, which if present is the text displayed for
|
||||
* {@code this} entry in the {@link TabList}, otherwise {@link GameProfile#getName()} is shown.
|
||||
* @return {@link Optional} text {@link Component} of name displayed in the tab list
|
||||
*/
|
||||
Optional<Component> getDisplayName();
|
||||
|
||||
/**
|
||||
* Sets the text {@link Component} to be displayed for {@code this} {@link TabListEntry}.
|
||||
* If {@code null}, {@link GameProfile#getName()} will be shown.
|
||||
* @param displayName to show in the {@link TabList} for {@code this} entry
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
TabListEntry setDisplayName(@Nullable Component displayName);
|
||||
|
||||
/**
|
||||
* Returns the latency for {@code this} entry.
|
||||
* <p>The icon shown in the tab list is calculated by the latency in the following way:<p>
|
||||
* <ul>
|
||||
* <li>A negative latency will display the no connection icon</li>
|
||||
* <li>0-150 will display 5 bars</li>
|
||||
* <li>150-300 will display 4 bars</li>
|
||||
* <li>300-600 will display 3 bars</li>
|
||||
* <li>600-1000 will display 2 bars</li>
|
||||
* <li>A latency move than 1 second will display 1 bar</li>
|
||||
* <li></li>
|
||||
* </ul>
|
||||
* @return latency set for {@code this} entry
|
||||
*/
|
||||
int getLatency();
|
||||
|
||||
/**
|
||||
* Sets the latency for {@code this} entry to the specified value
|
||||
* @see #getLatency()
|
||||
* @param latency to changed to
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
TabListEntry setLatency(int latency);
|
||||
|
||||
/**
|
||||
* Gets the game mode {@code this} entry has been set to.
|
||||
* <p>The number corresponds to the game mode in the following way:</p>
|
||||
* <ol start="0">
|
||||
* <li>Survival</li>
|
||||
* <li>Creative</li>
|
||||
* <li>Adventure</li>
|
||||
* <li>Spectator</li>
|
||||
* </ol>
|
||||
* @return the game mode
|
||||
*/
|
||||
int getGameMode();
|
||||
|
||||
/**
|
||||
* Sets the game mode for {@code this} entry to the specified value
|
||||
* @see #getGameMode()
|
||||
* @param gameMode to change to
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
TabListEntry setGameMode(int gameMode);
|
||||
|
||||
/**
|
||||
* Returns a {@link Builder} to create a {@link TabListEntry}.
|
||||
* @return {@link TabListEntry} builder
|
||||
*/
|
||||
static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a builder which creates {@link TabListEntry}s.
|
||||
* @see TabListEntry
|
||||
*/
|
||||
class Builder {
|
||||
private @Nullable TabList tabList;
|
||||
private @Nullable GameProfile profile;
|
||||
private @Nullable Component displayName;
|
||||
private int latency = 0;
|
||||
private int gameMode = 0;
|
||||
|
||||
private Builder() {}
|
||||
|
||||
/**
|
||||
* Sets the parent {@link TabList} for this entry,
|
||||
* the entry will only be able to be added to that specific {@link TabList}.
|
||||
* @param tabList to set
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
public Builder tabList(TabList tabList) {
|
||||
this.tabList = tabList;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link GameProfile} of the {@link TabListEntry}.
|
||||
* @see TabListEntry#getProfile()
|
||||
* @param profile to set
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
public Builder profile(GameProfile profile) {
|
||||
this.profile = profile;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the displayed name of the {@link TabListEntry}
|
||||
* @see TabListEntry#getDisplayName()
|
||||
* @param displayName to set
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
public Builder displayName(@Nullable Component displayName) {
|
||||
this.displayName = displayName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the latency of the {@link TabListEntry}
|
||||
* @see TabListEntry#getLatency()
|
||||
* @param latency to set
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
public Builder latency(int latency) {
|
||||
this.latency = latency;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the game mode of the {@link TabListEntry}
|
||||
* @see TabListEntry#getGameMode()
|
||||
* @param gameMode to set
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
public Builder gameMode(int gameMode) {
|
||||
this.gameMode = gameMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the {@link TabListEntry} specified by {@code this} {@link Builder}.
|
||||
* @return the constructed {@link TabListEntry}
|
||||
*/
|
||||
public TabListEntry build() {
|
||||
if (tabList == null) {
|
||||
throw new IllegalStateException("The Tablist must be set when building a TabListEntry");
|
||||
}
|
||||
if (profile == null) {
|
||||
throw new IllegalStateException("The GameProfile must be set when building a TabListEntry");
|
||||
}
|
||||
return tabList.buildEntry(profile, displayName, latency, gameMode);
|
||||
}
|
||||
/**
|
||||
* Returns the parent {@link TabList} of this {@code this} {@link TabListEntry}.
|
||||
*
|
||||
* @return parent {@link TabList}
|
||||
*/
|
||||
TabList getTabList();
|
||||
|
||||
/**
|
||||
* Returns the {@link GameProfile} of the entry, which uniquely identifies the entry with the
|
||||
* containing {@link java.util.UUID}, as well as deciding what is shown as the player head in the
|
||||
* tab list.
|
||||
*
|
||||
* @return {@link GameProfile} of the entry
|
||||
*/
|
||||
GameProfile getProfile();
|
||||
|
||||
/**
|
||||
* Returns {@link Optional} text {@link Component}, which if present is the text displayed for
|
||||
* {@code this} entry in the {@link TabList}, otherwise {@link GameProfile#getName()} is shown.
|
||||
*
|
||||
* @return {@link Optional} text {@link Component} of name displayed in the tab list
|
||||
*/
|
||||
Optional<Component> getDisplayName();
|
||||
|
||||
/**
|
||||
* Sets the text {@link Component} to be displayed for {@code this} {@link TabListEntry}. If
|
||||
* {@code null}, {@link GameProfile#getName()} will be shown.
|
||||
*
|
||||
* @param displayName to show in the {@link TabList} for {@code this} entry
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
TabListEntry setDisplayName(@Nullable Component displayName);
|
||||
|
||||
/**
|
||||
* Returns the latency for {@code this} entry.
|
||||
* <p>The icon shown in the tab list is calculated by the latency in the following way:<p>
|
||||
* <ul>
|
||||
* <li>A negative latency will display the no connection icon</li>
|
||||
* <li>0-150 will display 5 bars</li>
|
||||
* <li>150-300 will display 4 bars</li>
|
||||
* <li>300-600 will display 3 bars</li>
|
||||
* <li>600-1000 will display 2 bars</li>
|
||||
* <li>A latency move than 1 second will display 1 bar</li>
|
||||
* <li></li>
|
||||
* </ul>
|
||||
*
|
||||
* @return latency set for {@code this} entry
|
||||
*/
|
||||
int getLatency();
|
||||
|
||||
/**
|
||||
* Sets the latency for {@code this} entry to the specified value
|
||||
*
|
||||
* @param latency to changed to
|
||||
* @return {@code this}, for chaining
|
||||
* @see #getLatency()
|
||||
*/
|
||||
TabListEntry setLatency(int latency);
|
||||
|
||||
/**
|
||||
* Gets the game mode {@code this} entry has been set to.
|
||||
* <p>The number corresponds to the game mode in the following way:</p>
|
||||
* <ol start="0">
|
||||
* <li>Survival</li>
|
||||
* <li>Creative</li>
|
||||
* <li>Adventure</li>
|
||||
* <li>Spectator</li>
|
||||
* </ol>
|
||||
*
|
||||
* @return the game mode
|
||||
*/
|
||||
int getGameMode();
|
||||
|
||||
/**
|
||||
* Sets the game mode for {@code this} entry to the specified value
|
||||
*
|
||||
* @param gameMode to change to
|
||||
* @return {@code this}, for chaining
|
||||
* @see #getGameMode()
|
||||
*/
|
||||
TabListEntry setGameMode(int gameMode);
|
||||
|
||||
/**
|
||||
* Returns a {@link Builder} to create a {@link TabListEntry}.
|
||||
*
|
||||
* @return {@link TabListEntry} builder
|
||||
*/
|
||||
static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a builder which creates {@link TabListEntry}s.
|
||||
*
|
||||
* @see TabListEntry
|
||||
*/
|
||||
class Builder {
|
||||
|
||||
private @Nullable TabList tabList;
|
||||
private @Nullable GameProfile profile;
|
||||
private @Nullable Component displayName;
|
||||
private int latency = 0;
|
||||
private int gameMode = 0;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent {@link TabList} for this entry, the entry will only be able to be added to
|
||||
* that specific {@link TabList}.
|
||||
*
|
||||
* @param tabList to set
|
||||
* @return {@code this}, for chaining
|
||||
*/
|
||||
public Builder tabList(TabList tabList) {
|
||||
this.tabList = tabList;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link GameProfile} of the {@link TabListEntry}.
|
||||
*
|
||||
* @param profile to set
|
||||
* @return {@code this}, for chaining
|
||||
* @see TabListEntry#getProfile()
|
||||
*/
|
||||
public Builder profile(GameProfile profile) {
|
||||
this.profile = profile;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the displayed name of the {@link TabListEntry}
|
||||
*
|
||||
* @param displayName to set
|
||||
* @return {@code this}, for chaining
|
||||
* @see TabListEntry#getDisplayName()
|
||||
*/
|
||||
public Builder displayName(@Nullable Component displayName) {
|
||||
this.displayName = displayName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the latency of the {@link TabListEntry}
|
||||
*
|
||||
* @param latency to set
|
||||
* @return {@code this}, for chaining
|
||||
* @see TabListEntry#getLatency()
|
||||
*/
|
||||
public Builder latency(int latency) {
|
||||
this.latency = latency;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the game mode of the {@link TabListEntry}
|
||||
*
|
||||
* @param gameMode to set
|
||||
* @return {@code this}, for chaining
|
||||
* @see TabListEntry#getGameMode()
|
||||
*/
|
||||
public Builder gameMode(int gameMode) {
|
||||
this.gameMode = gameMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the {@link TabListEntry} specified by {@code this} {@link Builder}.
|
||||
*
|
||||
* @return the constructed {@link TabListEntry}
|
||||
*/
|
||||
public TabListEntry build() {
|
||||
if (tabList == null) {
|
||||
throw new IllegalStateException("The Tablist must be set when building a TabListEntry");
|
||||
}
|
||||
if (profile == null) {
|
||||
throw new IllegalStateException("The GameProfile must be set when building a TabListEntry");
|
||||
}
|
||||
return tabList.buildEntry(profile, displayName, latency, gameMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,301 +3,323 @@ package com.velocitypowered.api.proxy.server;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.proxy.config.ProxyConfig;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* GS4 query response. This class is immutable.
|
||||
*/
|
||||
public final class QueryResponse {
|
||||
private final String hostname;
|
||||
private final String gameVersion;
|
||||
private final String map;
|
||||
private final int currentPlayers;
|
||||
private final int maxPlayers;
|
||||
private final String proxyHost;
|
||||
private final int proxyPort;
|
||||
private final Collection<String> players;
|
||||
private final String proxyVersion;
|
||||
private final Collection<PluginInformation> plugins;
|
||||
|
||||
private QueryResponse(String hostname, String gameVersion, String map, int currentPlayers, int maxPlayers, String proxyHost, int proxyPort, Collection<String> players, String proxyVersion, Collection<PluginInformation> plugins) {
|
||||
this.hostname = hostname;
|
||||
this.gameVersion = gameVersion;
|
||||
this.map = map;
|
||||
this.currentPlayers = currentPlayers;
|
||||
this.maxPlayers = maxPlayers;
|
||||
this.proxyHost = proxyHost;
|
||||
this.proxyPort = proxyPort;
|
||||
this.players = players;
|
||||
this.proxyVersion = proxyVersion;
|
||||
this.plugins = plugins;
|
||||
private final String hostname;
|
||||
private final String gameVersion;
|
||||
private final String map;
|
||||
private final int currentPlayers;
|
||||
private final int maxPlayers;
|
||||
private final String proxyHost;
|
||||
private final int proxyPort;
|
||||
private final Collection<String> players;
|
||||
private final String proxyVersion;
|
||||
private final Collection<PluginInformation> plugins;
|
||||
|
||||
private QueryResponse(String hostname, String gameVersion, String map, int currentPlayers,
|
||||
int maxPlayers, String proxyHost, int proxyPort, Collection<String> players,
|
||||
String proxyVersion, Collection<PluginInformation> plugins) {
|
||||
this.hostname = hostname;
|
||||
this.gameVersion = gameVersion;
|
||||
this.map = map;
|
||||
this.currentPlayers = currentPlayers;
|
||||
this.maxPlayers = maxPlayers;
|
||||
this.proxyHost = proxyHost;
|
||||
this.proxyPort = proxyPort;
|
||||
this.players = players;
|
||||
this.proxyVersion = proxyVersion;
|
||||
this.plugins = plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hostname which will be used to reply to the query. By default it is {@link
|
||||
* ProxyConfig#getMotdComponent()} in plain text without colour codes.
|
||||
*
|
||||
* @return hostname
|
||||
*/
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get game version which will be used to reply to the query. By default supported Minecraft
|
||||
* versions range is sent.
|
||||
*
|
||||
* @return game version
|
||||
*/
|
||||
public String getGameVersion() {
|
||||
return gameVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get map name which will be used to reply to the query. By default {@link
|
||||
* ProxyConfig#getQueryMap()} is sent.
|
||||
*
|
||||
* @return map name
|
||||
*/
|
||||
public String getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current online player count which will be used to reply to the query.
|
||||
*
|
||||
* @return online player count
|
||||
*/
|
||||
public int getCurrentPlayers() {
|
||||
return currentPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get max player count which will be used to reply to the query.
|
||||
*
|
||||
* @return max player count
|
||||
*/
|
||||
public int getMaxPlayers() {
|
||||
return maxPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get proxy (public facing) hostname
|
||||
*
|
||||
* @return proxy hostname
|
||||
*/
|
||||
public String getProxyHost() {
|
||||
return proxyHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get proxy (public facing) port
|
||||
*
|
||||
* @return proxy port
|
||||
*/
|
||||
public int getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get collection of players which will be used to reply to the query.
|
||||
*
|
||||
* @return collection of players
|
||||
*/
|
||||
public Collection<String> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server software (name and version) which will be used to reply to the query.
|
||||
*
|
||||
* @return server software
|
||||
*/
|
||||
public String getProxyVersion() {
|
||||
return proxyVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of plugins which will be used to reply to the query.
|
||||
*
|
||||
* @return collection of plugins
|
||||
*/
|
||||
public Collection<PluginInformation> getPlugins() {
|
||||
return plugins;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link Builder} instance from data represented by this response
|
||||
*
|
||||
* @return {@link QueryResponse} builder
|
||||
*/
|
||||
public Builder toBuilder() {
|
||||
return QueryResponse.builder()
|
||||
.hostname(getHostname())
|
||||
.gameVersion(getGameVersion())
|
||||
.map(getMap())
|
||||
.currentPlayers(getCurrentPlayers())
|
||||
.maxPlayers(getMaxPlayers())
|
||||
.proxyHost(getProxyHost())
|
||||
.proxyPort(getProxyPort())
|
||||
.players(getPlayers())
|
||||
.proxyVersion(getProxyVersion())
|
||||
.plugins(getPlugins());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Builder} instance
|
||||
*
|
||||
* @return {@link QueryResponse} builder
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link QueryResponse} objects.
|
||||
*/
|
||||
public static final class Builder {
|
||||
|
||||
@MonotonicNonNull
|
||||
private String hostname;
|
||||
|
||||
@MonotonicNonNull
|
||||
private String gameVersion;
|
||||
|
||||
@MonotonicNonNull
|
||||
private String map;
|
||||
|
||||
@MonotonicNonNull
|
||||
private String proxyHost;
|
||||
|
||||
@MonotonicNonNull
|
||||
private String proxyVersion;
|
||||
|
||||
private int currentPlayers;
|
||||
private int maxPlayers;
|
||||
private int proxyPort;
|
||||
|
||||
private List<String> players = new ArrayList<>();
|
||||
private List<PluginInformation> plugins = new ArrayList<>();
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
public Builder hostname(String hostname) {
|
||||
this.hostname = Preconditions.checkNotNull(hostname, "hostname");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder gameVersion(String gameVersion) {
|
||||
this.gameVersion = Preconditions.checkNotNull(gameVersion, "gameVersion");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder map(String map) {
|
||||
this.map = Preconditions.checkNotNull(map, "map");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder currentPlayers(int currentPlayers) {
|
||||
Preconditions.checkArgument(currentPlayers >= 0, "currentPlayers cannot be negative");
|
||||
this.currentPlayers = currentPlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder maxPlayers(int maxPlayers) {
|
||||
Preconditions.checkArgument(maxPlayers >= 0, "maxPlayers cannot be negative");
|
||||
this.maxPlayers = maxPlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder proxyHost(String proxyHost) {
|
||||
this.proxyHost = Preconditions.checkNotNull(proxyHost, "proxyHost");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder proxyPort(int proxyPort) {
|
||||
Preconditions
|
||||
.checkArgument(proxyPort >= 1 && proxyPort <= 65535, "proxyPort must be between 1-65535");
|
||||
this.proxyPort = proxyPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder players(Collection<String> players) {
|
||||
this.players.addAll(Preconditions.checkNotNull(players, "players"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder players(String... players) {
|
||||
this.players.addAll(Arrays.asList(Preconditions.checkNotNull(players, "players")));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearPlayers() {
|
||||
this.players.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder proxyVersion(String proxyVersion) {
|
||||
this.proxyVersion = Preconditions.checkNotNull(proxyVersion, "proxyVersion");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder plugins(Collection<PluginInformation> plugins) {
|
||||
this.plugins.addAll(Preconditions.checkNotNull(plugins, "plugins"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder plugins(PluginInformation... plugins) {
|
||||
this.plugins.addAll(Arrays.asList(Preconditions.checkNotNull(plugins, "plugins")));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearPlugins() {
|
||||
this.plugins.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hostname which will be used to reply to the query. By default it is {@link ProxyConfig#getMotdComponent()} in plain text without colour codes.
|
||||
* @return hostname
|
||||
* Builds new {@link QueryResponse} with supplied data
|
||||
*
|
||||
* @return response
|
||||
*/
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
public QueryResponse build() {
|
||||
return new QueryResponse(
|
||||
Preconditions.checkNotNull(hostname, "hostname"),
|
||||
Preconditions.checkNotNull(gameVersion, "gameVersion"),
|
||||
Preconditions.checkNotNull(map, "map"),
|
||||
currentPlayers,
|
||||
maxPlayers,
|
||||
Preconditions.checkNotNull(proxyHost, "proxyHost"),
|
||||
proxyPort,
|
||||
ImmutableList.copyOf(players),
|
||||
Preconditions.checkNotNull(proxyVersion, "proxyVersion"),
|
||||
ImmutableList.copyOf(plugins)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin information
|
||||
*/
|
||||
public static class PluginInformation {
|
||||
|
||||
private String name;
|
||||
private String version;
|
||||
|
||||
public PluginInformation(String name, String version) {
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get game version which will be used to reply to the query. By default supported Minecraft versions range is sent.
|
||||
* @return game version
|
||||
*/
|
||||
public String getGameVersion() {
|
||||
return gameVersion;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get map name which will be used to reply to the query. By default {@link ProxyConfig#getQueryMap()} is sent.
|
||||
* @return map name
|
||||
*/
|
||||
public String getMap() {
|
||||
return map;
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current online player count which will be used to reply to the query.
|
||||
* @return online player count
|
||||
*/
|
||||
public int getCurrentPlayers() {
|
||||
return currentPlayers;
|
||||
public void setVersion(@Nullable String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get max player count which will be used to reply to the query.
|
||||
* @return max player count
|
||||
*/
|
||||
public int getMaxPlayers() {
|
||||
return maxPlayers;
|
||||
@Nullable
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get proxy (public facing) hostname
|
||||
* @return proxy hostname
|
||||
*/
|
||||
public String getProxyHost() {
|
||||
return proxyHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get proxy (public facing) port
|
||||
* @return proxy port
|
||||
*/
|
||||
public int getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get collection of players which will be used to reply to the query.
|
||||
* @return collection of players
|
||||
*/
|
||||
public Collection<String> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server software (name and version) which will be used to reply to the query.
|
||||
* @return server software
|
||||
*/
|
||||
public String getProxyVersion() {
|
||||
return proxyVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of plugins which will be used to reply to the query.
|
||||
* @return collection of plugins
|
||||
*/
|
||||
public Collection<PluginInformation> getPlugins() {
|
||||
return plugins;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link Builder} instance from data represented by this response
|
||||
* @return {@link QueryResponse} builder
|
||||
*/
|
||||
public Builder toBuilder() {
|
||||
return QueryResponse.builder()
|
||||
.hostname(getHostname())
|
||||
.gameVersion(getGameVersion())
|
||||
.map(getMap())
|
||||
.currentPlayers(getCurrentPlayers())
|
||||
.maxPlayers(getMaxPlayers())
|
||||
.proxyHost(getProxyHost())
|
||||
.proxyPort(getProxyPort())
|
||||
.players(getPlayers())
|
||||
.proxyVersion(getProxyVersion())
|
||||
.plugins(getPlugins());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Builder} instance
|
||||
* @return {@link QueryResponse} builder
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link QueryResponse} objects.
|
||||
*/
|
||||
public static final class Builder {
|
||||
@MonotonicNonNull
|
||||
private String hostname;
|
||||
|
||||
@MonotonicNonNull
|
||||
private String gameVersion;
|
||||
|
||||
@MonotonicNonNull
|
||||
private String map;
|
||||
|
||||
@MonotonicNonNull
|
||||
private String proxyHost;
|
||||
|
||||
@MonotonicNonNull
|
||||
private String proxyVersion;
|
||||
|
||||
private int currentPlayers;
|
||||
private int maxPlayers;
|
||||
private int proxyPort;
|
||||
|
||||
private List<String> players = new ArrayList<>();
|
||||
private List<PluginInformation> plugins = new ArrayList<>();
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public Builder hostname(String hostname) {
|
||||
this.hostname = Preconditions.checkNotNull(hostname, "hostname");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder gameVersion(String gameVersion) {
|
||||
this.gameVersion = Preconditions.checkNotNull(gameVersion, "gameVersion");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder map(String map) {
|
||||
this.map = Preconditions.checkNotNull(map, "map");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder currentPlayers(int currentPlayers) {
|
||||
Preconditions.checkArgument(currentPlayers >= 0, "currentPlayers cannot be negative");
|
||||
this.currentPlayers = currentPlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder maxPlayers(int maxPlayers) {
|
||||
Preconditions.checkArgument(maxPlayers >= 0, "maxPlayers cannot be negative");
|
||||
this.maxPlayers = maxPlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder proxyHost(String proxyHost) {
|
||||
this.proxyHost = Preconditions.checkNotNull(proxyHost, "proxyHost");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder proxyPort(int proxyPort) {
|
||||
Preconditions.checkArgument(proxyPort >= 1 && proxyPort <= 65535, "proxyPort must be between 1-65535");
|
||||
this.proxyPort = proxyPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder players(Collection<String> players) {
|
||||
this.players.addAll(Preconditions.checkNotNull(players, "players"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder players(String... players) {
|
||||
this.players.addAll(Arrays.asList(Preconditions.checkNotNull(players, "players")));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearPlayers() {
|
||||
this.players.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder proxyVersion(String proxyVersion) {
|
||||
this.proxyVersion = Preconditions.checkNotNull(proxyVersion, "proxyVersion");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder plugins(Collection<PluginInformation> plugins) {
|
||||
this.plugins.addAll(Preconditions.checkNotNull(plugins, "plugins"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder plugins(PluginInformation... plugins) {
|
||||
this.plugins.addAll(Arrays.asList(Preconditions.checkNotNull(plugins, "plugins")));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearPlugins() {
|
||||
this.plugins.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds new {@link QueryResponse} with supplied data
|
||||
* @return response
|
||||
*/
|
||||
public QueryResponse build() {
|
||||
return new QueryResponse(
|
||||
Preconditions.checkNotNull(hostname, "hostname"),
|
||||
Preconditions.checkNotNull(gameVersion, "gameVersion"),
|
||||
Preconditions.checkNotNull(map, "map"),
|
||||
currentPlayers,
|
||||
maxPlayers,
|
||||
Preconditions.checkNotNull(proxyHost, "proxyHost"),
|
||||
proxyPort,
|
||||
ImmutableList.copyOf(players),
|
||||
Preconditions.checkNotNull(proxyVersion, "proxyVersion"),
|
||||
ImmutableList.copyOf(plugins)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin information
|
||||
*/
|
||||
public static class PluginInformation {
|
||||
private String name;
|
||||
private String version;
|
||||
|
||||
public PluginInformation(String name, String version) {
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setVersion(@Nullable String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public static PluginInformation of(String name, @Nullable String version) {
|
||||
return new PluginInformation(name, version);
|
||||
}
|
||||
public static PluginInformation of(String name, @Nullable String version) {
|
||||
return new PluginInformation(name, version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ 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;
|
||||
|
||||
@ -10,21 +9,25 @@ 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();
|
||||
/**
|
||||
* Returns the {@link ServerInfo} for this server.
|
||||
*
|
||||
* @return the server info
|
||||
*/
|
||||
ServerInfo getServerInfo();
|
||||
|
||||
/**
|
||||
* Attempts to ping the remote server and return the server list ping result.
|
||||
* @return the server ping result from the server
|
||||
*/
|
||||
CompletableFuture<ServerPing> ping();
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
@ -1,55 +1,61 @@
|
||||
package com.velocitypowered.api.proxy.server;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Objects;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* ServerInfo represents a server that a player can connect to. This object is immutable and safe for concurrent access.
|
||||
* ServerInfo represents a server that a player can connect to. This object is immutable and safe
|
||||
* for concurrent access.
|
||||
*/
|
||||
public final class ServerInfo {
|
||||
private final String name;
|
||||
private final InetSocketAddress address;
|
||||
|
||||
/**
|
||||
* Creates a new ServerInfo object.
|
||||
* @param name the name for the server
|
||||
* @param address the address of the server to connect to
|
||||
*/
|
||||
public ServerInfo(String name, InetSocketAddress address) {
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.address = Preconditions.checkNotNull(address, "address");
|
||||
}
|
||||
private final String name;
|
||||
private final InetSocketAddress address;
|
||||
|
||||
public final String getName() {
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* Creates a new ServerInfo object.
|
||||
*
|
||||
* @param name the name for the server
|
||||
* @param address the address of the server to connect to
|
||||
*/
|
||||
public ServerInfo(String name, InetSocketAddress address) {
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.address = Preconditions.checkNotNull(address, "address");
|
||||
}
|
||||
|
||||
public final InetSocketAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
public final String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerInfo{" +
|
||||
"name='" + name + '\'' +
|
||||
", address=" + address +
|
||||
'}';
|
||||
}
|
||||
public final InetSocketAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ServerInfo that = (ServerInfo) o;
|
||||
return Objects.equals(name, that.name) &&
|
||||
Objects.equals(address, that.address);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerInfo{" +
|
||||
"name='" + name + '\'' +
|
||||
", address=" + address +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return Objects.hash(name, address);
|
||||
@Override
|
||||
public final boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ServerInfo that = (ServerInfo) o;
|
||||
return Objects.equals(name, that.name) &&
|
||||
Objects.equals(address, that.address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return Objects.hash(name, address);
|
||||
}
|
||||
}
|
||||
|
@ -4,308 +4,319 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.util.Favicon;
|
||||
import com.velocitypowered.api.util.ModInfo;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import net.kyori.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents a 1.7 and above server list ping response. This class is immutable.
|
||||
*/
|
||||
public final class ServerPing {
|
||||
private final Version version;
|
||||
private final @Nullable Players players;
|
||||
private final Component description;
|
||||
private final @Nullable Favicon favicon;
|
||||
private final @Nullable ModInfo modinfo;
|
||||
|
||||
public ServerPing(Version version, @Nullable Players players, Component description, @Nullable Favicon favicon) {
|
||||
this(version, players, description, favicon, ModInfo.DEFAULT);
|
||||
private final Version version;
|
||||
private final @Nullable Players players;
|
||||
private final Component description;
|
||||
private final @Nullable Favicon favicon;
|
||||
private final @Nullable ModInfo modinfo;
|
||||
|
||||
public ServerPing(Version version, @Nullable Players players, Component description,
|
||||
@Nullable Favicon favicon) {
|
||||
this(version, players, description, favicon, ModInfo.DEFAULT);
|
||||
}
|
||||
|
||||
public ServerPing(Version version, @Nullable Players players, Component description,
|
||||
@Nullable Favicon favicon, @Nullable ModInfo modinfo) {
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
this.players = players;
|
||||
this.description = Preconditions.checkNotNull(description, "description");
|
||||
this.favicon = favicon;
|
||||
this.modinfo = modinfo;
|
||||
}
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public Optional<Players> getPlayers() {
|
||||
return Optional.ofNullable(players);
|
||||
}
|
||||
|
||||
public Component getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public Optional<Favicon> getFavicon() {
|
||||
return Optional.ofNullable(favicon);
|
||||
}
|
||||
|
||||
public Optional<ModInfo> getModinfo() {
|
||||
return Optional.ofNullable(modinfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerPing{" +
|
||||
"version=" + version +
|
||||
", players=" + players +
|
||||
", description=" + description +
|
||||
", favicon='" + favicon + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public Builder asBuilder() {
|
||||
Builder builder = new Builder();
|
||||
builder.version = version;
|
||||
if (players != null) {
|
||||
builder.onlinePlayers = players.online;
|
||||
builder.maximumPlayers = players.max;
|
||||
builder.samplePlayers.addAll(players.sample);
|
||||
} else {
|
||||
builder.nullOutPlayers = true;
|
||||
}
|
||||
builder.description = description;
|
||||
builder.favicon = favicon;
|
||||
builder.nullOutModinfo = modinfo == null;
|
||||
if (modinfo != null) {
|
||||
builder.modType = modinfo.getType();
|
||||
builder.mods.addAll(modinfo.getMods());
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link ServerPing} objects.
|
||||
*/
|
||||
public static final class Builder {
|
||||
|
||||
private Version version = new Version(0, "Unknown");
|
||||
private int onlinePlayers;
|
||||
private int maximumPlayers;
|
||||
private final List<SamplePlayer> samplePlayers = new ArrayList<>();
|
||||
private String modType = "FML";
|
||||
private final List<ModInfo.Mod> mods = new ArrayList<>();
|
||||
private @Nullable Component description;
|
||||
private @Nullable Favicon favicon;
|
||||
private boolean nullOutPlayers;
|
||||
private boolean nullOutModinfo;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public ServerPing(Version version, @Nullable Players players, Component description, @Nullable Favicon favicon, @Nullable ModInfo modinfo) {
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
this.players = players;
|
||||
this.description = Preconditions.checkNotNull(description, "description");
|
||||
this.favicon = favicon;
|
||||
this.modinfo = modinfo;
|
||||
public Builder version(Version version) {
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onlinePlayers(int onlinePlayers) {
|
||||
this.onlinePlayers = onlinePlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder maximumPlayers(int maximumPlayers) {
|
||||
this.maximumPlayers = maximumPlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder samplePlayers(SamplePlayer... players) {
|
||||
this.samplePlayers.addAll(Arrays.asList(players));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder modType(String modType) {
|
||||
this.modType = Preconditions.checkNotNull(modType, "modType");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder mods(ModInfo.Mod... mods) {
|
||||
this.mods.addAll(Arrays.asList(mods));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearMods() {
|
||||
this.mods.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearSamplePlayers() {
|
||||
this.samplePlayers.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder notModCompatible() {
|
||||
this.nullOutModinfo = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder nullPlayers() {
|
||||
this.nullOutPlayers = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder description(Component description) {
|
||||
this.description = Preconditions.checkNotNull(description, "description");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder favicon(Favicon favicon) {
|
||||
this.favicon = Preconditions.checkNotNull(favicon, "favicon");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerPing build() {
|
||||
if (this.version == null) {
|
||||
throw new IllegalStateException("version not specified");
|
||||
}
|
||||
if (this.description == null) {
|
||||
throw new IllegalStateException("no server description supplied");
|
||||
}
|
||||
return new ServerPing(version,
|
||||
nullOutPlayers ? null : new Players(onlinePlayers, maximumPlayers, samplePlayers),
|
||||
description, favicon, nullOutModinfo ? null : new ModInfo(modType, mods));
|
||||
}
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
return version;
|
||||
}
|
||||
|
||||
public Optional<Players> getPlayers() {
|
||||
return Optional.ofNullable(players);
|
||||
public int getOnlinePlayers() {
|
||||
return onlinePlayers;
|
||||
}
|
||||
|
||||
public Component getDescription() {
|
||||
return description;
|
||||
public int getMaximumPlayers() {
|
||||
return maximumPlayers;
|
||||
}
|
||||
|
||||
public List<SamplePlayer> getSamplePlayers() {
|
||||
return samplePlayers;
|
||||
}
|
||||
|
||||
public Optional<Component> getDescription() {
|
||||
return Optional.ofNullable(description);
|
||||
}
|
||||
|
||||
public Optional<Favicon> getFavicon() {
|
||||
return Optional.ofNullable(favicon);
|
||||
return Optional.ofNullable(favicon);
|
||||
}
|
||||
|
||||
public Optional<ModInfo> getModinfo() {
|
||||
return Optional.ofNullable(modinfo);
|
||||
public String getModType() {
|
||||
return modType;
|
||||
}
|
||||
|
||||
public List<ModInfo.Mod> getMods() {
|
||||
return mods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerPing{" +
|
||||
"version=" + version +
|
||||
", players=" + players +
|
||||
", description=" + description +
|
||||
", favicon='" + favicon + '\'' +
|
||||
'}';
|
||||
return "Builder{" +
|
||||
"version=" + version +
|
||||
", onlinePlayers=" + onlinePlayers +
|
||||
", maximumPlayers=" + maximumPlayers +
|
||||
", samplePlayers=" + samplePlayers +
|
||||
", modType=" + modType +
|
||||
", mods=" + mods +
|
||||
", description=" + description +
|
||||
", favicon=" + favicon +
|
||||
", nullOutPlayers=" + nullOutPlayers +
|
||||
", nullOutModinfo=" + nullOutModinfo +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Version {
|
||||
|
||||
private final int protocol;
|
||||
private final String name;
|
||||
|
||||
public Version(int protocol, String name) {
|
||||
this.protocol = protocol;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Builder asBuilder() {
|
||||
Builder builder = new Builder();
|
||||
builder.version = version;
|
||||
if (players != null) {
|
||||
builder.onlinePlayers = players.online;
|
||||
builder.maximumPlayers = players.max;
|
||||
builder.samplePlayers.addAll(players.sample);
|
||||
} else {
|
||||
builder.nullOutPlayers = true;
|
||||
}
|
||||
builder.description = description;
|
||||
builder.favicon = favicon;
|
||||
builder.nullOutModinfo = modinfo == null;
|
||||
if (modinfo != null) {
|
||||
builder.modType = modinfo.getType();
|
||||
builder.mods.addAll(modinfo.getMods());
|
||||
}
|
||||
return builder;
|
||||
public int getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link ServerPing} objects.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private Version version = new Version(0, "Unknown");
|
||||
private int onlinePlayers;
|
||||
private int maximumPlayers;
|
||||
private final List<SamplePlayer> samplePlayers = new ArrayList<>();
|
||||
private String modType = "FML";
|
||||
private final List<ModInfo.Mod> mods = new ArrayList<>();
|
||||
private @Nullable Component description;
|
||||
private @Nullable Favicon favicon;
|
||||
private boolean nullOutPlayers;
|
||||
private boolean nullOutModinfo;
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Version{" +
|
||||
"protocol=" + protocol +
|
||||
", name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
private Builder() {
|
||||
public static final class Players {
|
||||
|
||||
}
|
||||
private final int online;
|
||||
private final int max;
|
||||
private final List<SamplePlayer> sample;
|
||||
|
||||
public Builder version(Version version) {
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onlinePlayers(int onlinePlayers) {
|
||||
this.onlinePlayers = onlinePlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder maximumPlayers(int maximumPlayers) {
|
||||
this.maximumPlayers = maximumPlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder samplePlayers(SamplePlayer... players) {
|
||||
this.samplePlayers.addAll(Arrays.asList(players));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder modType(String modType) {
|
||||
this.modType = Preconditions.checkNotNull(modType, "modType");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder mods(ModInfo.Mod... mods) {
|
||||
this.mods.addAll(Arrays.asList(mods));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearMods() {
|
||||
this.mods.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearSamplePlayers() {
|
||||
this.samplePlayers.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder notModCompatible() {
|
||||
this.nullOutModinfo = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder nullPlayers() {
|
||||
this.nullOutPlayers = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder description(Component description) {
|
||||
this.description = Preconditions.checkNotNull(description, "description");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder favicon(Favicon favicon) {
|
||||
this.favicon = Preconditions.checkNotNull(favicon, "favicon");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerPing build() {
|
||||
if (this.version == null) {
|
||||
throw new IllegalStateException("version not specified");
|
||||
}
|
||||
if (this.description == null) {
|
||||
throw new IllegalStateException("no server description supplied");
|
||||
}
|
||||
return new ServerPing(version, nullOutPlayers ? null : new Players(onlinePlayers, maximumPlayers, samplePlayers),
|
||||
description, favicon, nullOutModinfo ? null : new ModInfo(modType, mods));
|
||||
}
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public int getOnlinePlayers() {
|
||||
return onlinePlayers;
|
||||
}
|
||||
|
||||
public int getMaximumPlayers() {
|
||||
return maximumPlayers;
|
||||
}
|
||||
|
||||
public List<SamplePlayer> getSamplePlayers() {
|
||||
return samplePlayers;
|
||||
}
|
||||
|
||||
public Optional<Component> getDescription() {
|
||||
return Optional.ofNullable(description);
|
||||
}
|
||||
|
||||
public Optional<Favicon> getFavicon() {
|
||||
return Optional.ofNullable(favicon);
|
||||
}
|
||||
|
||||
public String getModType() {
|
||||
return modType;
|
||||
}
|
||||
|
||||
public List<ModInfo.Mod> getMods() {
|
||||
return mods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Builder{" +
|
||||
"version=" + version +
|
||||
", onlinePlayers=" + onlinePlayers +
|
||||
", maximumPlayers=" + maximumPlayers +
|
||||
", samplePlayers=" + samplePlayers +
|
||||
", modType=" + modType +
|
||||
", mods=" + mods +
|
||||
", description=" + description +
|
||||
", favicon=" + favicon +
|
||||
", nullOutPlayers=" + nullOutPlayers +
|
||||
", nullOutModinfo=" + nullOutModinfo +
|
||||
'}';
|
||||
}
|
||||
public Players(int online, int max, List<SamplePlayer> sample) {
|
||||
this.online = online;
|
||||
this.max = max;
|
||||
this.sample = ImmutableList.copyOf(sample);
|
||||
}
|
||||
|
||||
public static final class Version {
|
||||
private final int protocol;
|
||||
private final String name;
|
||||
|
||||
public Version(int protocol, String name) {
|
||||
this.protocol = protocol;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Version{" +
|
||||
"protocol=" + protocol +
|
||||
", name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
public int getOnline() {
|
||||
return online;
|
||||
}
|
||||
|
||||
public static final class Players {
|
||||
private final int online;
|
||||
private final int max;
|
||||
private final List<SamplePlayer> sample;
|
||||
|
||||
public Players(int online, int max, List<SamplePlayer> sample) {
|
||||
this.online = online;
|
||||
this.max = max;
|
||||
this.sample = ImmutableList.copyOf(sample);
|
||||
}
|
||||
|
||||
public int getOnline() {
|
||||
return online;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public List<SamplePlayer> getSample() {
|
||||
return sample;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Players{" +
|
||||
"online=" + online +
|
||||
", max=" + max +
|
||||
", sample=" + sample +
|
||||
'}';
|
||||
}
|
||||
public int getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public static final class SamplePlayer {
|
||||
private final String name;
|
||||
private final UUID id;
|
||||
|
||||
public SamplePlayer(String name, UUID id) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SamplePlayer{" +
|
||||
"name='" + name + '\'' +
|
||||
", id=" + id +
|
||||
'}';
|
||||
}
|
||||
public List<SamplePlayer> getSample() {
|
||||
return sample;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Players{" +
|
||||
"online=" + online +
|
||||
", max=" + max +
|
||||
", sample=" + sample +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SamplePlayer {
|
||||
|
||||
private final String name;
|
||||
private final UUID id;
|
||||
|
||||
public SamplePlayer(String name, UUID id) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SamplePlayer{" +
|
||||
"name='" + name + '\'' +
|
||||
", id=" + id +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,21 +4,24 @@ package com.velocitypowered.api.scheduler;
|
||||
* Represents a task that is scheduled to run on the proxy.
|
||||
*/
|
||||
public interface ScheduledTask {
|
||||
/**
|
||||
* Returns the plugin that scheduled this task.
|
||||
* @return the plugin that scheduled this task
|
||||
*/
|
||||
Object plugin();
|
||||
|
||||
/**
|
||||
* Returns the current status of this task.
|
||||
* @return the current status of this task
|
||||
*/
|
||||
TaskStatus status();
|
||||
/**
|
||||
* Returns the plugin that scheduled this task.
|
||||
*
|
||||
* @return the plugin that scheduled this task
|
||||
*/
|
||||
Object plugin();
|
||||
|
||||
/**
|
||||
* Cancels this task. If the task is already running, the thread in which it is running will be interrupted.
|
||||
* If the task is not currently running, Velocity will terminate it safely.
|
||||
*/
|
||||
void cancel();
|
||||
/**
|
||||
* Returns the current status of this task.
|
||||
*
|
||||
* @return the current status of this task
|
||||
*/
|
||||
TaskStatus status();
|
||||
|
||||
/**
|
||||
* Cancels this task. If the task is already running, the thread in which it is running will be
|
||||
* interrupted. If the task is not currently running, Velocity will terminate it safely.
|
||||
*/
|
||||
void cancel();
|
||||
}
|
||||
|
@ -1,57 +1,65 @@
|
||||
package com.velocitypowered.api.scheduler;
|
||||
|
||||
import org.checkerframework.common.value.qual.IntRange;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.checkerframework.common.value.qual.IntRange;
|
||||
|
||||
/**
|
||||
* Represents a scheduler to execute tasks on the proxy.
|
||||
*/
|
||||
public interface Scheduler {
|
||||
/**
|
||||
* Initializes a new {@link TaskBuilder} for creating a task on the proxy.
|
||||
* @param plugin the plugin to request the task for
|
||||
* @param runnable the task to run when scheduled
|
||||
* @return the task builder
|
||||
*/
|
||||
TaskBuilder buildTask(Object plugin, Runnable runnable);
|
||||
|
||||
/**
|
||||
* Initializes a new {@link TaskBuilder} for creating a task on the proxy.
|
||||
*
|
||||
* @param plugin the plugin to request the task for
|
||||
* @param runnable the task to run when scheduled
|
||||
* @return the task builder
|
||||
*/
|
||||
TaskBuilder buildTask(Object plugin, Runnable runnable);
|
||||
|
||||
/**
|
||||
* Represents a fluent interface to schedule tasks on the proxy.
|
||||
*/
|
||||
interface TaskBuilder {
|
||||
|
||||
/**
|
||||
* Represents a fluent interface to schedule tasks on the proxy.
|
||||
* Specifies that the task should delay its execution by the specified amount of time.
|
||||
*
|
||||
* @param time the time to delay by
|
||||
* @param unit the unit of time for {@code time}
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
interface TaskBuilder {
|
||||
/**
|
||||
* Specifies that the task should delay its execution by the specified amount of time.
|
||||
* @param time the time to delay by
|
||||
* @param unit the unit of time for {@code time}
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
TaskBuilder delay(@IntRange(from = 0) long time, TimeUnit unit);
|
||||
TaskBuilder delay(@IntRange(from = 0) long time, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Specifies that the task should continue running after waiting for the specified amount, until it is cancelled.
|
||||
* @param time the time to delay by
|
||||
* @param unit the unit of time for {@code time}
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
TaskBuilder repeat(@IntRange(from = 0) long time, TimeUnit unit);
|
||||
/**
|
||||
* Specifies that the task should continue running after waiting for the specified amount, until
|
||||
* it is cancelled.
|
||||
*
|
||||
* @param time the time to delay by
|
||||
* @param unit the unit of time for {@code time}
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
TaskBuilder repeat(@IntRange(from = 0) long time, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Clears the delay on this task.
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
TaskBuilder clearDelay();
|
||||
/**
|
||||
* Clears the delay on this task.
|
||||
*
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
TaskBuilder clearDelay();
|
||||
|
||||
/**
|
||||
* Clears the repeat interval on this task.
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
TaskBuilder clearRepeat();
|
||||
/**
|
||||
* Clears the repeat interval on this task.
|
||||
*
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
TaskBuilder clearRepeat();
|
||||
|
||||
/**
|
||||
* Schedules this task for execution.
|
||||
* @return the scheduled task
|
||||
*/
|
||||
ScheduledTask schedule();
|
||||
}
|
||||
/**
|
||||
* Schedules this task for execution.
|
||||
*
|
||||
* @return the scheduled task
|
||||
*/
|
||||
ScheduledTask schedule();
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
package com.velocitypowered.api.scheduler;
|
||||
|
||||
public enum TaskStatus {
|
||||
/**
|
||||
* The task is scheduled and is currently running.
|
||||
*/
|
||||
SCHEDULED,
|
||||
/**
|
||||
* The task was cancelled with {@link ScheduledTask#cancel()}.
|
||||
*/
|
||||
CANCELLED,
|
||||
/**
|
||||
* The task has run to completion. This is applicable only for tasks without a repeat.
|
||||
*/
|
||||
FINISHED
|
||||
/**
|
||||
* The task is scheduled and is currently running.
|
||||
*/
|
||||
SCHEDULED,
|
||||
/**
|
||||
* The task was cancelled with {@link ScheduledTask#cancel()}.
|
||||
*/
|
||||
CANCELLED,
|
||||
/**
|
||||
* The task has run to completion. This is applicable only for tasks without a repeat.
|
||||
*/
|
||||
FINISHED
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
package com.velocitypowered.api.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -12,78 +9,92 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
import javax.imageio.ImageIO;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a Minecraft server favicon. A Minecraft server favicon is a 64x64 image that can be displayed to a remote
|
||||
* client that sends a Server List Ping packet, and is automatically displayed in the Minecraft client.
|
||||
* Represents a Minecraft server favicon. A Minecraft server favicon is a 64x64 image that can be
|
||||
* displayed to a remote client that sends a Server List Ping packet, and is automatically displayed
|
||||
* in the Minecraft client.
|
||||
*/
|
||||
public final class Favicon {
|
||||
private final String base64Url;
|
||||
|
||||
/**
|
||||
* Directly create a favicon using its Base64 URL directly. You are generally better served by the create() series
|
||||
* of functions.
|
||||
* @param base64Url the url for use with this favicon
|
||||
*/
|
||||
public Favicon(String base64Url) {
|
||||
this.base64Url = Preconditions.checkNotNull(base64Url, "base64Url");
|
||||
}
|
||||
private final String base64Url;
|
||||
|
||||
/**
|
||||
* Returns the Base64-encoded URI for this image.
|
||||
* @return a URL representing this favicon
|
||||
*/
|
||||
public String getBase64Url() {
|
||||
return base64Url;
|
||||
}
|
||||
/**
|
||||
* Directly create a favicon using its Base64 URL directly. You are generally better served by the
|
||||
* create() series of functions.
|
||||
*
|
||||
* @param base64Url the url for use with this favicon
|
||||
*/
|
||||
public Favicon(String base64Url) {
|
||||
this.base64Url = Preconditions.checkNotNull(base64Url, "base64Url");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Favicon favicon = (Favicon) o;
|
||||
return Objects.equals(base64Url, favicon.base64Url);
|
||||
}
|
||||
/**
|
||||
* Returns the Base64-encoded URI for this image.
|
||||
*
|
||||
* @return a URL representing this favicon
|
||||
*/
|
||||
public String getBase64Url() {
|
||||
return base64Url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(base64Url);
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Favicon favicon = (Favicon) o;
|
||||
return Objects.equals(base64Url, favicon.base64Url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Favicon{" +
|
||||
"base64Url='" + base64Url + '\'' +
|
||||
'}';
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(base64Url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code Favicon} from the specified {@code image}.
|
||||
* @param image the image to use for the favicon
|
||||
* @return the created {@link Favicon} instance
|
||||
*/
|
||||
public static Favicon create(BufferedImage image) {
|
||||
Preconditions.checkNotNull(image, "image");
|
||||
Preconditions.checkArgument(image.getWidth() == 64 && image.getHeight() == 64, "Image does not have" +
|
||||
" 64x64 dimensions (found %sx%s)", image.getWidth(), image.getHeight());
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
try {
|
||||
ImageIO.write(image, "PNG", os);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return new Favicon("data:image/png;base64," + Base64.getEncoder().encodeToString(os.toByteArray()));
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Favicon{" +
|
||||
"base64Url='" + base64Url + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code Favicon} by reading the image from the specified {@code path}.
|
||||
* @param path the path to the image to create a favicon for
|
||||
* @return the created {@link Favicon} instance
|
||||
* @throws IOException if the file could not be read from the path
|
||||
*/
|
||||
public static Favicon create(Path path) throws IOException {
|
||||
try (InputStream stream = Files.newInputStream(path)) {
|
||||
return create(ImageIO.read(stream));
|
||||
}
|
||||
/**
|
||||
* Creates a new {@code Favicon} from the specified {@code image}.
|
||||
*
|
||||
* @param image the image to use for the favicon
|
||||
* @return the created {@link Favicon} instance
|
||||
*/
|
||||
public static Favicon create(BufferedImage image) {
|
||||
Preconditions.checkNotNull(image, "image");
|
||||
Preconditions
|
||||
.checkArgument(image.getWidth() == 64 && image.getHeight() == 64, "Image does not have" +
|
||||
" 64x64 dimensions (found %sx%s)", image.getWidth(), image.getHeight());
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
try {
|
||||
ImageIO.write(image, "PNG", os);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return new Favicon(
|
||||
"data:image/png;base64," + Base64.getEncoder().encodeToString(os.toByteArray()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code Favicon} by reading the image from the specified {@code path}.
|
||||
*
|
||||
* @param path the path to the image to create a favicon for
|
||||
* @return the created {@link Favicon} instance
|
||||
* @throws IOException if the file could not be read from the path
|
||||
*/
|
||||
public static Favicon create(Path path) throws IOException {
|
||||
try (InputStream stream = Files.newInputStream(path)) {
|
||||
return create(ImageIO.read(stream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.velocitypowered.api.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -10,82 +9,85 @@ import java.util.UUID;
|
||||
* Represents a Mojang game profile. This class is immutable.
|
||||
*/
|
||||
public final class GameProfile {
|
||||
private final String id;
|
||||
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final List<Property> properties;
|
||||
|
||||
public GameProfile(String id, String name, List<Property> properties) {
|
||||
this.id = Preconditions.checkNotNull(id, "id");
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.properties = ImmutableList.copyOf(properties);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public UUID idAsUuid() {
|
||||
return UuidUtils.fromUndashed(id);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a game profile suitable for use in offline-mode.
|
||||
*
|
||||
* @param username the username to use
|
||||
* @return the new offline-mode game profile
|
||||
*/
|
||||
public static GameProfile forOfflinePlayer(String username) {
|
||||
Preconditions.checkNotNull(username, "username");
|
||||
String id = UuidUtils.toUndashed(UuidUtils.generateOfflinePlayerUuid(username));
|
||||
return new GameProfile(id, username, ImmutableList.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GameProfile{" +
|
||||
"id='" + id + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", properties=" + properties +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Property {
|
||||
|
||||
private final String name;
|
||||
private final List<Property> properties;
|
||||
private final String value;
|
||||
private final String signature;
|
||||
|
||||
public GameProfile(String id, String name, List<Property> properties) {
|
||||
this.id = Preconditions.checkNotNull(id, "id");
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.properties = ImmutableList.copyOf(properties);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public UUID idAsUuid() {
|
||||
return UuidUtils.fromUndashed(id);
|
||||
public Property(String name, String value, String signature) {
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.value = Preconditions.checkNotNull(value, "value");
|
||||
this.signature = Preconditions.checkNotNull(signature, "signature");
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a game profile suitable for use in offline-mode.
|
||||
* @param username the username to use
|
||||
* @return the new offline-mode game profile
|
||||
*/
|
||||
public static GameProfile forOfflinePlayer(String username) {
|
||||
Preconditions.checkNotNull(username, "username");
|
||||
String id = UuidUtils.toUndashed(UuidUtils.generateOfflinePlayerUuid(username));
|
||||
return new GameProfile(id, username, ImmutableList.of());
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GameProfile{" +
|
||||
"id='" + id + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", properties=" + properties +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Property {
|
||||
private final String name;
|
||||
private final String value;
|
||||
private final String signature;
|
||||
|
||||
public Property(String name, String value, String signature) {
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.value = Preconditions.checkNotNull(value, "value");
|
||||
this.signature = Preconditions.checkNotNull(signature, "signature");
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Property{" +
|
||||
"name='" + name + '\'' +
|
||||
", value='" + value + '\'' +
|
||||
", signature='" + signature + '\'' +
|
||||
'}';
|
||||
}
|
||||
return "Property{" +
|
||||
"name='" + name + '\'' +
|
||||
", value='" + value + '\'' +
|
||||
", signature='" + signature + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,18 @@ package com.velocitypowered.api.util;
|
||||
* Represents where a chat message is going to be sent.
|
||||
*/
|
||||
public enum MessagePosition {
|
||||
/**
|
||||
* The chat message will appear in the client's HUD. These messages can be filtered out by the client.
|
||||
*/
|
||||
CHAT,
|
||||
/**
|
||||
* The chat message will appear in the client's HUD and can't be dismissed.
|
||||
*/
|
||||
SYSTEM,
|
||||
/**
|
||||
* The chat message will appear above the player's main HUD. This text format doesn't support many component features,
|
||||
* such as hover events.
|
||||
*/
|
||||
ACTION_BAR
|
||||
/**
|
||||
* The chat message will appear in the client's HUD. These messages can be filtered out by the
|
||||
* client.
|
||||
*/
|
||||
CHAT,
|
||||
/**
|
||||
* The chat message will appear in the client's HUD and can't be dismissed.
|
||||
*/
|
||||
SYSTEM,
|
||||
/**
|
||||
* The chat message will appear above the player's main HUD. This text format doesn't support many
|
||||
* component features, such as hover events.
|
||||
*/
|
||||
ACTION_BAR
|
||||
}
|
||||
|
@ -2,59 +2,60 @@ package com.velocitypowered.api.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class ModInfo {
|
||||
public static final ModInfo DEFAULT = new ModInfo("FML", ImmutableList.of());
|
||||
|
||||
private final String type;
|
||||
private final List<Mod> modList;
|
||||
|
||||
public ModInfo(String type, List<Mod> modList) {
|
||||
this.type = Preconditions.checkNotNull(type, "type");
|
||||
this.modList = ImmutableList.copyOf(modList);
|
||||
|
||||
public static final ModInfo DEFAULT = new ModInfo("FML", ImmutableList.of());
|
||||
|
||||
private final String type;
|
||||
private final 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ModInfo{" +
|
||||
"type='" + type + '\'' +
|
||||
", modList=" + modList +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Mod {
|
||||
|
||||
private final String id;
|
||||
private final String version;
|
||||
|
||||
public Mod(String id, String version) {
|
||||
this.id = Preconditions.checkNotNull(id, "id");
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<Mod> getMods() {
|
||||
return modList;
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ModInfo{" +
|
||||
"type='" + type + '\'' +
|
||||
", modList=" + modList +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Mod {
|
||||
private final String id;
|
||||
private final String version;
|
||||
|
||||
public Mod(String id, String version) {
|
||||
this.id = Preconditions.checkNotNull(id, "id");
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Mod{" +
|
||||
"id='" + id + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
'}';
|
||||
}
|
||||
return "Mod{" +
|
||||
"id='" + id + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +1,61 @@
|
||||
package com.velocitypowered.api.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Provides a version object for the proxy.
|
||||
*/
|
||||
public final class ProxyVersion {
|
||||
private final String name;
|
||||
private final String vendor;
|
||||
private final String version;
|
||||
|
||||
public ProxyVersion(String name, String vendor, String version) {
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.vendor = Preconditions.checkNotNull(vendor, "vendor");
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
}
|
||||
private final String name;
|
||||
private final String vendor;
|
||||
private final String version;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public ProxyVersion(String name, String vendor, String version) {
|
||||
this.name = Preconditions.checkNotNull(name, "name");
|
||||
this.vendor = Preconditions.checkNotNull(vendor, "vendor");
|
||||
this.version = Preconditions.checkNotNull(version, "version");
|
||||
}
|
||||
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ProxyVersion that = (ProxyVersion) o;
|
||||
return Objects.equals(name, that.name) &&
|
||||
Objects.equals(vendor, that.vendor) &&
|
||||
Objects.equals(version, that.version);
|
||||
}
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, vendor, version);
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ProxyVersion that = (ProxyVersion) o;
|
||||
return Objects.equals(name, that.name) &&
|
||||
Objects.equals(vendor, that.vendor) &&
|
||||
Objects.equals(version, that.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyVersion{" +
|
||||
"name='" + name + '\'' +
|
||||
", vendor='" + vendor + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
'}';
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, vendor, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProxyVersion{" +
|
||||
"name='" + name + '\'' +
|
||||
", vendor='" + vendor + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.velocitypowered.api.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
@ -11,41 +10,45 @@ import java.util.UUID;
|
||||
* Provides a small, useful selection of utilities for working with Minecraft UUIDs.
|
||||
*/
|
||||
public final class UuidUtils {
|
||||
private UuidUtils() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from an undashed Mojang-style UUID into a Java {@link UUID} object.
|
||||
* @param string the string to convert
|
||||
* @return the UUID object
|
||||
*/
|
||||
public static UUID fromUndashed(final String string) {
|
||||
Objects.requireNonNull(string, "string");
|
||||
Preconditions.checkArgument(string.length() == 32, "Length is incorrect");
|
||||
return new UUID(
|
||||
Long.parseUnsignedLong(string.substring(0, 16), 16),
|
||||
Long.parseUnsignedLong(string.substring(16), 16)
|
||||
);
|
||||
}
|
||||
private UuidUtils() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from a Java {@link UUID} object into an undashed Mojang-style UUID.
|
||||
* @param uuid the UUID to convert
|
||||
* @return the undashed UUID
|
||||
*/
|
||||
public static String toUndashed(final UUID uuid) {
|
||||
Preconditions.checkNotNull(uuid, "uuid");
|
||||
return Strings.padStart(Long.toHexString(uuid.getMostSignificantBits()), 16, '0') +
|
||||
Strings.padStart(Long.toHexString(uuid.getLeastSignificantBits()), 16, '0');
|
||||
}
|
||||
/**
|
||||
* Converts from an undashed Mojang-style UUID into a Java {@link UUID} object.
|
||||
*
|
||||
* @param string the string to convert
|
||||
* @return the UUID object
|
||||
*/
|
||||
public static UUID fromUndashed(final String string) {
|
||||
Objects.requireNonNull(string, "string");
|
||||
Preconditions.checkArgument(string.length() == 32, "Length is incorrect");
|
||||
return new UUID(
|
||||
Long.parseUnsignedLong(string.substring(0, 16), 16),
|
||||
Long.parseUnsignedLong(string.substring(16), 16)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a UUID for use for offline mode.
|
||||
* @param username the username to use
|
||||
* @return the offline mode UUID
|
||||
*/
|
||||
public static UUID generateOfflinePlayerUuid(String username) {
|
||||
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
/**
|
||||
* Converts from a Java {@link UUID} object into an undashed Mojang-style UUID.
|
||||
*
|
||||
* @param uuid the UUID to convert
|
||||
* @return the undashed UUID
|
||||
*/
|
||||
public static String toUndashed(final UUID uuid) {
|
||||
Preconditions.checkNotNull(uuid, "uuid");
|
||||
return Strings.padStart(Long.toHexString(uuid.getMostSignificantBits()), 16, '0') +
|
||||
Strings.padStart(Long.toHexString(uuid.getLeastSignificantBits()), 16, '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a UUID for use for offline mode.
|
||||
*
|
||||
* @param username the username to use
|
||||
* @return the offline mode UUID
|
||||
*/
|
||||
public static UUID generateOfflinePlayerUuid(String username) {
|
||||
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
@ -1,236 +1,251 @@
|
||||
package com.velocitypowered.api.util.title;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.kyori.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import net.kyori.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a "full" title, including all components. This class is immutable.
|
||||
*/
|
||||
public final class TextTitle implements Title {
|
||||
private final @Nullable Component title;
|
||||
private final @Nullable Component subtitle;
|
||||
private final int stay;
|
||||
private final int fadeIn;
|
||||
private final int fadeOut;
|
||||
private final boolean resetBeforeSend;
|
||||
|
||||
private TextTitle(Builder builder) {
|
||||
this.title = builder.title;
|
||||
this.subtitle = builder.subtitle;
|
||||
this.stay = builder.stay;
|
||||
this.fadeIn = builder.fadeIn;
|
||||
this.fadeOut = builder.fadeOut;
|
||||
this.resetBeforeSend = builder.resetBeforeSend;
|
||||
private final @Nullable Component title;
|
||||
private final @Nullable Component subtitle;
|
||||
private final int stay;
|
||||
private final int fadeIn;
|
||||
private final int fadeOut;
|
||||
private final boolean resetBeforeSend;
|
||||
|
||||
private TextTitle(Builder builder) {
|
||||
this.title = builder.title;
|
||||
this.subtitle = builder.subtitle;
|
||||
this.stay = builder.stay;
|
||||
this.fadeIn = builder.fadeIn;
|
||||
this.fadeOut = builder.fadeOut;
|
||||
this.resetBeforeSend = builder.resetBeforeSend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the main title this title has, if any.
|
||||
*
|
||||
* @return the main title of this title
|
||||
*/
|
||||
public Optional<Component> getTitle() {
|
||||
return Optional.ofNullable(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subtitle this title has, if any.
|
||||
*
|
||||
* @return the subtitle
|
||||
*/
|
||||
public Optional<Component> getSubtitle() {
|
||||
return Optional.ofNullable(subtitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of ticks this title will stay up.
|
||||
*
|
||||
* @return how long the title will stay, in ticks
|
||||
*/
|
||||
public int getStay() {
|
||||
return stay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of ticks over which this title will fade in.
|
||||
*
|
||||
* @return how long the title will fade in, in ticks
|
||||
*/
|
||||
public int getFadeIn() {
|
||||
return fadeIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of ticks over which this title will fade out.
|
||||
*
|
||||
* @return how long the title will fade out, in ticks
|
||||
*/
|
||||
public int getFadeOut() {
|
||||
return fadeOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not a reset packet will be sent before this title is sent. By default,
|
||||
* unless explicitly disabled, this is enabled by default.
|
||||
*
|
||||
* @return whether or not a reset packet will be sent before this title is sent
|
||||
*/
|
||||
public boolean isResetBeforeSend() {
|
||||
return resetBeforeSend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this title has times set on it. If none are set, it will update the
|
||||
* previous title set on the client.
|
||||
*
|
||||
* @return whether or not this title has times set on it
|
||||
*/
|
||||
public boolean areTimesSet() {
|
||||
return stay != 0 || fadeIn != 0 || fadeOut != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder from the contents of this title so that it may be changed.
|
||||
*
|
||||
* @return a builder instance with the contents of this title
|
||||
*/
|
||||
public Builder toBuilder() {
|
||||
return new Builder(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TextTitle textTitle = (TextTitle) o;
|
||||
return stay == textTitle.stay &&
|
||||
fadeIn == textTitle.fadeIn &&
|
||||
fadeOut == textTitle.fadeOut &&
|
||||
resetBeforeSend == textTitle.resetBeforeSend &&
|
||||
Objects.equals(title, textTitle.title) &&
|
||||
Objects.equals(subtitle, textTitle.subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TextTitle{" +
|
||||
"title=" + title +
|
||||
", subtitle=" + subtitle +
|
||||
", stay=" + stay +
|
||||
", fadeIn=" + fadeIn +
|
||||
", fadeOut=" + fadeOut +
|
||||
", resetBeforeSend=" + resetBeforeSend +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(title, subtitle, stay, fadeIn, fadeOut, resetBeforeSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder for constructing titles.
|
||||
*
|
||||
* @return a builder for constructing titles
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private @Nullable Component title;
|
||||
private @Nullable Component subtitle;
|
||||
private int stay;
|
||||
private int fadeIn;
|
||||
private int fadeOut;
|
||||
private boolean resetBeforeSend = true;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
private Builder(TextTitle copy) {
|
||||
this.title = copy.title;
|
||||
this.subtitle = copy.subtitle;
|
||||
this.stay = copy.stay;
|
||||
this.fadeIn = copy.fadeIn;
|
||||
this.fadeOut = copy.fadeOut;
|
||||
this.resetBeforeSend = copy.resetBeforeSend;
|
||||
}
|
||||
|
||||
public Builder title(Component title) {
|
||||
this.title = Preconditions.checkNotNull(title, "title");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearTitle() {
|
||||
this.title = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder subtitle(Component subtitle) {
|
||||
this.subtitle = Preconditions.checkNotNull(subtitle, "subtitle");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearSubtitle() {
|
||||
this.subtitle = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder stay(int ticks) {
|
||||
Preconditions.checkArgument(ticks >= 0, "ticks value %s is negative", ticks);
|
||||
this.stay = ticks;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fadeIn(int ticks) {
|
||||
Preconditions.checkArgument(ticks >= 0, "ticks value %s is negative", ticks);
|
||||
this.fadeIn = ticks;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fadeOut(int ticks) {
|
||||
Preconditions.checkArgument(ticks >= 0, "ticks value %s is negative", ticks);
|
||||
this.fadeOut = ticks;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder resetBeforeSend(boolean b) {
|
||||
this.resetBeforeSend = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the main title this title has, if any.
|
||||
* @return the main title of this title
|
||||
*/
|
||||
public Optional<Component> getTitle() {
|
||||
return Optional.ofNullable(title);
|
||||
return Optional.ofNullable(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subtitle this title has, if any.
|
||||
* @return the subtitle
|
||||
*/
|
||||
public Optional<Component> getSubtitle() {
|
||||
return Optional.ofNullable(subtitle);
|
||||
return Optional.ofNullable(subtitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of ticks this title will stay up.
|
||||
* @return how long the title will stay, in ticks
|
||||
*/
|
||||
public int getStay() {
|
||||
return stay;
|
||||
return stay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of ticks over which this title will fade in.
|
||||
* @return how long the title will fade in, in ticks
|
||||
*/
|
||||
public int getFadeIn() {
|
||||
return fadeIn;
|
||||
return fadeIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of ticks over which this title will fade out.
|
||||
* @return how long the title will fade out, in ticks
|
||||
*/
|
||||
public int getFadeOut() {
|
||||
return fadeOut;
|
||||
return fadeOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not a reset packet will be sent before this title is sent. By default, unless explicitly
|
||||
* disabled, this is enabled by default.
|
||||
* @return whether or not a reset packet will be sent before this title is sent
|
||||
*/
|
||||
public boolean isResetBeforeSend() {
|
||||
return resetBeforeSend;
|
||||
return resetBeforeSend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this title has times set on it. If none are set, it will update the previous title
|
||||
* set on the client.
|
||||
* @return whether or not this title has times set on it
|
||||
*/
|
||||
public boolean areTimesSet() {
|
||||
return stay != 0 || fadeIn != 0 || fadeOut != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder from the contents of this title so that it may be changed.
|
||||
* @return a builder instance with the contents of this title
|
||||
*/
|
||||
public Builder toBuilder() {
|
||||
return new Builder(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
TextTitle textTitle = (TextTitle) o;
|
||||
return stay == textTitle.stay &&
|
||||
fadeIn == textTitle.fadeIn &&
|
||||
fadeOut == textTitle.fadeOut &&
|
||||
resetBeforeSend == textTitle.resetBeforeSend &&
|
||||
Objects.equals(title, textTitle.title) &&
|
||||
Objects.equals(subtitle, textTitle.subtitle);
|
||||
public TextTitle build() {
|
||||
return new TextTitle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TextTitle{" +
|
||||
"title=" + title +
|
||||
", subtitle=" + subtitle +
|
||||
", stay=" + stay +
|
||||
", fadeIn=" + fadeIn +
|
||||
", fadeOut=" + fadeOut +
|
||||
", resetBeforeSend=" + resetBeforeSend +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(title, subtitle, stay, fadeIn, fadeOut, resetBeforeSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder for constructing titles.
|
||||
* @return a builder for constructing titles
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private @Nullable Component title;
|
||||
private @Nullable Component subtitle;
|
||||
private int stay;
|
||||
private int fadeIn;
|
||||
private int fadeOut;
|
||||
private boolean resetBeforeSend = true;
|
||||
|
||||
private Builder() {}
|
||||
|
||||
private Builder(TextTitle copy) {
|
||||
this.title = copy.title;
|
||||
this.subtitle = copy.subtitle;
|
||||
this.stay = copy.stay;
|
||||
this.fadeIn = copy.fadeIn;
|
||||
this.fadeOut = copy.fadeOut;
|
||||
this.resetBeforeSend = copy.resetBeforeSend;
|
||||
}
|
||||
|
||||
public Builder title(Component title) {
|
||||
this.title = Preconditions.checkNotNull(title, "title");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearTitle() {
|
||||
this.title = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder subtitle(Component subtitle) {
|
||||
this.subtitle = Preconditions.checkNotNull(subtitle, "subtitle");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clearSubtitle() {
|
||||
this.subtitle = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder stay(int ticks) {
|
||||
Preconditions.checkArgument(ticks >= 0, "ticks value %s is negative", ticks);
|
||||
this.stay = ticks;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fadeIn(int ticks) {
|
||||
Preconditions.checkArgument(ticks >= 0, "ticks value %s is negative", ticks);
|
||||
this.fadeIn = ticks;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fadeOut(int ticks) {
|
||||
Preconditions.checkArgument(ticks >= 0, "ticks value %s is negative", ticks);
|
||||
this.fadeOut = ticks;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder resetBeforeSend(boolean b) {
|
||||
this.resetBeforeSend = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Optional<Component> getTitle() {
|
||||
return Optional.ofNullable(title);
|
||||
}
|
||||
|
||||
public Optional<Component> getSubtitle() {
|
||||
return Optional.ofNullable(subtitle);
|
||||
}
|
||||
|
||||
public int getStay() {
|
||||
return stay;
|
||||
}
|
||||
|
||||
public int getFadeIn() {
|
||||
return fadeIn;
|
||||
}
|
||||
|
||||
public int getFadeOut() {
|
||||
return fadeOut;
|
||||
}
|
||||
|
||||
public boolean isResetBeforeSend() {
|
||||
return resetBeforeSend;
|
||||
}
|
||||
|
||||
public TextTitle build() {
|
||||
return new TextTitle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Builder{" +
|
||||
"title=" + title +
|
||||
", subtitle=" + subtitle +
|
||||
", stay=" + stay +
|
||||
", fadeIn=" + fadeIn +
|
||||
", fadeOut=" + fadeOut +
|
||||
", resetBeforeSend=" + resetBeforeSend +
|
||||
'}';
|
||||
}
|
||||
return "Builder{" +
|
||||
"title=" + title +
|
||||
", subtitle=" + subtitle +
|
||||
", stay=" + stay +
|
||||
", fadeIn=" + fadeIn +
|
||||
", fadeOut=" + fadeOut +
|
||||
", resetBeforeSend=" + resetBeforeSend +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,4 +4,5 @@ package com.velocitypowered.api.util.title;
|
||||
* Represents a title that can be sent to a Minecraft client.
|
||||
*/
|
||||
public interface Title {
|
||||
|
||||
}
|
||||
|
@ -4,47 +4,51 @@ package com.velocitypowered.api.util.title;
|
||||
* Provides special-purpose titles.
|
||||
*/
|
||||
public final class Titles {
|
||||
private Titles() {
|
||||
throw new AssertionError();
|
||||
|
||||
private Titles() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
private static final Title RESET = new Title() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "reset title";
|
||||
}
|
||||
};
|
||||
|
||||
private static final Title RESET = new Title() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "reset title";
|
||||
}
|
||||
};
|
||||
|
||||
private static final Title HIDE = new Title() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "hide title";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a title that, when sent to the client, will cause all title data to be reset and any existing title to be
|
||||
* hidden.
|
||||
* @return the reset title
|
||||
*/
|
||||
public static Title reset() {
|
||||
return RESET;
|
||||
private static final Title HIDE = new Title() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "hide title";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a title that, when sent to the client, will cause any existing title to be hidden. The title may be
|
||||
* restored by a {@link TextTitle} with no title or subtitle (only a time).
|
||||
* @return the hide title
|
||||
*/
|
||||
public static Title hide() {
|
||||
return HIDE;
|
||||
}
|
||||
/**
|
||||
* Returns a title that, when sent to the client, will cause all title data to be reset and any
|
||||
* existing title to be hidden.
|
||||
*
|
||||
* @return the reset title
|
||||
*/
|
||||
public static Title reset() {
|
||||
return RESET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a builder for {@link TextTitle}s.
|
||||
* @return a builder for text titles
|
||||
*/
|
||||
public static TextTitle.Builder text() {
|
||||
return TextTitle.builder();
|
||||
}
|
||||
/**
|
||||
* Returns a title that, when sent to the client, will cause any existing title to be hidden. The
|
||||
* title may be restored by a {@link TextTitle} with no title or subtitle (only a time).
|
||||
*
|
||||
* @return the hide title
|
||||
*/
|
||||
public static Title hide() {
|
||||
return HIDE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a builder for {@link TextTitle}s.
|
||||
*
|
||||
* @return a builder for text titles
|
||||
*/
|
||||
public static TextTitle.Builder text() {
|
||||
return TextTitle.builder();
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +1,81 @@
|
||||
package com.velocitypowered.api.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class UuidUtilsTest {
|
||||
private static final UUID EXPECTED_DASHED_UUID = UUID.fromString("6b501978-d3be-4f33-bcf6-6e7808f37a0d");
|
||||
private static final String ACTUAL_UNDASHED_UUID = EXPECTED_DASHED_UUID.toString().replace("-", "");
|
||||
|
||||
private static final UUID ISSUE_109_ZERO_UUID = new UUID(0, 0);
|
||||
private static final String ISSUE_109_ZERO_UUID_UNDASHED = "00000000000000000000000000000000";
|
||||
private static final UUID EXPECTED_DASHED_UUID = UUID
|
||||
.fromString("6b501978-d3be-4f33-bcf6-6e7808f37a0d");
|
||||
private static final String ACTUAL_UNDASHED_UUID = EXPECTED_DASHED_UUID.toString()
|
||||
.replace("-", "");
|
||||
|
||||
private static final UUID ISSUE_109_ONE_LSB_UUID = new UUID(0, 1);
|
||||
private static final String ISSUE_109_ONE_LSB_UUID_UNDASHED = "00000000000000000000000000000001";
|
||||
private static final UUID ISSUE_109_ZERO_UUID = new UUID(0, 0);
|
||||
private static final String ISSUE_109_ZERO_UUID_UNDASHED = "00000000000000000000000000000000";
|
||||
|
||||
private static final UUID ISSUE_109_ONE_MLSB_UUID = new UUID(1, 1);
|
||||
private static final String ISSUE_109_ONE_MLSB_UUID_UNDASHED = "00000000000000010000000000000001";
|
||||
private static final UUID ISSUE_109_ONE_LSB_UUID = new UUID(0, 1);
|
||||
private static final String ISSUE_109_ONE_LSB_UUID_UNDASHED = "00000000000000000000000000000001";
|
||||
|
||||
private static final UUID ISSUE_109_LEADING_ZERO_UUID = UUID.fromString("0d470a25-0416-48a1-b7a6-2a27aa5eb251");
|
||||
private static final String ISSUE_109_LEADING_ZERO_UNDASHED = "0d470a25041648a1b7a62a27aa5eb251";
|
||||
private static final UUID ISSUE_109_ONE_MLSB_UUID = new UUID(1, 1);
|
||||
private static final String ISSUE_109_ONE_MLSB_UUID_UNDASHED = "00000000000000010000000000000001";
|
||||
|
||||
private static final UUID TEST_OFFLINE_PLAYER_UUID = UUID.fromString("708f6260-183d-3912-bbde-5e279a5e739a");
|
||||
private static final String TEST_OFFLINE_PLAYER = "tuxed";
|
||||
private static final UUID ISSUE_109_LEADING_ZERO_UUID = UUID
|
||||
.fromString("0d470a25-0416-48a1-b7a6-2a27aa5eb251");
|
||||
private static final String ISSUE_109_LEADING_ZERO_UNDASHED = "0d470a25041648a1b7a62a27aa5eb251";
|
||||
|
||||
@Test
|
||||
void generateOfflinePlayerUuid() {
|
||||
assertEquals(TEST_OFFLINE_PLAYER_UUID, UuidUtils.generateOfflinePlayerUuid(TEST_OFFLINE_PLAYER), "UUIDs do not match");
|
||||
}
|
||||
private static final UUID TEST_OFFLINE_PLAYER_UUID = UUID
|
||||
.fromString("708f6260-183d-3912-bbde-5e279a5e739a");
|
||||
private static final String TEST_OFFLINE_PLAYER = "tuxed";
|
||||
|
||||
@Test
|
||||
void fromUndashed() {
|
||||
assertEquals(EXPECTED_DASHED_UUID, UuidUtils.fromUndashed(ACTUAL_UNDASHED_UUID), "UUIDs do not match");
|
||||
}
|
||||
@Test
|
||||
void generateOfflinePlayerUuid() {
|
||||
assertEquals(TEST_OFFLINE_PLAYER_UUID, UuidUtils.generateOfflinePlayerUuid(TEST_OFFLINE_PLAYER),
|
||||
"UUIDs do not match");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toUndashed() {
|
||||
assertEquals(ACTUAL_UNDASHED_UUID, UuidUtils.toUndashed(EXPECTED_DASHED_UUID), "UUIDs do not match");
|
||||
}
|
||||
@Test
|
||||
void fromUndashed() {
|
||||
assertEquals(EXPECTED_DASHED_UUID, UuidUtils.fromUndashed(ACTUAL_UNDASHED_UUID),
|
||||
"UUIDs do not match");
|
||||
}
|
||||
|
||||
@Test
|
||||
void zeroUuidIssue109() {
|
||||
assertEquals(ISSUE_109_ZERO_UUID, UuidUtils.fromUndashed(ISSUE_109_ZERO_UUID_UNDASHED), "UUIDs do not match");
|
||||
assertEquals(ISSUE_109_ZERO_UUID_UNDASHED, UuidUtils.toUndashed(ISSUE_109_ZERO_UUID), "UUIDs do not match");
|
||||
}
|
||||
@Test
|
||||
void toUndashed() {
|
||||
assertEquals(ACTUAL_UNDASHED_UUID, UuidUtils.toUndashed(EXPECTED_DASHED_UUID),
|
||||
"UUIDs do not match");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leadingZeroUuidIssue109() {
|
||||
assertEquals(ISSUE_109_LEADING_ZERO_UUID, UuidUtils.fromUndashed(ISSUE_109_LEADING_ZERO_UNDASHED), "UUIDs do not match");
|
||||
assertEquals(ISSUE_109_LEADING_ZERO_UNDASHED, UuidUtils.toUndashed(ISSUE_109_LEADING_ZERO_UUID), "UUIDs do not match");
|
||||
}
|
||||
@Test
|
||||
void zeroUuidIssue109() {
|
||||
assertEquals(ISSUE_109_ZERO_UUID, UuidUtils.fromUndashed(ISSUE_109_ZERO_UUID_UNDASHED),
|
||||
"UUIDs do not match");
|
||||
assertEquals(ISSUE_109_ZERO_UUID_UNDASHED, UuidUtils.toUndashed(ISSUE_109_ZERO_UUID),
|
||||
"UUIDs do not match");
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneUuidLsbIssue109() {
|
||||
assertEquals(ISSUE_109_ONE_LSB_UUID, UuidUtils.fromUndashed(ISSUE_109_ONE_LSB_UUID_UNDASHED), "UUIDs do not match");
|
||||
assertEquals(ISSUE_109_ONE_LSB_UUID_UNDASHED, UuidUtils.toUndashed(ISSUE_109_ONE_LSB_UUID), "UUIDs do not match");
|
||||
}
|
||||
@Test
|
||||
void leadingZeroUuidIssue109() {
|
||||
assertEquals(ISSUE_109_LEADING_ZERO_UUID,
|
||||
UuidUtils.fromUndashed(ISSUE_109_LEADING_ZERO_UNDASHED), "UUIDs do not match");
|
||||
assertEquals(ISSUE_109_LEADING_ZERO_UNDASHED, UuidUtils.toUndashed(ISSUE_109_LEADING_ZERO_UUID),
|
||||
"UUIDs do not match");
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneUuidMsbAndLsbIssue109() {
|
||||
assertEquals(ISSUE_109_ONE_MLSB_UUID, UuidUtils.fromUndashed(ISSUE_109_ONE_MLSB_UUID_UNDASHED), "UUIDs do not match");
|
||||
assertEquals(ISSUE_109_ONE_MLSB_UUID_UNDASHED, UuidUtils.toUndashed(ISSUE_109_ONE_MLSB_UUID), "UUIDs do not match");
|
||||
}
|
||||
@Test
|
||||
void oneUuidLsbIssue109() {
|
||||
assertEquals(ISSUE_109_ONE_LSB_UUID, UuidUtils.fromUndashed(ISSUE_109_ONE_LSB_UUID_UNDASHED),
|
||||
"UUIDs do not match");
|
||||
assertEquals(ISSUE_109_ONE_LSB_UUID_UNDASHED, UuidUtils.toUndashed(ISSUE_109_ONE_LSB_UUID),
|
||||
"UUIDs do not match");
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneUuidMsbAndLsbIssue109() {
|
||||
assertEquals(ISSUE_109_ONE_MLSB_UUID, UuidUtils.fromUndashed(ISSUE_109_ONE_MLSB_UUID_UNDASHED),
|
||||
"UUIDs do not match");
|
||||
assertEquals(ISSUE_109_ONE_MLSB_UUID_UNDASHED, UuidUtils.toUndashed(ISSUE_109_ONE_MLSB_UUID),
|
||||
"UUIDs do not match");
|
||||
}
|
||||
}
|
||||
|
256
config/checkstyle/checkstyle.xml
Normale Datei
256
config/checkstyle/checkstyle.xml
Normale Datei
@ -0,0 +1,256 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!--
|
||||
Checkstyle configuration that checks the Google coding conventions from Google Java Style
|
||||
that can be found at https://google.github.io/styleguide/javaguide.html.
|
||||
|
||||
Checkstyle is very configurable. Be sure to read the documentation at
|
||||
http://checkstyle.sf.net (or in your downloaded distribution).
|
||||
|
||||
To completely disable a check, just comment it out or delete it from the file.
|
||||
|
||||
Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
|
||||
-->
|
||||
|
||||
<module name="Checker">
|
||||
<property name="charset" value="UTF-8"/>
|
||||
|
||||
<property name="severity" value="warning"/>
|
||||
|
||||
<property name="fileExtensions" value="java, properties, xml"/>
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<module name="OuterTypeFilename"/>
|
||||
<module name="IllegalTokenText">
|
||||
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
|
||||
<property name="format"
|
||||
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
|
||||
<property name="message"
|
||||
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
|
||||
</module>
|
||||
<module name="AvoidEscapedUnicodeCharacters">
|
||||
<property name="allowEscapesForControlCharacters" value="true"/>
|
||||
<property name="allowByTailComment" value="true"/>
|
||||
<property name="allowNonPrintableEscapes" value="true"/>
|
||||
</module>
|
||||
<module name="LineLength">
|
||||
<property name="max" value="100"/>
|
||||
<property name="ignorePattern"
|
||||
value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
|
||||
</module>
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="OneTopLevelClass"/>
|
||||
<module name="NoLineWrap"/>
|
||||
<module name="EmptyBlock">
|
||||
<property name="option" value="TEXT"/>
|
||||
<property name="tokens"
|
||||
value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
|
||||
</module>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="LeftCurly"/>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlySame"/>
|
||||
<property name="tokens"
|
||||
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
|
||||
LITERAL_DO"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlyAlone"/>
|
||||
<property name="option" value="alone"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
|
||||
INSTANCE_INIT"/>
|
||||
</module>
|
||||
<module name="WhitespaceAround">
|
||||
<property name="allowEmptyConstructors" value="true"/>
|
||||
<property name="allowEmptyMethods" value="true"/>
|
||||
<property name="allowEmptyTypes" value="true"/>
|
||||
<property name="allowEmptyLoops" value="true"/>
|
||||
<message key="ws.notFollowed"
|
||||
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
|
||||
<message key="ws.notPreceded"
|
||||
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
<module name="OneStatementPerLine"/>
|
||||
<module name="MultipleVariableDeclarations"/>
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<module name="FallThrough"/>
|
||||
<module name="UpperEll"/>
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="EmptyLineSeparator">
|
||||
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapDot"/>
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="option" value="nl"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapComma"/>
|
||||
<property name="tokens" value="COMMA"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/258 -->
|
||||
<property name="id" value="SeparatorWrapEllipsis"/>
|
||||
<property name="tokens" value="ELLIPSIS"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/259 -->
|
||||
<property name="id" value="SeparatorWrapArrayDeclarator"/>
|
||||
<property name="tokens" value="ARRAY_DECLARATOR"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="id" value="SeparatorWrapMethodRef"/>
|
||||
<property name="tokens" value="METHOD_REF"/>
|
||||
<property name="option" value="nl"/>
|
||||
</module>
|
||||
<module name="PackageName">
|
||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Package name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="TypeName">
|
||||
<message key="name.invalidPattern"
|
||||
value="Type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Member name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="LambdaParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="CatchParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="LocalVariableName">
|
||||
<property name="tokens" value="VARIABLE_DEF"/>
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ClassTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Class type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MethodTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Method type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="InterfaceTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="NoFinalizer"/>
|
||||
<module name="GenericWhitespace">
|
||||
<message key="ws.followed"
|
||||
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
|
||||
<message key="ws.preceded"
|
||||
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
|
||||
<message key="ws.illegalFollow"
|
||||
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
|
||||
<message key="ws.notPreceded"
|
||||
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
<module name="Indentation">
|
||||
<property name="basicOffset" value="2"/>
|
||||
<property name="braceAdjustment" value="0"/>
|
||||
<property name="caseIndent" value="2"/>
|
||||
<property name="throwsIndent" value="4"/>
|
||||
<property name="lineWrappingIndentation" value="4"/>
|
||||
<property name="arrayInitIndent" value="2"/>
|
||||
</module>
|
||||
<module name="AbbreviationAsWordInName">
|
||||
<property name="ignoreFinal" value="false"/>
|
||||
<property name="allowedAbbreviationLength" value="1"/>
|
||||
</module>
|
||||
<module name="OverloadMethodsDeclarationOrder"/>
|
||||
<module name="VariableDeclarationUsageDistance"/>
|
||||
<module name="CustomImportOrder">
|
||||
<property name="sortImportsInGroupAlphabetically" value="true"/>
|
||||
<property name="separateLineBetweenGroups" value="true"/>
|
||||
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
|
||||
</module>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="NoWhitespaceBefore">
|
||||
<property name="tokens"
|
||||
value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
</module>
|
||||
<module name="ParenPad"/>
|
||||
<module name="OperatorWrap">
|
||||
<property name="option" value="NL"/>
|
||||
<property name="tokens"
|
||||
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
|
||||
LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
|
||||
</module>
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationMostCases"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationVariables"/>
|
||||
<property name="tokens" value="VARIABLE_DEF"/>
|
||||
<property name="allowSamelineMultipleAnnotations" value="true"/>
|
||||
</module>
|
||||
<module name="NonEmptyAtclauseDescription"/>
|
||||
<module name="JavadocTagContinuationIndentation"/>
|
||||
<module name="SummaryJavadoc">
|
||||
<property name="forbiddenSummaryFragments"
|
||||
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
|
||||
</module>
|
||||
<module name="JavadocParagraph"/>
|
||||
<module name="AtclauseOrder">
|
||||
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
|
||||
<property name="target"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
|
||||
</module>
|
||||
<module name="JavadocMethod">
|
||||
<property name="scope" value="public"/>
|
||||
<property name="allowMissingParamTags" value="true"/>
|
||||
<property name="allowMissingThrowsTags" value="true"/>
|
||||
<property name="allowMissingReturnTag" value="true"/>
|
||||
<property name="minLineCount" value="2"/>
|
||||
<property name="allowedAnnotations" value="Override, Test"/>
|
||||
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
||||
</module>
|
||||
<module name="MethodName">
|
||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Method name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="SingleLineJavadoc">
|
||||
<property name="ignoreInlineTags" value="false"/>
|
||||
</module>
|
||||
<module name="EmptyCatchBlock">
|
||||
<property name="exceptionVariableName" value="expected"/>
|
||||
</module>
|
||||
<module name="CommentsIndentation"/>
|
||||
</module>
|
||||
</module>
|
@ -25,7 +25,7 @@ dependencies {
|
||||
implementation "org.checkerframework:checker-qual:${checkerFrameworkVersion}"
|
||||
} else if (System.getenv("CHECKERFRAMEWORK") == null) {
|
||||
throw new GradleException("Environment variable CHECKERFRAMEWORK is not set")
|
||||
} else if (! file(System.getenv("CHECKERFRAMEWORK")).exists()) {
|
||||
} else if (!file(System.getenv("CHECKERFRAMEWORK")).exists()) {
|
||||
throw new GradleException("Environment variable CHECKERFRAMEWORK is set to non-existent directory " + System.getenv("CHECKERFRAMEWORK"));
|
||||
} else {
|
||||
ext.checkerframeworkdist = "$System.env.CHECKERFRAMEWORK/checker/dist"
|
||||
|
4
gradle/checkstyle.gradle
Normale Datei
4
gradle/checkstyle.gradle
Normale Datei
@ -0,0 +1,4 @@
|
||||
checkstyle {
|
||||
toolVersion '8.14'
|
||||
configFile new File(project.rootDir, ['config', 'checkstyle', 'checkstyle.xml'].join(File.separator))
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'checkstyle'
|
||||
}
|
||||
|
||||
apply from: '../gradle/checkerframework.gradle'
|
||||
apply from: '../gradle/checkstyle.gradle'
|
||||
|
||||
dependencies {
|
||||
compile "com.google.guava:guava:${guavaVersion}"
|
||||
|
@ -1,13 +1,16 @@
|
||||
package com.velocitypowered.natives;
|
||||
|
||||
/**
|
||||
* This marker interface indicates that this object should be explicitly disposed before the object can no longer be used.
|
||||
* Not disposing these objects will likely leak native resources and eventually lead to resource exhaustion.
|
||||
* This marker interface indicates that this object should be explicitly disposed before the object
|
||||
* can no longer be used. Not disposing these objects will likely leak native resources and
|
||||
* eventually lead to resource exhaustion.
|
||||
*/
|
||||
public interface Disposable {
|
||||
/**
|
||||
* Disposes this object. After this call returns, any use of this object becomes invalid. Multiple calls to
|
||||
* this function should be safe: there should be no side-effects once an object is disposed.
|
||||
*/
|
||||
void dispose();
|
||||
|
||||
/**
|
||||
* Disposes this object. After this call returns, any use of this object becomes invalid. Multiple
|
||||
* calls to this function should be safe: there should be no side-effects once an object is
|
||||
* disposed.
|
||||
*/
|
||||
void dispose();
|
||||
}
|
||||
|
@ -2,62 +2,62 @@ package com.velocitypowered.natives.compression;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
public class JavaVelocityCompressor implements VelocityCompressor {
|
||||
public static final VelocityCompressorFactory FACTORY = JavaVelocityCompressor::new;
|
||||
|
||||
private final Deflater deflater;
|
||||
private final Inflater inflater;
|
||||
private final byte[] buf;
|
||||
private boolean disposed = false;
|
||||
public static final VelocityCompressorFactory FACTORY = JavaVelocityCompressor::new;
|
||||
|
||||
private JavaVelocityCompressor(int level) {
|
||||
this.deflater = new Deflater(level);
|
||||
this.inflater = new Inflater();
|
||||
this.buf = new byte[ZLIB_BUFFER_SIZE];
|
||||
private final Deflater deflater;
|
||||
private final Inflater inflater;
|
||||
private final byte[] buf;
|
||||
private boolean disposed = false;
|
||||
|
||||
private JavaVelocityCompressor(int level) {
|
||||
this.deflater = new Deflater(level);
|
||||
this.inflater = new Inflater();
|
||||
this.buf = new byte[ZLIB_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
|
||||
byte[] inData = new byte[source.readableBytes()];
|
||||
source.readBytes(inData);
|
||||
inflater.setInput(inData);
|
||||
while (!inflater.finished()) {
|
||||
int read = inflater.inflate(buf);
|
||||
destination.writeBytes(buf, 0, read);
|
||||
}
|
||||
inflater.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
@Override
|
||||
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
|
||||
byte[] inData = new byte[source.readableBytes()];
|
||||
source.readBytes(inData);
|
||||
inflater.setInput(inData);
|
||||
while (!inflater.finished()) {
|
||||
int read = inflater.inflate(buf);
|
||||
destination.writeBytes(buf, 0, read);
|
||||
}
|
||||
inflater.reset();
|
||||
byte[] inData = new byte[source.readableBytes()];
|
||||
source.readBytes(inData);
|
||||
deflater.setInput(inData);
|
||||
deflater.finish();
|
||||
while (!deflater.finished()) {
|
||||
int bytes = deflater.deflate(buf);
|
||||
destination.writeBytes(buf, 0, bytes);
|
||||
}
|
||||
deflater.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposed = true;
|
||||
deflater.end();
|
||||
inflater.end();
|
||||
}
|
||||
|
||||
byte[] inData = new byte[source.readableBytes()];
|
||||
source.readBytes(inData);
|
||||
deflater.setInput(inData);
|
||||
deflater.finish();
|
||||
while (!deflater.finished()) {
|
||||
int bytes = deflater.deflate(buf);
|
||||
destination.writeBytes(buf, 0, bytes);
|
||||
}
|
||||
deflater.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposed = true;
|
||||
deflater.end();
|
||||
inflater.end();
|
||||
}
|
||||
|
||||
private void ensureNotDisposed() {
|
||||
Preconditions.checkState(!disposed, "Object already disposed");
|
||||
}
|
||||
private void ensureNotDisposed() {
|
||||
Preconditions.checkState(!disposed, "Object already disposed");
|
||||
}
|
||||
}
|
||||
|
@ -2,75 +2,78 @@ package com.velocitypowered.natives.compression;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
public class NativeVelocityCompressor implements VelocityCompressor {
|
||||
public static final VelocityCompressorFactory FACTORY = NativeVelocityCompressor::new;
|
||||
|
||||
private final NativeZlibInflate inflate = new NativeZlibInflate();
|
||||
private final long inflateCtx;
|
||||
private final NativeZlibDeflate deflate = new NativeZlibDeflate();
|
||||
private final long deflateCtx;
|
||||
private boolean disposed = false;
|
||||
public static final VelocityCompressorFactory FACTORY = NativeVelocityCompressor::new;
|
||||
|
||||
private NativeVelocityCompressor(int level) {
|
||||
this.inflateCtx = inflate.init();
|
||||
this.deflateCtx = deflate.init(level);
|
||||
private final NativeZlibInflate inflate = new NativeZlibInflate();
|
||||
private final long inflateCtx;
|
||||
private final NativeZlibDeflate deflate = new NativeZlibDeflate();
|
||||
private final long deflateCtx;
|
||||
private boolean disposed = false;
|
||||
|
||||
private NativeVelocityCompressor(int level) {
|
||||
this.inflateCtx = inflate.init();
|
||||
this.deflateCtx = deflate.init(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
source.memoryAddress();
|
||||
destination.memoryAddress();
|
||||
|
||||
while (!inflate.finished && source.isReadable()) {
|
||||
if (!destination.isWritable()) {
|
||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
||||
}
|
||||
int produced = inflate.process(inflateCtx, source.memoryAddress() + source.readerIndex(),
|
||||
source.readableBytes(),
|
||||
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes());
|
||||
source.readerIndex(source.readerIndex() + inflate.consumed);
|
||||
destination.writerIndex(destination.writerIndex() + produced);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
source.memoryAddress();
|
||||
destination.memoryAddress();
|
||||
inflate.reset(inflateCtx);
|
||||
inflate.consumed = 0;
|
||||
inflate.finished = false;
|
||||
}
|
||||
|
||||
while (!inflate.finished && source.isReadable()) {
|
||||
if (!destination.isWritable()) {
|
||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
||||
}
|
||||
int produced = inflate.process(inflateCtx, source.memoryAddress() + source.readerIndex(), source.readableBytes(),
|
||||
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes());
|
||||
source.readerIndex(source.readerIndex() + inflate.consumed);
|
||||
destination.writerIndex(destination.writerIndex() + produced);
|
||||
}
|
||||
@Override
|
||||
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
source.memoryAddress();
|
||||
destination.memoryAddress();
|
||||
|
||||
inflate.reset(inflateCtx);
|
||||
inflate.consumed = 0;
|
||||
inflate.finished = false;
|
||||
while (!deflate.finished) {
|
||||
if (!destination.isWritable()) {
|
||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
||||
}
|
||||
int produced = deflate.process(deflateCtx, source.memoryAddress() + source.readerIndex(),
|
||||
source.readableBytes(),
|
||||
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes(),
|
||||
!source.isReadable());
|
||||
source.readerIndex(source.readerIndex() + deflate.consumed);
|
||||
destination.writerIndex(destination.writerIndex() + produced);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
source.memoryAddress();
|
||||
destination.memoryAddress();
|
||||
deflate.reset(deflateCtx);
|
||||
deflate.consumed = 0;
|
||||
deflate.finished = false;
|
||||
}
|
||||
|
||||
while (!deflate.finished) {
|
||||
if (!destination.isWritable()) {
|
||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
||||
}
|
||||
int produced = deflate.process(deflateCtx, source.memoryAddress() + source.readerIndex(), source.readableBytes(),
|
||||
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes(), !source.isReadable());
|
||||
source.readerIndex(source.readerIndex() + deflate.consumed);
|
||||
destination.writerIndex(destination.writerIndex() + produced);
|
||||
}
|
||||
private void ensureNotDisposed() {
|
||||
Preconditions.checkState(!disposed, "Object already disposed");
|
||||
}
|
||||
|
||||
deflate.reset(deflateCtx);
|
||||
deflate.consumed = 0;
|
||||
deflate.finished = false;
|
||||
}
|
||||
|
||||
private void ensureNotDisposed() {
|
||||
Preconditions.checkState(!disposed, "Object already disposed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (!disposed) {
|
||||
inflate.free(inflateCtx);
|
||||
deflate.free(deflateCtx);
|
||||
}
|
||||
disposed = true;
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (!disposed) {
|
||||
inflate.free(inflateCtx);
|
||||
deflate.free(deflateCtx);
|
||||
}
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
@ -4,21 +4,23 @@ package com.velocitypowered.natives.compression;
|
||||
* Represents a native interface for zlib's deflate functions.
|
||||
*/
|
||||
class NativeZlibDeflate {
|
||||
boolean finished;
|
||||
int consumed;
|
||||
|
||||
native long init(int level);
|
||||
boolean finished;
|
||||
int consumed;
|
||||
|
||||
native long free(long ctx);
|
||||
native long init(int level);
|
||||
|
||||
native int process(long ctx, long sourceAddress, int sourceLength, long destinationAddress, int destinationLength,
|
||||
boolean flush);
|
||||
native long free(long ctx);
|
||||
|
||||
native void reset(long ctx);
|
||||
native int process(long ctx, long sourceAddress, int sourceLength, long destinationAddress,
|
||||
int destinationLength,
|
||||
boolean flush);
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
native void reset(long ctx);
|
||||
|
||||
private static native void initIDs();
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
}
|
||||
|
@ -4,20 +4,22 @@ package com.velocitypowered.natives.compression;
|
||||
* Represents a native interface for zlib's inflate functions.
|
||||
*/
|
||||
class NativeZlibInflate {
|
||||
boolean finished;
|
||||
int consumed;
|
||||
|
||||
native long init();
|
||||
boolean finished;
|
||||
int consumed;
|
||||
|
||||
native long free(long ctx);
|
||||
native long init();
|
||||
|
||||
native int process(long ctx, long sourceAddress, int sourceLength, long destinationAddress, int destinationLength);
|
||||
native long free(long ctx);
|
||||
|
||||
native void reset(long ctx);
|
||||
native int process(long ctx, long sourceAddress, int sourceLength, long destinationAddress,
|
||||
int destinationLength);
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
native void reset(long ctx);
|
||||
|
||||
private static native void initIDs();
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
}
|
||||
|
@ -2,19 +2,19 @@ package com.velocitypowered.natives.compression;
|
||||
|
||||
import com.velocitypowered.natives.Disposable;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
/**
|
||||
* Provides an interface to inflate and deflate {@link ByteBuf}s using zlib.
|
||||
*/
|
||||
public interface VelocityCompressor extends Disposable {
|
||||
/**
|
||||
* The default preferred output buffer size for zlib.
|
||||
*/
|
||||
int ZLIB_BUFFER_SIZE = 8192;
|
||||
|
||||
void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException;
|
||||
/**
|
||||
* The default preferred output buffer size for zlib.
|
||||
*/
|
||||
int ZLIB_BUFFER_SIZE = 8192;
|
||||
|
||||
void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException;
|
||||
void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException;
|
||||
|
||||
void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.velocitypowered.natives.compression;
|
||||
|
||||
public interface VelocityCompressorFactory {
|
||||
VelocityCompressor create(int level);
|
||||
|
||||
VelocityCompressor create(int level);
|
||||
}
|
||||
|
@ -2,53 +2,54 @@ package com.velocitypowered.natives.encryption;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.ShortBufferException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
public class JavaVelocityCipher implements VelocityCipher {
|
||||
public static final VelocityCipherFactory FACTORY = new VelocityCipherFactory() {
|
||||
@Override
|
||||
public VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException {
|
||||
return new JavaVelocityCipher(true, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException {
|
||||
return new JavaVelocityCipher(false, key);
|
||||
}
|
||||
};
|
||||
|
||||
private final Cipher cipher;
|
||||
private boolean disposed = false;
|
||||
|
||||
private JavaVelocityCipher(boolean encrypt, SecretKey key) throws GeneralSecurityException {
|
||||
this.cipher = Cipher.getInstance("AES/CFB8/NoPadding");
|
||||
this.cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, key, new IvParameterSpec(key.getEncoded()));
|
||||
public static final VelocityCipherFactory FACTORY = new VelocityCipherFactory() {
|
||||
@Override
|
||||
public VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException {
|
||||
return new JavaVelocityCipher(true, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException {
|
||||
ensureNotDisposed();
|
||||
|
||||
byte[] sourceAsBytes = new byte[source.readableBytes()];
|
||||
source.readBytes(sourceAsBytes);
|
||||
|
||||
int outputSize = cipher.getOutputSize(sourceAsBytes.length);
|
||||
byte[] destinationBytes = new byte[outputSize];
|
||||
cipher.update(sourceAsBytes, 0, sourceAsBytes.length, destinationBytes);
|
||||
destination.writeBytes(destinationBytes);
|
||||
public VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException {
|
||||
return new JavaVelocityCipher(false, key);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposed = true;
|
||||
}
|
||||
private final Cipher cipher;
|
||||
private boolean disposed = false;
|
||||
|
||||
private void ensureNotDisposed() {
|
||||
Preconditions.checkState(!disposed, "Object already disposed");
|
||||
}
|
||||
private JavaVelocityCipher(boolean encrypt, SecretKey key) throws GeneralSecurityException {
|
||||
this.cipher = Cipher.getInstance("AES/CFB8/NoPadding");
|
||||
this.cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, key,
|
||||
new IvParameterSpec(key.getEncoded()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException {
|
||||
ensureNotDisposed();
|
||||
|
||||
byte[] sourceAsBytes = new byte[source.readableBytes()];
|
||||
source.readBytes(sourceAsBytes);
|
||||
|
||||
int outputSize = cipher.getOutputSize(sourceAsBytes.length);
|
||||
byte[] destinationBytes = new byte[outputSize];
|
||||
cipher.update(sourceAsBytes, 0, sourceAsBytes.length, destinationBytes);
|
||||
destination.writeBytes(destinationBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
private void ensureNotDisposed() {
|
||||
Preconditions.checkState(!disposed, "Object already disposed");
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package com.velocitypowered.natives.encryption;
|
||||
|
||||
public class MbedtlsAesImpl {
|
||||
native long init(byte[] key);
|
||||
|
||||
native void process(long ctx, long sourceAddress, int sourceLength, long destinationAddress, boolean encrypt);
|
||||
native long init(byte[] key);
|
||||
|
||||
native void free(long ptr);
|
||||
native void process(long ctx, long sourceAddress, int sourceLength, long destinationAddress,
|
||||
boolean encrypt);
|
||||
|
||||
native void free(long ptr);
|
||||
}
|
||||
|
@ -1,55 +1,55 @@
|
||||
package com.velocitypowered.natives.encryption;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.ShortBufferException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
public class NativeVelocityCipher implements VelocityCipher {
|
||||
public static final VelocityCipherFactory FACTORY = new VelocityCipherFactory() {
|
||||
@Override
|
||||
public VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException {
|
||||
return new NativeVelocityCipher(true, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException {
|
||||
return new NativeVelocityCipher(false, key);
|
||||
}
|
||||
};
|
||||
private static final MbedtlsAesImpl impl = new MbedtlsAesImpl();
|
||||
|
||||
private final long ctx;
|
||||
private final boolean encrypt;
|
||||
private boolean disposed = false;
|
||||
|
||||
private NativeVelocityCipher(boolean encrypt, SecretKey key) {
|
||||
this.encrypt = encrypt;
|
||||
this.ctx = impl.init(key.getEncoded());
|
||||
public static final VelocityCipherFactory FACTORY = new VelocityCipherFactory() {
|
||||
@Override
|
||||
public VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException {
|
||||
return new NativeVelocityCipher(true, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException {
|
||||
source.memoryAddress();
|
||||
destination.memoryAddress();
|
||||
|
||||
// The exact amount we read in is also the amount we write out.
|
||||
int len = source.readableBytes();
|
||||
destination.ensureWritable(len);
|
||||
|
||||
impl.process(ctx, source.memoryAddress() + source.readerIndex(), len,
|
||||
destination.memoryAddress() + destination.writerIndex(), encrypt);
|
||||
|
||||
source.skipBytes(len);
|
||||
destination.writerIndex(destination.writerIndex() + len);
|
||||
public VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException {
|
||||
return new NativeVelocityCipher(false, key);
|
||||
}
|
||||
};
|
||||
private static final MbedtlsAesImpl impl = new MbedtlsAesImpl();
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (!disposed) {
|
||||
impl.free(ctx);
|
||||
}
|
||||
disposed = true;
|
||||
private final long ctx;
|
||||
private final boolean encrypt;
|
||||
private boolean disposed = false;
|
||||
|
||||
private NativeVelocityCipher(boolean encrypt, SecretKey key) {
|
||||
this.encrypt = encrypt;
|
||||
this.ctx = impl.init(key.getEncoded());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException {
|
||||
source.memoryAddress();
|
||||
destination.memoryAddress();
|
||||
|
||||
// The exact amount we read in is also the amount we write out.
|
||||
int len = source.readableBytes();
|
||||
destination.ensureWritable(len);
|
||||
|
||||
impl.process(ctx, source.memoryAddress() + source.readerIndex(), len,
|
||||
destination.memoryAddress() + destination.writerIndex(), encrypt);
|
||||
|
||||
source.skipBytes(len);
|
||||
destination.writerIndex(destination.writerIndex() + len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (!disposed) {
|
||||
impl.free(ctx);
|
||||
}
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ package com.velocitypowered.natives.encryption;
|
||||
|
||||
import com.velocitypowered.natives.Disposable;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import javax.crypto.ShortBufferException;
|
||||
|
||||
public interface VelocityCipher extends Disposable {
|
||||
void process(ByteBuf source, ByteBuf destination) throws ShortBufferException;
|
||||
|
||||
void process(ByteBuf source, ByteBuf destination) throws ShortBufferException;
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package com.velocitypowered.natives.encryption;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.GeneralSecurityException;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public interface VelocityCipherFactory {
|
||||
VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException;
|
||||
|
||||
VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException;
|
||||
VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException;
|
||||
|
||||
VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException;
|
||||
}
|
||||
|
@ -1,81 +1,85 @@
|
||||
package com.velocitypowered.natives.util;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public final class NativeCodeLoader<T> implements Supplier<T> {
|
||||
private final Variant<T> selected;
|
||||
|
||||
NativeCodeLoader(List<Variant<T>> variants) {
|
||||
this.selected = getVariant(variants);
|
||||
private final Variant<T> selected;
|
||||
|
||||
NativeCodeLoader(List<Variant<T>> variants) {
|
||||
this.selected = getVariant(variants);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return selected.object;
|
||||
}
|
||||
|
||||
private static <T> Variant<T> getVariant(List<Variant<T>> variants) {
|
||||
for (Variant<T> variant : variants) {
|
||||
T got = variant.get();
|
||||
if (got == null) {
|
||||
continue;
|
||||
}
|
||||
return variant;
|
||||
}
|
||||
throw new IllegalArgumentException("Can't find any suitable variants");
|
||||
}
|
||||
|
||||
public String getLoadedVariant() {
|
||||
return selected.name;
|
||||
}
|
||||
|
||||
static class Variant<T> {
|
||||
|
||||
private Status status;
|
||||
private final Runnable setup;
|
||||
private final String name;
|
||||
private final T object;
|
||||
|
||||
Variant(BooleanSupplier possiblyAvailable, Runnable setup, String name, T object) {
|
||||
this.status =
|
||||
possiblyAvailable.getAsBoolean() ? Status.POSSIBLY_AVAILABLE : Status.NOT_AVAILABLE;
|
||||
this.setup = setup;
|
||||
this.name = name;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return selected.object;
|
||||
}
|
||||
public @Nullable T get() {
|
||||
if (status == Status.NOT_AVAILABLE || status == Status.SETUP_FAILURE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static <T> Variant<T> getVariant(List<Variant<T>> variants) {
|
||||
for (Variant<T> variant : variants) {
|
||||
T got = variant.get();
|
||||
if (got == null) {
|
||||
continue;
|
||||
}
|
||||
return variant;
|
||||
// Make sure setup happens only once
|
||||
if (status == Status.POSSIBLY_AVAILABLE) {
|
||||
try {
|
||||
setup.run();
|
||||
status = Status.SETUP;
|
||||
} catch (Exception e) {
|
||||
status = Status.SETUP_FAILURE;
|
||||
return null;
|
||||
}
|
||||
throw new IllegalArgumentException("Can't find any suitable variants");
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
public String getLoadedVariant() {
|
||||
return selected.name;
|
||||
}
|
||||
private enum Status {
|
||||
NOT_AVAILABLE,
|
||||
POSSIBLY_AVAILABLE,
|
||||
SETUP,
|
||||
SETUP_FAILURE
|
||||
}
|
||||
|
||||
static class Variant<T> {
|
||||
private Status status;
|
||||
private final Runnable setup;
|
||||
private final String name;
|
||||
private final T object;
|
||||
|
||||
Variant(BooleanSupplier possiblyAvailable, Runnable setup, String name, T object) {
|
||||
this.status = possiblyAvailable.getAsBoolean() ? Status.POSSIBLY_AVAILABLE : Status.NOT_AVAILABLE;
|
||||
this.setup = setup;
|
||||
this.name = name;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public @Nullable T get() {
|
||||
if (status == Status.NOT_AVAILABLE || status == Status.SETUP_FAILURE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make sure setup happens only once
|
||||
if (status == Status.POSSIBLY_AVAILABLE) {
|
||||
try {
|
||||
setup.run();
|
||||
status = Status.SETUP;
|
||||
} catch (Exception e) {
|
||||
status = Status.SETUP_FAILURE;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
private enum Status {
|
||||
NOT_AVAILABLE,
|
||||
POSSIBLY_AVAILABLE,
|
||||
SETUP,
|
||||
SETUP_FAILURE
|
||||
}
|
||||
|
||||
static final BooleanSupplier MACOS = () -> System.getProperty("os.name", "").equalsIgnoreCase("Mac OS X") &&
|
||||
System.getProperty("os.arch").equals("x86_64");
|
||||
static final BooleanSupplier LINUX = () -> System.getProperties().getProperty("os.name", "").equalsIgnoreCase("Linux") &&
|
||||
System.getProperty("os.arch").equals("amd64");
|
||||
static final BooleanSupplier ALWAYS = () -> true;
|
||||
static final BooleanSupplier MACOS = () ->
|
||||
System.getProperty("os.name", "").equalsIgnoreCase("Mac OS X") &&
|
||||
System.getProperty("os.arch").equals("x86_64");
|
||||
static final BooleanSupplier LINUX = () ->
|
||||
System.getProperties().getProperty("os.name", "").equalsIgnoreCase("Linux") &&
|
||||
System.getProperty("os.arch").equals("amd64");
|
||||
static final BooleanSupplier ALWAYS = () -> true;
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import com.velocitypowered.natives.compression.NativeVelocityCompressor;
|
||||
import com.velocitypowered.natives.compression.VelocityCompressorFactory;
|
||||
import com.velocitypowered.natives.encryption.JavaVelocityCipher;
|
||||
import com.velocitypowered.natives.encryption.VelocityCipherFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
@ -14,55 +13,58 @@ import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
public class Natives {
|
||||
private Natives() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
private static Runnable copyAndLoadNative(String path) {
|
||||
return () -> {
|
||||
try {
|
||||
Path tempFile = Files.createTempFile("native-", path.substring(path.lastIndexOf('.')));
|
||||
InputStream nativeLib = Natives.class.getResourceAsStream(path);
|
||||
if (nativeLib == null) {
|
||||
throw new IllegalStateException("Native library " + path + " not found.");
|
||||
}
|
||||
private Natives() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
Files.copy(nativeLib, tempFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
try {
|
||||
Files.deleteIfExists(tempFile);
|
||||
} catch (IOException ignored) {
|
||||
// Well, it doesn't matter...
|
||||
}
|
||||
}));
|
||||
System.load(tempFile.toAbsolutePath().toString());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
private static Runnable copyAndLoadNative(String path) {
|
||||
return () -> {
|
||||
try {
|
||||
Path tempFile = Files.createTempFile("native-", path.substring(path.lastIndexOf('.')));
|
||||
InputStream nativeLib = Natives.class.getResourceAsStream(path);
|
||||
if (nativeLib == null) {
|
||||
throw new IllegalStateException("Native library " + path + " not found.");
|
||||
}
|
||||
|
||||
public static final NativeCodeLoader<VelocityCompressorFactory> compressor = new NativeCodeLoader<>(
|
||||
ImmutableList.of(
|
||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS,
|
||||
copyAndLoadNative("/macosx/velocity-compress.dylib"), "native (macOS)",
|
||||
NativeVelocityCompressor.FACTORY),
|
||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX,
|
||||
copyAndLoadNative("/linux_x64/velocity-compress.so"), "native (Linux amd64)",
|
||||
NativeVelocityCompressor.FACTORY),
|
||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {}, "Java", JavaVelocityCompressor.FACTORY)
|
||||
)
|
||||
);
|
||||
Files.copy(nativeLib, tempFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
try {
|
||||
Files.deleteIfExists(tempFile);
|
||||
} catch (IOException ignored) {
|
||||
// Well, it doesn't matter...
|
||||
}
|
||||
}));
|
||||
System.load(tempFile.toAbsolutePath().toString());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final NativeCodeLoader<VelocityCipherFactory> cipher = new NativeCodeLoader<>(
|
||||
ImmutableList.of(
|
||||
public static final NativeCodeLoader<VelocityCompressorFactory> compressor = new NativeCodeLoader<>(
|
||||
ImmutableList.of(
|
||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS,
|
||||
copyAndLoadNative("/macosx/velocity-compress.dylib"), "native (macOS)",
|
||||
NativeVelocityCompressor.FACTORY),
|
||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX,
|
||||
copyAndLoadNative("/linux_x64/velocity-compress.so"), "native (Linux amd64)",
|
||||
NativeVelocityCompressor.FACTORY),
|
||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {
|
||||
}, "Java", JavaVelocityCompressor.FACTORY)
|
||||
)
|
||||
);
|
||||
|
||||
public static final NativeCodeLoader<VelocityCipherFactory> cipher = new NativeCodeLoader<>(
|
||||
ImmutableList.of(
|
||||
/*new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS,
|
||||
copyAndLoadNative("/macosx/velocity-cipher.dylib"), "mbed TLS (macOS)",
|
||||
NativeVelocityCipher.FACTORY),
|
||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX,
|
||||
copyAndLoadNative("/linux_x64/velocity-cipher.so"), "mbed TLS (Linux amd64)",
|
||||
NativeVelocityCipher.FACTORY),*/
|
||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {}, "Java", JavaVelocityCipher.FACTORY)
|
||||
)
|
||||
);
|
||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {
|
||||
}, "Java", JavaVelocityCipher.FACTORY)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1,65 +1,66 @@
|
||||
package com.velocitypowered.natives.compression;
|
||||
|
||||
import com.velocitypowered.natives.util.Natives;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.condition.OS.LINUX;
|
||||
import static org.junit.jupiter.api.condition.OS.MAC;
|
||||
|
||||
import com.velocitypowered.natives.util.Natives;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.util.Random;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||
|
||||
class VelocityCompressorTest {
|
||||
@BeforeAll
|
||||
static void checkNatives() {
|
||||
Natives.compressor.getLoadedVariant();
|
||||
|
||||
@BeforeAll
|
||||
static void checkNatives() {
|
||||
Natives.compressor.getLoadedVariant();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs({MAC, LINUX})
|
||||
void nativeIntegrityCheck() throws DataFormatException {
|
||||
VelocityCompressor compressor = Natives.compressor.get().create(Deflater.DEFAULT_COMPRESSION);
|
||||
if (compressor instanceof JavaVelocityCompressor) {
|
||||
compressor.dispose();
|
||||
fail("Loaded regular compressor");
|
||||
}
|
||||
check(compressor);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs({ MAC, LINUX })
|
||||
void nativeIntegrityCheck() throws DataFormatException {
|
||||
VelocityCompressor compressor = Natives.compressor.get().create(Deflater.DEFAULT_COMPRESSION);
|
||||
if (compressor instanceof JavaVelocityCompressor) {
|
||||
compressor.dispose();
|
||||
fail("Loaded regular compressor");
|
||||
}
|
||||
check(compressor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaIntegrityCheck() throws DataFormatException {
|
||||
VelocityCompressor compressor = JavaVelocityCompressor.FACTORY.create(Deflater.DEFAULT_COMPRESSION);
|
||||
check(compressor);
|
||||
}
|
||||
|
||||
private void check(VelocityCompressor compressor) throws DataFormatException {
|
||||
ByteBuf source = Unpooled.directBuffer();
|
||||
ByteBuf dest = Unpooled.directBuffer();
|
||||
ByteBuf decompressed = Unpooled.directBuffer();
|
||||
|
||||
Random random = new Random(1);
|
||||
byte[] randomBytes = new byte[1 << 16];
|
||||
random.nextBytes(randomBytes);
|
||||
source.writeBytes(randomBytes);
|
||||
|
||||
try {
|
||||
compressor.deflate(source, dest);
|
||||
compressor.inflate(dest, decompressed);
|
||||
source.readerIndex(0);
|
||||
assertTrue(ByteBufUtil.equals(source, decompressed));
|
||||
} finally {
|
||||
source.release();
|
||||
dest.release();
|
||||
decompressed.release();
|
||||
compressor.dispose();
|
||||
}
|
||||
@Test
|
||||
void javaIntegrityCheck() throws DataFormatException {
|
||||
VelocityCompressor compressor = JavaVelocityCompressor.FACTORY
|
||||
.create(Deflater.DEFAULT_COMPRESSION);
|
||||
check(compressor);
|
||||
}
|
||||
|
||||
private void check(VelocityCompressor compressor) throws DataFormatException {
|
||||
ByteBuf source = Unpooled.directBuffer();
|
||||
ByteBuf dest = Unpooled.directBuffer();
|
||||
ByteBuf decompressed = Unpooled.directBuffer();
|
||||
|
||||
Random random = new Random(1);
|
||||
byte[] randomBytes = new byte[1 << 16];
|
||||
random.nextBytes(randomBytes);
|
||||
source.writeBytes(randomBytes);
|
||||
|
||||
try {
|
||||
compressor.deflate(source, dest);
|
||||
compressor.inflate(dest, decompressed);
|
||||
source.readerIndex(0);
|
||||
assertTrue(ByteBufUtil.equals(source, decompressed));
|
||||
} finally {
|
||||
source.release();
|
||||
dest.release();
|
||||
decompressed.release();
|
||||
compressor.dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,71 +1,71 @@
|
||||
package com.velocitypowered.natives.encryption;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import com.velocitypowered.natives.util.Natives;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Random;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
class VelocityCipherTest {
|
||||
private static final int ENCRYPT_DATA_SIZE = 1 << 16;
|
||||
|
||||
@BeforeAll
|
||||
static void checkNatives() {
|
||||
Natives.cipher.getLoadedVariant();
|
||||
private static final int ENCRYPT_DATA_SIZE = 1 << 16;
|
||||
|
||||
@BeforeAll
|
||||
static void checkNatives() {
|
||||
Natives.cipher.getLoadedVariant();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void nativeIntegrityCheck() throws GeneralSecurityException {
|
||||
VelocityCipherFactory factory = Natives.cipher.get();
|
||||
if (factory == JavaVelocityCipher.FACTORY) {
|
||||
fail("Loaded regular compressor");
|
||||
}
|
||||
check(factory);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void nativeIntegrityCheck() throws GeneralSecurityException {
|
||||
VelocityCipherFactory factory = Natives.cipher.get();
|
||||
if (factory == JavaVelocityCipher.FACTORY) {
|
||||
fail("Loaded regular compressor");
|
||||
}
|
||||
check(factory);
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaIntegrityCheck() throws GeneralSecurityException {
|
||||
check(JavaVelocityCipher.FACTORY);
|
||||
}
|
||||
|
||||
private void check(VelocityCipherFactory factory) throws GeneralSecurityException {
|
||||
// Generate a random 16-byte key.
|
||||
Random random = new Random(1);
|
||||
byte[] key = new byte[16];
|
||||
random.nextBytes(key);
|
||||
|
||||
VelocityCipher decrypt = factory.forDecryption(new SecretKeySpec(key, "AES"));
|
||||
VelocityCipher encrypt = factory.forEncryption(new SecretKeySpec(key, "AES"));
|
||||
|
||||
ByteBuf source = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
|
||||
ByteBuf dest = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
|
||||
ByteBuf decryptionBuf = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
|
||||
|
||||
byte[] randomBytes = new byte[ENCRYPT_DATA_SIZE];
|
||||
random.nextBytes(randomBytes);
|
||||
source.writeBytes(randomBytes);
|
||||
|
||||
try {
|
||||
encrypt.process(source, dest);
|
||||
decrypt.process(dest, decryptionBuf);
|
||||
source.readerIndex(0);
|
||||
assertTrue(ByteBufUtil.equals(source, decryptionBuf));
|
||||
} finally {
|
||||
source.release();
|
||||
dest.release();
|
||||
decryptionBuf.release();
|
||||
decrypt.dispose();
|
||||
encrypt.dispose();
|
||||
}
|
||||
@Test
|
||||
void javaIntegrityCheck() throws GeneralSecurityException {
|
||||
check(JavaVelocityCipher.FACTORY);
|
||||
}
|
||||
|
||||
private void check(VelocityCipherFactory factory) throws GeneralSecurityException {
|
||||
// Generate a random 16-byte key.
|
||||
Random random = new Random(1);
|
||||
byte[] key = new byte[16];
|
||||
random.nextBytes(key);
|
||||
|
||||
VelocityCipher decrypt = factory.forDecryption(new SecretKeySpec(key, "AES"));
|
||||
VelocityCipher encrypt = factory.forEncryption(new SecretKeySpec(key, "AES"));
|
||||
|
||||
ByteBuf source = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
|
||||
ByteBuf dest = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
|
||||
ByteBuf decryptionBuf = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
|
||||
|
||||
byte[] randomBytes = new byte[ENCRYPT_DATA_SIZE];
|
||||
random.nextBytes(randomBytes);
|
||||
source.writeBytes(randomBytes);
|
||||
|
||||
try {
|
||||
encrypt.process(source, dest);
|
||||
decrypt.process(dest, decryptionBuf);
|
||||
source.readerIndex(0);
|
||||
assertTrue(ByteBufUtil.equals(source, decryptionBuf));
|
||||
} finally {
|
||||
source.release();
|
||||
dest.release();
|
||||
decryptionBuf.release();
|
||||
decrypt.dispose();
|
||||
encrypt.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,11 @@ plugins {
|
||||
id 'java'
|
||||
id 'com.github.johnrengelman.shadow' version '2.0.4'
|
||||
id 'de.sebastianboegl.shadow.transformer.log4j' version '2.1.1'
|
||||
id 'checkstyle'
|
||||
}
|
||||
|
||||
apply from: '../gradle/checkerframework.gradle'
|
||||
|
||||
compileJava {
|
||||
options.compilerArgs += ['-proc:none']
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
options.compilerArgs += ['-proc:none']
|
||||
}
|
||||
apply from: '../gradle/checkstyle.gradle'
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
|
@ -1,29 +1,29 @@
|
||||
package com.velocitypowered.proxy;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class Velocity {
|
||||
private static final Logger logger = LogManager.getLogger(Velocity.class);
|
||||
|
||||
static {
|
||||
// We use BufferedImage for favicons, and on macOS this puts the Java application in the dock. How inconvenient.
|
||||
// Force AWT to work with its head chopped off.
|
||||
System.setProperty("java.awt.headless", "true");
|
||||
}
|
||||
private static final Logger logger = LogManager.getLogger(Velocity.class);
|
||||
|
||||
public static void main(String... args) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
static {
|
||||
// We use BufferedImage for favicons, and on macOS this puts the Java application in the dock. How inconvenient.
|
||||
// Force AWT to work with its head chopped off.
|
||||
System.setProperty("java.awt.headless", "true");
|
||||
}
|
||||
|
||||
VelocityServer server = new VelocityServer();
|
||||
server.start();
|
||||
public static void main(String... args) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(server::shutdown, "Shutdown thread"));
|
||||
VelocityServer server = new VelocityServer();
|
||||
server.start();
|
||||
|
||||
double bootTime = (System.currentTimeMillis() - startTime) / 1000d;
|
||||
logger.info("Done ({}s)!", new DecimalFormat("#.##").format(bootTime));
|
||||
server.getConsoleCommandSource().start();
|
||||
}
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(server::shutdown, "Shutdown thread"));
|
||||
|
||||
double bootTime = (System.currentTimeMillis() - startTime) / 1000d;
|
||||
logger.info("Done ({}s)!", new DecimalFormat("#.##").format(bootTime));
|
||||
server.getConsoleCommandSource().start();
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import com.velocitypowered.proxy.config.AnnotatedConfig;
|
||||
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
import com.velocitypowered.proxy.console.VelocityConsole;
|
||||
import com.velocitypowered.proxy.util.VelocityChannelRegistrar;
|
||||
import com.velocitypowered.proxy.network.ConnectionManager;
|
||||
import com.velocitypowered.proxy.network.http.NettyHttpClient;
|
||||
import com.velocitypowered.proxy.plugin.VelocityEventManager;
|
||||
@ -36,356 +35,367 @@ import com.velocitypowered.proxy.server.ServerMap;
|
||||
import com.velocitypowered.proxy.util.AddressUtil;
|
||||
import com.velocitypowered.proxy.util.EncryptionUtils;
|
||||
import com.velocitypowered.proxy.util.Ratelimiter;
|
||||
import com.velocitypowered.proxy.util.VelocityChannelRegistrar;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.serializer.GsonComponentSerializer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.*;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyPair;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.serializer.GsonComponentSerializer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
public class VelocityServer implements ProxyServer {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(VelocityServer.class);
|
||||
public static final Gson GSON = new GsonBuilder()
|
||||
.registerTypeHierarchyAdapter(Component.class, new GsonComponentSerializer())
|
||||
.registerTypeHierarchyAdapter(Favicon.class, new FaviconSerializer())
|
||||
.create();
|
||||
private static final Logger logger = LogManager.getLogger(VelocityServer.class);
|
||||
public static final Gson GSON = new GsonBuilder()
|
||||
.registerTypeHierarchyAdapter(Component.class, new GsonComponentSerializer())
|
||||
.registerTypeHierarchyAdapter(Favicon.class, new FaviconSerializer())
|
||||
.create();
|
||||
|
||||
private @MonotonicNonNull ConnectionManager cm;
|
||||
private @MonotonicNonNull VelocityConfiguration configuration;
|
||||
private @MonotonicNonNull NettyHttpClient httpClient;
|
||||
private @MonotonicNonNull KeyPair serverKeyPair;
|
||||
private @MonotonicNonNull ServerMap servers;
|
||||
private final VelocityCommandManager commandManager = new VelocityCommandManager();
|
||||
private final AtomicBoolean shutdownInProgress = new AtomicBoolean(false);
|
||||
private boolean shutdown = false;
|
||||
private @MonotonicNonNull VelocityPluginManager pluginManager;
|
||||
private @MonotonicNonNull ConnectionManager cm;
|
||||
private @MonotonicNonNull VelocityConfiguration configuration;
|
||||
private @MonotonicNonNull NettyHttpClient httpClient;
|
||||
private @MonotonicNonNull KeyPair serverKeyPair;
|
||||
private @MonotonicNonNull ServerMap servers;
|
||||
private final VelocityCommandManager commandManager = new VelocityCommandManager();
|
||||
private final AtomicBoolean shutdownInProgress = new AtomicBoolean(false);
|
||||
private boolean shutdown = false;
|
||||
private @MonotonicNonNull VelocityPluginManager pluginManager;
|
||||
|
||||
private final Map<UUID, ConnectedPlayer> connectionsByUuid = new ConcurrentHashMap<>();
|
||||
private final Map<String, ConnectedPlayer> connectionsByName = new ConcurrentHashMap<>();
|
||||
private @MonotonicNonNull VelocityConsole console;
|
||||
private @MonotonicNonNull Ratelimiter ipAttemptLimiter;
|
||||
private @MonotonicNonNull VelocityEventManager eventManager;
|
||||
private @MonotonicNonNull VelocityScheduler scheduler;
|
||||
private final VelocityChannelRegistrar channelRegistrar = new VelocityChannelRegistrar();
|
||||
private final Map<UUID, ConnectedPlayer> connectionsByUuid = new ConcurrentHashMap<>();
|
||||
private final Map<String, ConnectedPlayer> connectionsByName = new ConcurrentHashMap<>();
|
||||
private @MonotonicNonNull VelocityConsole console;
|
||||
private @MonotonicNonNull Ratelimiter ipAttemptLimiter;
|
||||
private @MonotonicNonNull VelocityEventManager eventManager;
|
||||
private @MonotonicNonNull VelocityScheduler scheduler;
|
||||
private final VelocityChannelRegistrar channelRegistrar = new VelocityChannelRegistrar();
|
||||
|
||||
public KeyPair getServerKeyPair() {
|
||||
if (serverKeyPair == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
return serverKeyPair;
|
||||
public KeyPair getServerKeyPair() {
|
||||
if (serverKeyPair == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
return serverKeyPair;
|
||||
}
|
||||
|
||||
public VelocityConfiguration getConfiguration() {
|
||||
VelocityConfiguration cfg = this.configuration;
|
||||
if (cfg == null) {
|
||||
throw new IllegalStateException("Configuration not initialized!");
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxyVersion getVersion() {
|
||||
Package pkg = VelocityServer.class.getPackage();
|
||||
String implName;
|
||||
String implVersion;
|
||||
String implVendor;
|
||||
if (pkg != null) {
|
||||
implName = MoreObjects.firstNonNull(pkg.getImplementationTitle(), "Velocity");
|
||||
implVersion = MoreObjects.firstNonNull(pkg.getImplementationVersion(), "<unknown>");
|
||||
implVendor = MoreObjects.firstNonNull(pkg.getImplementationVendor(), "Velocity Contributors");
|
||||
} else {
|
||||
implName = "Velocity";
|
||||
implVersion = "<unknown>";
|
||||
implVendor = "Velocity Contributors";
|
||||
}
|
||||
|
||||
public VelocityConfiguration getConfiguration() {
|
||||
VelocityConfiguration cfg = this.configuration;
|
||||
if (cfg == null) {
|
||||
throw new IllegalStateException("Configuration not initialized!");
|
||||
}
|
||||
return cfg;
|
||||
return new ProxyVersion(implName, implVendor, implVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityCommandManager getCommandManager() {
|
||||
return commandManager;
|
||||
}
|
||||
|
||||
@EnsuresNonNull({"serverKeyPair", "servers", "pluginManager", "eventManager", "scheduler",
|
||||
"console", "cm", "configuration"})
|
||||
public void start() {
|
||||
logger.info("Booting up {} {}...", getVersion().getName(), getVersion().getVersion());
|
||||
|
||||
serverKeyPair = EncryptionUtils.createRsaKeyPair(1024);
|
||||
pluginManager = new VelocityPluginManager(this);
|
||||
eventManager = new VelocityEventManager(pluginManager);
|
||||
scheduler = new VelocityScheduler(pluginManager);
|
||||
console = new VelocityConsole(this);
|
||||
cm = new ConnectionManager(this);
|
||||
servers = new ServerMap(this);
|
||||
|
||||
cm.logChannelInformation();
|
||||
|
||||
// Initialize commands first
|
||||
commandManager.register(new VelocityCommand(this), "velocity");
|
||||
commandManager.register(new ServerCommand(this), "server");
|
||||
commandManager.register(new ShutdownCommand(this), "shutdown", "end");
|
||||
|
||||
try {
|
||||
Path configPath = Paths.get("velocity.toml");
|
||||
configuration = VelocityConfiguration.read(configPath);
|
||||
|
||||
if (!configuration.validate()) {
|
||||
logger.error(
|
||||
"Your configuration is invalid. Velocity will refuse to start up until the errors are resolved.");
|
||||
LogManager.shutdown();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
AnnotatedConfig
|
||||
.saveConfig(configuration.dumpConfig(), configPath); //Resave config to add new values
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to read/load/save your velocity.toml. The server will shut down.", e);
|
||||
LogManager.shutdown();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxyVersion getVersion() {
|
||||
Package pkg = VelocityServer.class.getPackage();
|
||||
String implName;
|
||||
String implVersion;
|
||||
String implVendor;
|
||||
if (pkg != null) {
|
||||
implName = MoreObjects.firstNonNull(pkg.getImplementationTitle(), "Velocity");
|
||||
implVersion = MoreObjects.firstNonNull(pkg.getImplementationVersion(), "<unknown>");
|
||||
implVendor = MoreObjects.firstNonNull(pkg.getImplementationVendor(), "Velocity Contributors");
|
||||
} else {
|
||||
implName = "Velocity";
|
||||
implVersion = "<unknown>";
|
||||
implVendor = "Velocity Contributors";
|
||||
for (Map.Entry<String, String> entry : configuration.getServers().entrySet()) {
|
||||
servers.register(new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue())));
|
||||
}
|
||||
|
||||
ipAttemptLimiter = new Ratelimiter(configuration.getLoginRatelimit());
|
||||
httpClient = new NettyHttpClient(this);
|
||||
loadPlugins();
|
||||
|
||||
// Go ahead and fire the proxy initialization event. We block since plugins should have a chance
|
||||
// to fully initialize before we accept any connections to the server.
|
||||
eventManager.fire(new ProxyInitializeEvent()).join();
|
||||
|
||||
// init console permissions after plugins are loaded
|
||||
console.setupPermissions();
|
||||
|
||||
this.cm.bind(configuration.getBind());
|
||||
|
||||
if (configuration.isQueryEnabled()) {
|
||||
this.cm.queryBind(configuration.getBind().getHostString(), configuration.getQueryPort());
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresNonNull({"pluginManager", "eventManager"})
|
||||
private void loadPlugins() {
|
||||
logger.info("Loading plugins...");
|
||||
|
||||
try {
|
||||
Path pluginPath = Paths.get("plugins");
|
||||
|
||||
if (!pluginPath.toFile().exists()) {
|
||||
Files.createDirectory(pluginPath);
|
||||
} else {
|
||||
if (!pluginPath.toFile().isDirectory()) {
|
||||
logger.warn("Plugin location {} is not a directory, continuing without loading plugins",
|
||||
pluginPath);
|
||||
return;
|
||||
}
|
||||
|
||||
return new ProxyVersion(implName, implVendor, implVersion);
|
||||
pluginManager.loadPlugins(pluginPath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Couldn't load plugins", e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityCommandManager getCommandManager() {
|
||||
return commandManager;
|
||||
// Register the plugin main classes so that we may proceed with firing the proxy initialize event
|
||||
for (PluginContainer plugin : pluginManager.getPlugins()) {
|
||||
Optional<?> instance = plugin.getInstance();
|
||||
if (instance.isPresent()) {
|
||||
eventManager.register(instance.get(), instance.get());
|
||||
}
|
||||
}
|
||||
|
||||
@EnsuresNonNull({"serverKeyPair", "servers", "pluginManager", "eventManager", "scheduler", "console", "cm", "configuration"})
|
||||
public void start() {
|
||||
logger.info("Booting up {} {}...", getVersion().getName(), getVersion().getVersion());
|
||||
logger.info("Loaded {} plugins", pluginManager.getPlugins().size());
|
||||
}
|
||||
|
||||
serverKeyPair = EncryptionUtils.createRsaKeyPair(1024);
|
||||
pluginManager = new VelocityPluginManager(this);
|
||||
eventManager = new VelocityEventManager(pluginManager);
|
||||
scheduler = new VelocityScheduler(pluginManager);
|
||||
console = new VelocityConsole(this);
|
||||
cm = new ConnectionManager(this);
|
||||
servers = new ServerMap(this);
|
||||
public Bootstrap initializeGenericBootstrap() {
|
||||
if (cm == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return this.cm.createWorker();
|
||||
}
|
||||
|
||||
cm.logChannelInformation();
|
||||
public boolean isShutdown() {
|
||||
return shutdown;
|
||||
}
|
||||
|
||||
// Initialize commands first
|
||||
commandManager.register(new VelocityCommand(this), "velocity");
|
||||
commandManager.register(new ServerCommand(this), "server");
|
||||
commandManager.register(new ShutdownCommand(this), "shutdown", "end");
|
||||
|
||||
try {
|
||||
Path configPath = Paths.get("velocity.toml");
|
||||
configuration = VelocityConfiguration.read(configPath);
|
||||
|
||||
if (!configuration.validate()) {
|
||||
logger.error("Your configuration is invalid. Velocity will refuse to start up until the errors are resolved.");
|
||||
LogManager.shutdown();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
AnnotatedConfig.saveConfig(configuration.dumpConfig(), configPath); //Resave config to add new values
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to read/load/save your velocity.toml. The server will shut down.", e);
|
||||
LogManager.shutdown();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : configuration.getServers().entrySet()) {
|
||||
servers.register(new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue())));
|
||||
}
|
||||
|
||||
ipAttemptLimiter = new Ratelimiter(configuration.getLoginRatelimit());
|
||||
httpClient = new NettyHttpClient(this);
|
||||
loadPlugins();
|
||||
|
||||
// Go ahead and fire the proxy initialization event. We block since plugins should have a chance
|
||||
// to fully initialize before we accept any connections to the server.
|
||||
eventManager.fire(new ProxyInitializeEvent()).join();
|
||||
|
||||
// init console permissions after plugins are loaded
|
||||
console.setupPermissions();
|
||||
|
||||
this.cm.bind(configuration.getBind());
|
||||
|
||||
if (configuration.isQueryEnabled()) {
|
||||
this.cm.queryBind(configuration.getBind().getHostString(), configuration.getQueryPort());
|
||||
}
|
||||
public void shutdown() {
|
||||
if (eventManager == null || pluginManager == null || cm == null || scheduler == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@RequiresNonNull({"pluginManager", "eventManager"})
|
||||
private void loadPlugins() {
|
||||
logger.info("Loading plugins...");
|
||||
if (!shutdownInProgress.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
logger.info("Shutting down the proxy...");
|
||||
|
||||
try {
|
||||
Path pluginPath = Paths.get("plugins");
|
||||
|
||||
if (!pluginPath.toFile().exists()) {
|
||||
Files.createDirectory(pluginPath);
|
||||
} else {
|
||||
if (!pluginPath.toFile().isDirectory()) {
|
||||
logger.warn("Plugin location {} is not a directory, continuing without loading plugins", pluginPath);
|
||||
return;
|
||||
}
|
||||
|
||||
pluginManager.loadPlugins(pluginPath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Couldn't load plugins", e);
|
||||
}
|
||||
|
||||
// Register the plugin main classes so that we may proceed with firing the proxy initialize event
|
||||
for (PluginContainer plugin : pluginManager.getPlugins()) {
|
||||
Optional<?> instance = plugin.getInstance();
|
||||
if (instance.isPresent()) {
|
||||
eventManager.register(instance.get(), instance.get());
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Loaded {} plugins", pluginManager.getPlugins().size());
|
||||
for (ConnectedPlayer player : ImmutableList.copyOf(connectionsByUuid.values())) {
|
||||
player.close(TextComponent.of("Proxy shutting down."));
|
||||
}
|
||||
|
||||
public Bootstrap initializeGenericBootstrap() {
|
||||
if (cm == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return this.cm.createWorker();
|
||||
this.cm.shutdown();
|
||||
|
||||
eventManager.fire(new ProxyShutdownEvent());
|
||||
try {
|
||||
if (!eventManager.shutdown() || !scheduler.shutdown()) {
|
||||
logger.error("Your plugins took over 10 seconds to shut down.");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// Not much we can do about this...
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
public boolean isShutdown() {
|
||||
return shutdown;
|
||||
shutdown = true;
|
||||
}
|
||||
|
||||
public NettyHttpClient getHttpClient() {
|
||||
if (httpClient == null) {
|
||||
throw new IllegalStateException("HTTP client not initialized");
|
||||
}
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (eventManager == null || pluginManager == null || cm == null || scheduler == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
if (!shutdownInProgress.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
logger.info("Shutting down the proxy...");
|
||||
|
||||
for (ConnectedPlayer player : ImmutableList.copyOf(connectionsByUuid.values())) {
|
||||
player.close(TextComponent.of("Proxy shutting down."));
|
||||
}
|
||||
|
||||
this.cm.shutdown();
|
||||
|
||||
eventManager.fire(new ProxyShutdownEvent());
|
||||
try {
|
||||
if (!eventManager.shutdown() || !scheduler.shutdown()) {
|
||||
logger.error("Your plugins took over 10 seconds to shut down.");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// Not much we can do about this...
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
shutdown = true;
|
||||
public Ratelimiter getIpAttemptLimiter() {
|
||||
if (ipAttemptLimiter == null) {
|
||||
throw new IllegalStateException("Ratelimiter not initialized");
|
||||
}
|
||||
return ipAttemptLimiter;
|
||||
}
|
||||
|
||||
public NettyHttpClient getHttpClient() {
|
||||
if (httpClient == null) {
|
||||
throw new IllegalStateException("HTTP client not initialized");
|
||||
}
|
||||
return httpClient;
|
||||
public boolean registerConnection(ConnectedPlayer connection) {
|
||||
String lowerName = connection.getUsername().toLowerCase(Locale.US);
|
||||
if (connectionsByName.putIfAbsent(lowerName, connection) != null) {
|
||||
return false;
|
||||
}
|
||||
if (connectionsByUuid.putIfAbsent(connection.getUniqueId(), connection) != null) {
|
||||
connectionsByName.remove(lowerName, connection);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Ratelimiter getIpAttemptLimiter() {
|
||||
if (ipAttemptLimiter == null) {
|
||||
throw new IllegalStateException("Ratelimiter not initialized");
|
||||
}
|
||||
return ipAttemptLimiter;
|
||||
}
|
||||
public void unregisterConnection(ConnectedPlayer connection) {
|
||||
connectionsByName.remove(connection.getUsername().toLowerCase(Locale.US), connection);
|
||||
connectionsByUuid.remove(connection.getUniqueId(), connection);
|
||||
}
|
||||
|
||||
public boolean registerConnection(ConnectedPlayer connection) {
|
||||
String lowerName = connection.getUsername().toLowerCase(Locale.US);
|
||||
if (connectionsByName.putIfAbsent(lowerName, connection) != null) {
|
||||
return false;
|
||||
}
|
||||
if (connectionsByUuid.putIfAbsent(connection.getUniqueId(), connection) != null) {
|
||||
connectionsByName.remove(lowerName, connection);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public Optional<Player> getPlayer(String username) {
|
||||
Preconditions.checkNotNull(username, "username");
|
||||
return Optional.ofNullable(connectionsByName.get(username.toLowerCase(Locale.US)));
|
||||
}
|
||||
|
||||
public void unregisterConnection(ConnectedPlayer connection) {
|
||||
connectionsByName.remove(connection.getUsername().toLowerCase(Locale.US), connection);
|
||||
connectionsByUuid.remove(connection.getUniqueId(), connection);
|
||||
}
|
||||
@Override
|
||||
public Optional<Player> getPlayer(UUID uuid) {
|
||||
Preconditions.checkNotNull(uuid, "uuid");
|
||||
return Optional.ofNullable(connectionsByUuid.get(uuid));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Player> getPlayer(String username) {
|
||||
Preconditions.checkNotNull(username, "username");
|
||||
return Optional.ofNullable(connectionsByName.get(username.toLowerCase(Locale.US)));
|
||||
@Override
|
||||
public void broadcast(Component component) {
|
||||
Preconditions.checkNotNull(component, "component");
|
||||
Chat chat = Chat.createClientbound(component);
|
||||
for (ConnectedPlayer player : connectionsByUuid.values()) {
|
||||
player.getConnection().write(chat);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Player> getPlayer(UUID uuid) {
|
||||
Preconditions.checkNotNull(uuid, "uuid");
|
||||
return Optional.ofNullable(connectionsByUuid.get(uuid));
|
||||
}
|
||||
@Override
|
||||
public Collection<Player> getAllPlayers() {
|
||||
return ImmutableList.copyOf(connectionsByUuid.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcast(Component component) {
|
||||
Preconditions.checkNotNull(component, "component");
|
||||
Chat chat = Chat.createClientbound(component);
|
||||
for (ConnectedPlayer player : connectionsByUuid.values()) {
|
||||
player.getConnection().write(chat);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int getPlayerCount() {
|
||||
return connectionsByUuid.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Player> getAllPlayers() {
|
||||
return ImmutableList.copyOf(connectionsByUuid.values());
|
||||
@Override
|
||||
public Optional<RegisteredServer> getServer(String name) {
|
||||
Preconditions.checkNotNull(name, "name");
|
||||
if (servers == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return servers.getServer(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerCount() {
|
||||
return connectionsByUuid.size();
|
||||
@Override
|
||||
public Collection<RegisteredServer> getAllServers() {
|
||||
if (servers == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return servers.getAllServers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RegisteredServer> getServer(String name) {
|
||||
Preconditions.checkNotNull(name, "name");
|
||||
if (servers == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return servers.getServer(name);
|
||||
@Override
|
||||
public RegisteredServer registerServer(ServerInfo server) {
|
||||
if (servers == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return servers.register(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RegisteredServer> getAllServers() {
|
||||
if (servers == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return servers.getAllServers();
|
||||
@Override
|
||||
public void unregisterServer(ServerInfo server) {
|
||||
if (servers == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
servers.unregister(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisteredServer registerServer(ServerInfo server) {
|
||||
if (servers == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return servers.register(server);
|
||||
@Override
|
||||
public VelocityConsole getConsoleCommandSource() {
|
||||
if (console == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return console;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterServer(ServerInfo server) {
|
||||
if (servers == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
servers.unregister(server);
|
||||
@Override
|
||||
public PluginManager getPluginManager() {
|
||||
if (pluginManager == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return pluginManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityConsole getConsoleCommandSource() {
|
||||
if (console == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return console;
|
||||
@Override
|
||||
public EventManager getEventManager() {
|
||||
if (eventManager == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return eventManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginManager getPluginManager() {
|
||||
if (pluginManager == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return pluginManager;
|
||||
@Override
|
||||
public VelocityScheduler getScheduler() {
|
||||
if (scheduler == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventManager getEventManager() {
|
||||
if (eventManager == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return eventManager;
|
||||
}
|
||||
@Override
|
||||
public VelocityChannelRegistrar getChannelRegistrar() {
|
||||
return channelRegistrar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityScheduler getScheduler() {
|
||||
if (scheduler == null) {
|
||||
throw new IllegalStateException("Server did not initialize properly.");
|
||||
}
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VelocityChannelRegistrar getChannelRegistrar() {
|
||||
return channelRegistrar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getBoundAddress() {
|
||||
if (configuration == null) {
|
||||
throw new IllegalStateException("No configuration"); // even though you'll never get the chance... heh, heh
|
||||
}
|
||||
return configuration.getBind();
|
||||
@Override
|
||||
public InetSocketAddress getBoundAddress() {
|
||||
if (configuration == null) {
|
||||
throw new IllegalStateException(
|
||||
"No configuration"); // even though you'll never get the chance... heh, heh
|
||||
}
|
||||
return configuration.getBind();
|
||||
}
|
||||
}
|
||||
|
@ -9,90 +9,96 @@ import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.ClickEvent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.format.TextColor;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ServerCommand implements Command {
|
||||
private final ProxyServer server;
|
||||
|
||||
public ServerCommand(ProxyServer server) {
|
||||
this.server = server;
|
||||
private final ProxyServer server;
|
||||
|
||||
public ServerCommand(ProxyServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSource source, String @NonNull [] args) {
|
||||
if (!(source instanceof Player)) {
|
||||
source.sendMessage(TextComponent.of("Only players may run this command.", TextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSource source, String @NonNull [] args) {
|
||||
if (!(source instanceof Player)) {
|
||||
source.sendMessage(TextComponent.of("Only players may run this command.", TextColor.RED));
|
||||
return;
|
||||
}
|
||||
Player player = (Player) source;
|
||||
if (args.length == 1) {
|
||||
// Trying to connect to a server.
|
||||
String serverName = args[0];
|
||||
Optional<RegisteredServer> toConnect = server.getServer(serverName);
|
||||
if (!toConnect.isPresent()) {
|
||||
player.sendMessage(
|
||||
TextComponent.of("Server " + serverName + " doesn't exist.", TextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = (Player) source;
|
||||
if (args.length == 1) {
|
||||
// Trying to connect to a server.
|
||||
String serverName = args[0];
|
||||
Optional<RegisteredServer> toConnect = server.getServer(serverName);
|
||||
if (!toConnect.isPresent()) {
|
||||
player.sendMessage(TextComponent.of("Server " + serverName + " doesn't exist.", TextColor.RED));
|
||||
return;
|
||||
}
|
||||
player.createConnectionRequest(toConnect.get()).fireAndForget();
|
||||
} else {
|
||||
String currentServer = player.getCurrentServer().map(ServerConnection::getServerInfo)
|
||||
.map(ServerInfo::getName)
|
||||
.orElse("<unknown>");
|
||||
player.sendMessage(TextComponent
|
||||
.of("You are currently connected to " + currentServer + ".", TextColor.YELLOW));
|
||||
|
||||
player.createConnectionRequest(toConnect.get()).fireAndForget();
|
||||
// Assemble the list of servers as components
|
||||
TextComponent.Builder serverListBuilder = TextComponent.builder("Available servers: ")
|
||||
.color(TextColor.YELLOW);
|
||||
List<RegisteredServer> infos = ImmutableList.copyOf(server.getAllServers());
|
||||
for (int i = 0; i < infos.size(); i++) {
|
||||
RegisteredServer rs = infos.get(i);
|
||||
TextComponent infoComponent = TextComponent.of(rs.getServerInfo().getName());
|
||||
String playersText = rs.getPlayersConnected().size() + " player(s) online";
|
||||
if (rs.getServerInfo().getName().equals(currentServer)) {
|
||||
infoComponent = infoComponent.color(TextColor.GREEN)
|
||||
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||
TextComponent.of("Currently connected to this server\n" + playersText)));
|
||||
} else {
|
||||
String currentServer = player.getCurrentServer().map(ServerConnection::getServerInfo).map(ServerInfo::getName)
|
||||
.orElse("<unknown>");
|
||||
player.sendMessage(TextComponent.of("You are currently connected to " + currentServer + ".", TextColor.YELLOW));
|
||||
|
||||
// Assemble the list of servers as components
|
||||
TextComponent.Builder serverListBuilder = TextComponent.builder("Available servers: ").color(TextColor.YELLOW);
|
||||
List<RegisteredServer> infos = ImmutableList.copyOf(server.getAllServers());
|
||||
for (int i = 0; i < infos.size(); i++) {
|
||||
RegisteredServer rs = infos.get(i);
|
||||
TextComponent infoComponent = TextComponent.of(rs.getServerInfo().getName());
|
||||
String playersText = rs.getPlayersConnected().size() + " player(s) online";
|
||||
if (rs.getServerInfo().getName().equals(currentServer)) {
|
||||
infoComponent = infoComponent.color(TextColor.GREEN)
|
||||
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||
TextComponent.of("Currently connected to this server\n" + playersText)));
|
||||
} else {
|
||||
infoComponent = infoComponent.color(TextColor.GRAY)
|
||||
.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/server " + rs.getServerInfo().getName()))
|
||||
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to connect to this server\n" + playersText)));
|
||||
}
|
||||
serverListBuilder.append(infoComponent);
|
||||
if (i != infos.size() - 1) {
|
||||
serverListBuilder.append(TextComponent.of(", ", TextColor.GRAY));
|
||||
}
|
||||
}
|
||||
|
||||
player.sendMessage(serverListBuilder.build());
|
||||
infoComponent = infoComponent.color(TextColor.GRAY)
|
||||
.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
|
||||
"/server " + rs.getServerInfo().getName()))
|
||||
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||
TextComponent.of("Click to connect to this server\n" + playersText)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandSource source, String @NonNull [] currentArgs) {
|
||||
if (currentArgs.length == 0) {
|
||||
return server.getAllServers().stream()
|
||||
.map(rs -> rs.getServerInfo().getName())
|
||||
.collect(Collectors.toList());
|
||||
} else if (currentArgs.length == 1) {
|
||||
return server.getAllServers().stream()
|
||||
.map(rs -> rs.getServerInfo().getName())
|
||||
.filter(name -> name.regionMatches(true, 0, currentArgs[0], 0, currentArgs[0].length()))
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
return ImmutableList.of();
|
||||
serverListBuilder.append(infoComponent);
|
||||
if (i != infos.size() - 1) {
|
||||
serverListBuilder.append(TextComponent.of(", ", TextColor.GRAY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSource source, String @NonNull [] args) {
|
||||
return source.getPermissionValue("velocity.command.server") != Tristate.FALSE;
|
||||
player.sendMessage(serverListBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandSource source, String @NonNull [] currentArgs) {
|
||||
if (currentArgs.length == 0) {
|
||||
return server.getAllServers().stream()
|
||||
.map(rs -> rs.getServerInfo().getName())
|
||||
.collect(Collectors.toList());
|
||||
} else if (currentArgs.length == 1) {
|
||||
return server.getAllServers().stream()
|
||||
.map(rs -> rs.getServerInfo().getName())
|
||||
.filter(name -> name.regionMatches(true, 0, currentArgs[0], 0, currentArgs[0].length()))
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSource source, String @NonNull [] args) {
|
||||
return source.getPermissionValue("velocity.command.server") != Tristate.FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -8,23 +8,25 @@ import net.kyori.text.format.TextColor;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public class ShutdownCommand implements Command {
|
||||
private final VelocityServer server;
|
||||
|
||||
public ShutdownCommand(VelocityServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
private final VelocityServer server;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSource source, String @NonNull [] args) {
|
||||
if (source != server.getConsoleCommandSource()) {
|
||||
source.sendMessage(TextComponent.of("You are not allowed to use this command.", TextColor.RED));
|
||||
return;
|
||||
}
|
||||
server.shutdown();
|
||||
}
|
||||
public ShutdownCommand(VelocityServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSource source, String @NonNull [] args) {
|
||||
return source == server.getConsoleCommandSource();
|
||||
@Override
|
||||
public void execute(CommandSource source, String @NonNull [] args) {
|
||||
if (source != server.getConsoleCommandSource()) {
|
||||
source
|
||||
.sendMessage(TextComponent.of("You are not allowed to use this command.", TextColor.RED));
|
||||
return;
|
||||
}
|
||||
server.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSource source, String @NonNull [] args) {
|
||||
return source == server.getConsoleCommandSource();
|
||||
}
|
||||
}
|
||||
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren