Initial commit
commit
76040ff950
|
@ -0,0 +1,33 @@
|
|||
# Eclipse #
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
|
||||
# IntelliJ #
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
# NetBeans #
|
||||
|
||||
nbproject
|
||||
|
||||
# Maven #
|
||||
build.xml
|
||||
target
|
||||
|
||||
# Mac #
|
||||
.DS_Store
|
||||
|
||||
# Vim #
|
||||
.*.sw[a-p]
|
||||
|
||||
# Misc #
|
||||
build
|
||||
bin
|
||||
dist
|
||||
manifest.mf
|
||||
|
||||
# Deploy #
|
||||
pom.xml.releaseBackup
|
||||
release.properties
|
||||
/.gradle/
|
|
@ -0,0 +1,26 @@
|
|||
plugins {
|
||||
id 'net.kyori.blossom' version '1.1.0'
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group 'me.crypnotic'
|
||||
version '1.0.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
url 'https://repo.velocitypowered.com/snapshots/'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.velocitypowered:velocity-api:1.0-SNAPSHOT'
|
||||
compile 'org.projectlombok:lombok:1.18.4'
|
||||
}
|
||||
|
||||
blossom {
|
||||
replaceToken '@ID@', name.toLowerCase()
|
||||
replaceToken '@NAME@', name
|
||||
replaceToken '@VERSION@', version
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-bin.zip
|
|
@ -0,0 +1,172 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
|
@ -0,0 +1,84 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
|
@ -0,0 +1 @@
|
|||
rootProject.name = 'Neutron'
|
|
@ -0,0 +1,68 @@
|
|||
package me.crypnotic.neutron;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.velocitypowered.api.command.CommandManager;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.crypnotic.neutron.api.Neutron;
|
||||
import me.crypnotic.neutron.command.AlertCommand;
|
||||
import me.crypnotic.neutron.command.FindCommand;
|
||||
import me.crypnotic.neutron.command.InfoCommand;
|
||||
import me.crypnotic.neutron.command.ListCommand;
|
||||
import me.crypnotic.neutron.command.MessageCommand;
|
||||
import me.crypnotic.neutron.command.SendCommand;
|
||||
import me.crypnotic.neutron.command.ServerCommand;
|
||||
import me.crypnotic.neutron.manager.ModuleManager;
|
||||
|
||||
@Plugin(id = "@ID@", name = "@NAME@", version = "@VERSION@")
|
||||
public class NeutronPlugin {
|
||||
|
||||
@Inject
|
||||
@Getter
|
||||
private ProxyServer proxy;
|
||||
@Inject
|
||||
@Getter
|
||||
private Logger logger;
|
||||
@Inject
|
||||
@DataDirectory
|
||||
@Getter
|
||||
private Path dataFolderPath;
|
||||
|
||||
@Getter
|
||||
private ModuleManager moduleManager;
|
||||
|
||||
@Subscribe
|
||||
public void onProxyInitialize(ProxyInitializeEvent event) {
|
||||
Neutron.setNeutron(this);
|
||||
|
||||
this.moduleManager = new ModuleManager();
|
||||
|
||||
if (!moduleManager.init()) {
|
||||
logger.warn("Failed to initialize ModuleManager");
|
||||
return;
|
||||
}
|
||||
|
||||
registerCommands();
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
CommandManager commandManager = proxy.getCommandManager();
|
||||
|
||||
commandManager.register(new AlertCommand(), "alert");
|
||||
commandManager.register(new FindCommand(), "find");
|
||||
commandManager.register(new InfoCommand(), "info");
|
||||
commandManager.register(new ListCommand(), "glist");
|
||||
commandManager.register(new MessageCommand(), "message", "msg", "tell", "whisper");
|
||||
commandManager.register(new SendCommand(), "send");
|
||||
commandManager.register(new ServerCommand(), "server");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package me.crypnotic.neutron.api;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
|
||||
import me.crypnotic.neutron.NeutronPlugin;
|
||||
import me.crypnotic.neutron.manager.ModuleManager;
|
||||
|
||||
public interface INeutronAccessor {
|
||||
|
||||
default NeutronPlugin getPlugin() {
|
||||
return Neutron.getNeutron();
|
||||
}
|
||||
|
||||
default ProxyServer getProxy() {
|
||||
return getPlugin().getProxy();
|
||||
}
|
||||
|
||||
default Logger getLogger() {
|
||||
return getPlugin().getLogger();
|
||||
}
|
||||
|
||||
default Path getDataFolderPath() {
|
||||
return getPlugin().getDataFolderPath();
|
||||
}
|
||||
|
||||
default ModuleManager getModuleManager() {
|
||||
return getPlugin().getModuleManager();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package me.crypnotic.neutron.api;
|
||||
|
||||
import me.crypnotic.neutron.NeutronPlugin;
|
||||
|
||||
public class Neutron {
|
||||
|
||||
private static Object LOCK = new Object();
|
||||
private static NeutronPlugin instance;
|
||||
|
||||
public static final NeutronPlugin getNeutron() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static final void setNeutron(NeutronPlugin plugin) {
|
||||
if (plugin == null) {
|
||||
throw new IllegalStateException("NeutronPlugin instance cannot be null");
|
||||
}
|
||||
|
||||
if (instance == null) {
|
||||
synchronized (LOCK) {
|
||||
if (instance == null) {
|
||||
instance = plugin;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("NeutronPlugin instance cannot be redefined");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package me.crypnotic.neutron.api.command;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CommandContext {
|
||||
|
||||
private final String[] arguments;
|
||||
|
||||
public String get(int index) {
|
||||
if (index >= size()) {
|
||||
throw new IllegalArgumentException("Index: " + index + " > Length: " + size());
|
||||
}
|
||||
return arguments[index];
|
||||
}
|
||||
|
||||
public Integer getInteger(int index) {
|
||||
try {
|
||||
return Integer.valueOf(get(index));
|
||||
} catch (NumberFormatException exception) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public String join(String delimeter) {
|
||||
return String.join(" ", arguments);
|
||||
}
|
||||
|
||||
public String join(String delimeter, int start) {
|
||||
return join(delimeter, start, size());
|
||||
}
|
||||
|
||||
public String join(String delimeter, int start, int end) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = start; i < end; i++) {
|
||||
builder.append(get(i));
|
||||
if (i < end) {
|
||||
builder.append(delimeter);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return arguments.length;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package me.crypnotic.neutron.api.command;
|
||||
|
||||
import com.velocitypowered.api.command.Command;
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import me.crypnotic.neutron.api.INeutronAccessor;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
|
||||
public interface CommandWrapper extends Command, INeutronAccessor {
|
||||
|
||||
@Override
|
||||
default void execute(CommandSource source, String[] args) {
|
||||
try {
|
||||
handle(source, new CommandContext(args));
|
||||
} catch (CommandExitException exception) {
|
||||
/* Catch silently */
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
default void assertUsage(CommandSource source, boolean assertion) {
|
||||
assertCustom(source, assertion, "&cUsage: {0}", getUsage());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
default void assertPlayer(CommandSource source, String message, Object... values) {
|
||||
assertCustom(source, source instanceof Player, message, values);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
default void assertNull(CommandSource source, Object value, String message, Object... values) {
|
||||
assertCustom(source, value == null, message, values);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
default void assertNotNull(CommandSource source, Object value, String message, Object... values) {
|
||||
assertCustom(source, value != null, message, values);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
default void assertPermission(CommandSource source, String permission) {
|
||||
assertCustom(source, source.hasPermission(permission), "&cYou don't have permission to execute this command.");
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
default void assertCustom(CommandSource source, boolean assertion, String message, Object... values) {
|
||||
if (!assertion) {
|
||||
message(source, message, values);
|
||||
|
||||
throw new CommandExitException();
|
||||
}
|
||||
}
|
||||
|
||||
default void message(CommandSource source, String message, Object... values) {
|
||||
source.sendMessage(Strings.formatAndColor(message, values));
|
||||
}
|
||||
|
||||
void handle(CommandSource source, CommandContext context) throws CommandExitException;
|
||||
|
||||
String getUsage();
|
||||
|
||||
public class CommandExitException extends Exception {
|
||||
private static final long serialVersionUID = -1299193476106186693L;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package me.crypnotic.neutron.command;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.crypnotic.neutron.api.command.CommandContext;
|
||||
import me.crypnotic.neutron.api.command.CommandWrapper;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
import net.kyori.text.TextComponent;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class AlertCommand implements CommandWrapper {
|
||||
|
||||
@Override
|
||||
public void handle(CommandSource source, CommandContext context) throws CommandExitException {
|
||||
assertPermission(source, "neutron.command.alert");
|
||||
assertUsage(source, context.size() > 0);
|
||||
|
||||
TextComponent message = Strings.formatAndColor("&7&l[&c&lALERT&7&l] &e" + context.join(" "));
|
||||
|
||||
getProxy().broadcast(message);
|
||||
|
||||
/* Log to console since ProxyServer#broadcast doesn't do so */
|
||||
getProxy().getConsoleCommandSource().sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "/alert (message)";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package me.crypnotic.neutron.command;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
|
||||
import me.crypnotic.neutron.api.command.CommandContext;
|
||||
import me.crypnotic.neutron.api.command.CommandWrapper;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
|
||||
public class FindCommand implements CommandWrapper {
|
||||
|
||||
@Override
|
||||
public void handle(CommandSource source, CommandContext context) throws CommandExitException {
|
||||
assertPermission(source, "neutron.command.find");
|
||||
assertUsage(source, context.size() > 0);
|
||||
|
||||
Player target = getProxy().getPlayer(context.get(0)).orElse(null);
|
||||
assertNotNull(source, target, "&cUnknown player: {0}", context.get(0));
|
||||
|
||||
ServerConnection server = target.getCurrentServer().get();
|
||||
/* We'll consider this offline as the Player is in a limbo state */
|
||||
assertNotNull(source, server, "&c{0} is currently offline.", context.get(0));
|
||||
|
||||
source.sendMessage(Strings.formatAndColor("&b{0} &7is connected to &b{1}", target.getUsername(), server.getServerInfo().getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandSource source, String[] args) {
|
||||
if (args.length == 0) {
|
||||
return Arrays.asList();
|
||||
}
|
||||
return Strings.matchPlayer(getProxy(), args[0]).stream().map(Player::getUsername).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "/find (player)";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package me.crypnotic.neutron.command;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
|
||||
import me.crypnotic.neutron.api.command.CommandContext;
|
||||
import me.crypnotic.neutron.api.command.CommandWrapper;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
|
||||
public class InfoCommand implements CommandWrapper {
|
||||
|
||||
@Override
|
||||
public void handle(CommandSource source, CommandContext context) throws CommandExitException {
|
||||
assertPermission(source, "neutron.command.info");
|
||||
assertUsage(source, context.size() > 0);
|
||||
|
||||
Player target = getProxy().getPlayer(context.get(0)).orElse(null);
|
||||
assertNotNull(source, target, "&cUnknown player: {0}", context.get(0));
|
||||
|
||||
ServerConnection server = target.getCurrentServer().orElse(null);
|
||||
|
||||
message(source, "&l&7==> Information for player: &b{0}", target.getUsername());
|
||||
message(source, "&7Unique Id: &b{0}", target.getUniqueId().toString());
|
||||
message(source, "&7Minecraft Version: &b{0}", target.getProtocolVersion());
|
||||
message(source, "&7Locale: &b{0}", target.getPlayerSettings().getLocale());
|
||||
message(source, "&7Current Server: &b{0}", server != null ? server.getServerInfo().getName() : "N/A");
|
||||
message(source, "&7Ping: &b{0}", target.getPing());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "/info (player)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandSource source, String[] args) {
|
||||
if (args.length == 0) {
|
||||
return Arrays.asList();
|
||||
}
|
||||
return Strings.matchPlayer(getProxy(), args[0]).stream().map(Player::getUsername).collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package me.crypnotic.neutron.command;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
|
||||
import me.crypnotic.neutron.api.command.CommandContext;
|
||||
import me.crypnotic.neutron.api.command.CommandWrapper;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.ClickEvent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
|
||||
public class ListCommand implements CommandWrapper {
|
||||
|
||||
@Override
|
||||
public void handle(CommandSource source, CommandContext context) throws CommandExitException {
|
||||
assertPermission(source, "neutron.command.list");
|
||||
|
||||
for (RegisteredServer server : getProxy().getAllServers()) {
|
||||
ServerInfo info = server.getServerInfo();
|
||||
Collection<Player> players = server.getPlayersConnected();
|
||||
|
||||
String playerString = players.stream().map(Player::getUsername).sorted(String.CASE_INSENSITIVE_ORDER).collect(Collectors.joining(", "));
|
||||
|
||||
TextComponent message = Strings.formatAndColor("&a[{0}] &e{1} player{2} online", info.getName(), players.size(),
|
||||
players.size() == 1 ? "" : "s");
|
||||
|
||||
message = message.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of(playerString)));
|
||||
message = message.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/server " + info.getName()));
|
||||
|
||||
source.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "/glist";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package me.crypnotic.neutron.command;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
import me.crypnotic.neutron.api.command.CommandContext;
|
||||
import me.crypnotic.neutron.api.command.CommandWrapper;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
import net.kyori.text.TextComponent;
|
||||
|
||||
public class MessageCommand implements CommandWrapper {
|
||||
|
||||
@Override
|
||||
public void handle(CommandSource source, CommandContext context) throws CommandExitException {
|
||||
assertPermission(source, "neutron.command.message");
|
||||
assertUsage(source, context.size() > 1);
|
||||
|
||||
Player target = getProxy().getPlayer(context.get(0)).orElse(null);
|
||||
assertNotNull(source, target, "&cUnknown player: {0}", context.get(0));
|
||||
|
||||
String sourceName = source instanceof Player ? ((Player) source).getUsername() : "Console";
|
||||
|
||||
TextComponent content = TextComponent.of(context.join(" ", 1));
|
||||
TextComponent sourceMessage = Strings.formatAndColor("&b&lme » {0} &7> &o", target.getUsername()).append(content);
|
||||
TextComponent targetMessage = Strings.formatAndColor("&b&l{0} » me &7> &o", sourceName).append(content);
|
||||
|
||||
source.sendMessage(sourceMessage);
|
||||
target.sendMessage(targetMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "/message (player) (message)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandSource source, String[] args) {
|
||||
if (args.length == 0) {
|
||||
return Arrays.asList();
|
||||
}
|
||||
return Strings.matchPlayer(getProxy(), args[0]).stream().map(Player::getUsername).collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package me.crypnotic.neutron.command;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
|
||||
import me.crypnotic.neutron.api.command.CommandContext;
|
||||
import me.crypnotic.neutron.api.command.CommandWrapper;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
|
||||
public class SendCommand implements CommandWrapper {
|
||||
|
||||
@Override
|
||||
public void handle(CommandSource source, CommandContext context) throws CommandExitException {
|
||||
assertPermission(source, "neutron.command.send");
|
||||
assertUsage(source, context.size() > 1);
|
||||
|
||||
RegisteredServer targetServer = getProxy().getServer(context.get(1).toLowerCase()).orElse(null);
|
||||
assertNotNull(source, targetServer, "&cUnknown server: {0}", context.get(1));
|
||||
|
||||
switch (context.get(0).toLowerCase()) {
|
||||
case "current":
|
||||
assertPlayer(source, "&cOnly players can use this subcommand.");
|
||||
|
||||
Player player = (Player) source;
|
||||
ServerConnection currentServer = player.getCurrentServer().orElse(null);
|
||||
assertNotNull(player, currentServer, "&cYou must be connected to a server to use this subcommand.");
|
||||
|
||||
currentServer.getServer().getPlayersConnected().forEach(targetPlayer -> {
|
||||
targetPlayer.createConnectionRequest(targetServer).fireAndForget();
|
||||
message(targetPlayer, "&aYou have been sent to &b{0}", targetServer.getServerInfo().getName());
|
||||
});
|
||||
|
||||
message(player, "&aAll players from your current server have been sent to &b{0}", targetServer.getServerInfo().getName());
|
||||
break;
|
||||
case "all":
|
||||
getProxy().getAllPlayers().forEach(targetPlayer -> {
|
||||
targetPlayer.createConnectionRequest(targetServer).fireAndForget();
|
||||
message(targetPlayer, "&aYou have been sent to &b{0}", targetServer.getServerInfo().getName());
|
||||
});
|
||||
|
||||
message(source, "&aAll players have been sent to &b{0}", targetServer.getServerInfo().getName());
|
||||
break;
|
||||
default:
|
||||
Player targetPlayer = getProxy().getPlayer(context.get(0)).orElse(null);
|
||||
assertNotNull(source, targetPlayer, "&cUnknown player: {0}", context.get(0));
|
||||
|
||||
targetPlayer.createConnectionRequest(targetServer).fireAndForget();
|
||||
message(targetPlayer, "&aYou have been sent to &b{0}", targetServer.getServerInfo().getName());
|
||||
message(source, "&b{0} &ahas been sent to &b{1}", targetPlayer.getUsername(), targetServer.getServerInfo().getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandSource source, String[] args) {
|
||||
if (args.length == 1) {
|
||||
List<String> result = Strings.matchPlayer(getProxy(), args[0]).stream().map(Player::getUsername).collect(Collectors.toList());
|
||||
|
||||
/* Inject `current`/`all` subcommands */
|
||||
result.add("current");
|
||||
result.add("all");
|
||||
|
||||
return result;
|
||||
} else if (args.length == 2) {
|
||||
return Strings.matchServer(getProxy(), args[1]).stream().map(server -> server.getServerInfo().getName()).collect(Collectors.toList());
|
||||
}
|
||||
return Arrays.asList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "/send (player / current / all) (server)";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package me.crypnotic.neutron.command;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
|
||||
import me.crypnotic.neutron.api.command.CommandContext;
|
||||
import me.crypnotic.neutron.api.command.CommandWrapper;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
|
||||
public class ServerCommand implements CommandWrapper {
|
||||
|
||||
@Override
|
||||
public void handle(CommandSource source, CommandContext context) throws CommandExitException {
|
||||
assertPlayer(source, "&cOnly players can use this command.");
|
||||
assertPermission(source, "neutron.command.server");
|
||||
assertUsage(source, context.size() > 0);
|
||||
|
||||
Player player = (Player) source;
|
||||
RegisteredServer server = getProxy().getServer(context.get(0)).orElse(null);
|
||||
|
||||
assertNotNull(source, server, "&cUnknown server: {0}", context.get(0));
|
||||
|
||||
player.createConnectionRequest(server).fireAndForget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "/server (name)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandSource source, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Strings.matchServer(getProxy(), args[0]).stream().map(server -> server.getServerInfo().getName()).collect(Collectors.toList());
|
||||
}
|
||||
return Arrays.asList();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package me.crypnotic.neutron.manager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.moandjiezana.toml.Toml;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyReloadEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.crypnotic.neutron.api.INeutronAccessor;
|
||||
import me.crypnotic.neutron.module.AbstractModule;
|
||||
import me.crypnotic.neutron.module.announcement.AnnouncementsModule;
|
||||
import me.crypnotic.neutron.module.serverlist.ServerListModule;
|
||||
import me.crypnotic.neutron.util.FileIO;
|
||||
|
||||
public class ModuleManager implements INeutronAccessor {
|
||||
|
||||
@Getter
|
||||
private File mainConfigFile;
|
||||
@Getter
|
||||
private Toml mainConfig;
|
||||
|
||||
private Map<Class<? extends AbstractModule>, AbstractModule> modules;
|
||||
|
||||
public boolean init() {
|
||||
this.modules = new HashMap<Class<? extends AbstractModule>, AbstractModule>();
|
||||
|
||||
try {
|
||||
this.mainConfigFile = FileIO.getOrCreate(getDataFolderPath(), "config.toml");
|
||||
this.mainConfig = new Toml().read(mainConfigFile);
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
modules.put(AnnouncementsModule.class, new AnnouncementsModule());
|
||||
modules.put(ServerListModule.class, new ServerListModule());
|
||||
|
||||
for (AbstractModule module : modules.values()) {
|
||||
Toml table = mainConfig.getTable(module.getName());
|
||||
if (table == null) {
|
||||
getLogger().warn("Unknown module attempted to load: " + module.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
module.setEnabled(table.getBoolean("enabled"));
|
||||
if (module.isEnabled()) {
|
||||
if (module.init()) {
|
||||
continue;
|
||||
} else {
|
||||
getLogger().warn("Module failed to initialize: " + module.getName());
|
||||
|
||||
module.setEnabled(false);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getProxy().getEventManager().register(getPlugin(), this);
|
||||
|
||||
getLogger().info("Modules loaded: " + modules.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onProxyReload(ProxyReloadEvent event) {
|
||||
try {
|
||||
this.mainConfigFile = FileIO.getOrCreate(getDataFolderPath(), "config.toml");
|
||||
this.mainConfig = new Toml().read(mainConfigFile);
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
for (AbstractModule module : modules.values()) {
|
||||
Toml table = mainConfig.getTable(module.getName());
|
||||
if (table == null) {
|
||||
getLogger().warn("Unknown module attempted to reload: " + module.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
module.setEnabled(table.getBoolean("enabled"));
|
||||
if (module.isEnabled()) {
|
||||
if (module.reload()) {
|
||||
continue;
|
||||
} else {
|
||||
getLogger().warn("Module failed to reload: " + module.getName());
|
||||
|
||||
module.setEnabled(false);
|
||||
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
getLogger().info(String.format("Modules reloaded: %d", modules.size()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends AbstractModule> Optional<T> get(Class<T> clazz) {
|
||||
return (Optional<T>) Optional.ofNullable(modules.get(clazz));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package me.crypnotic.neutron.module;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.crypnotic.neutron.api.INeutronAccessor;
|
||||
|
||||
public abstract class AbstractModule implements INeutronAccessor {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean enabled;
|
||||
|
||||
public abstract boolean init();
|
||||
|
||||
public abstract boolean reload();
|
||||
|
||||
public abstract boolean shutdown();
|
||||
|
||||
public abstract String getName();
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package me.crypnotic.neutron.module.announcement;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.moandjiezana.toml.Toml;
|
||||
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class Announcements {
|
||||
|
||||
@Getter
|
||||
private final String id;
|
||||
@Getter
|
||||
private final long interval;
|
||||
@Getter
|
||||
private final boolean maintainOrder;
|
||||
@Getter
|
||||
private final List<String> messages;
|
||||
@Getter
|
||||
private final String prefix;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private ScheduledTask task;
|
||||
|
||||
public static Announcements load(String id, Toml toml) {
|
||||
long interval = toml.getLong("interval");
|
||||
boolean maintainOrder = toml.getBoolean("maintain-order");
|
||||
String prefix = toml.contains("prefix") ? toml.getString("prefix") : "";
|
||||
List<String> messages = toml.getList("messages");
|
||||
|
||||
return new Announcements(id, interval, maintainOrder, messages, prefix);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package me.crypnotic.neutron.module.announcement;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.moandjiezana.toml.Toml;
|
||||
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||
|
||||
import me.crypnotic.neutron.module.AbstractModule;
|
||||
import me.crypnotic.neutron.util.FileIO;
|
||||
|
||||
public class AnnouncementsModule extends AbstractModule {
|
||||
|
||||
private File file;
|
||||
private Toml toml;
|
||||
private Map<String, Announcements> announcements;
|
||||
|
||||
public boolean init() {
|
||||
this.file = FileIO.getOrCreate(getDataFolderPath(), "announcements.toml");
|
||||
this.toml = new Toml().read(file);
|
||||
this.announcements = new HashMap<String, Announcements>();
|
||||
|
||||
for (Entry<String, Object> entry : toml.entrySet()) {
|
||||
String id = entry.getKey();
|
||||
if (announcements.containsKey(id)) {
|
||||
getLogger().warn("An announcement list has already been defined with the id: " + id);
|
||||
continue;
|
||||
}
|
||||
|
||||
Announcements announcement = Announcements.load(id, toml.getTable(id));
|
||||
if (announcement != null) {
|
||||
announcements.put(id, announcement);
|
||||
} else {
|
||||
getLogger().warn("Failed to load announcement list: " + id);
|
||||
}
|
||||
|
||||
ScheduledTask task = getProxy().getScheduler().buildTask(getPlugin(), new AnnouncementsTask(getPlugin(), announcement))
|
||||
.repeat(announcement.getInterval(), TimeUnit.SECONDS).schedule();
|
||||
|
||||
announcement.setTask(task);
|
||||
}
|
||||
|
||||
getLogger().info("Announcements loaded: " + announcements.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reload() {
|
||||
return shutdown() && init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shutdown() {
|
||||
announcements.values().stream().map(Announcements::getTask).forEach(ScheduledTask::cancel);
|
||||
|
||||
announcements.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "announcements";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package me.crypnotic.neutron.module.announcement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.crypnotic.neutron.NeutronPlugin;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
import net.kyori.text.TextComponent;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class AnnouncementsTask implements Runnable {
|
||||
|
||||
private final NeutronPlugin plugin;
|
||||
private final Announcements announcements;
|
||||
|
||||
private List<String> localMessages;
|
||||
|
||||
private volatile int index = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (index == 0) {
|
||||
if (localMessages == null) {
|
||||
/* Create a local copy to avoid reading or shuffling the master copy */
|
||||
this.localMessages = new ArrayList<String>(announcements.getMessages());
|
||||
}
|
||||
|
||||
if (!announcements.isMaintainOrder()) {
|
||||
Collections.shuffle(localMessages);
|
||||
}
|
||||
}
|
||||
|
||||
TextComponent message = Strings.formatAndColor("{0}{1}", announcements.getPrefix(), localMessages.get(index));
|
||||
|
||||
plugin.getProxy().broadcast(message);
|
||||
|
||||
index += 1;
|
||||
if (index == localMessages.size()) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package me.crypnotic.neutron.module.serverlist;
|
||||
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing.Builder;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing.SamplePlayer;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.crypnotic.neutron.api.INeutronAccessor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ServerListHandler implements INeutronAccessor {
|
||||
|
||||
private final ServerListModule module;
|
||||
|
||||
@Subscribe
|
||||
public void onServerListPing(ProxyPingEvent event) {
|
||||
if (!module.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerPing original = event.getPing();
|
||||
|
||||
int playerCount = getProxy().getPlayerCount();
|
||||
|
||||
Builder builder = ServerPing.builder();
|
||||
|
||||
builder.version(original.getVersion());
|
||||
builder.onlinePlayers(playerCount);
|
||||
|
||||
builder.description(module.getMotd());
|
||||
|
||||
switch (module.getPlayerCountType()) {
|
||||
case CURRENT:
|
||||
builder.maximumPlayers(playerCount);
|
||||
break;
|
||||
case ONEMORE:
|
||||
builder.maximumPlayers(playerCount + 1);
|
||||
break;
|
||||
case STATIC:
|
||||
builder.maximumPlayers(module.getMaxPlayerCount());
|
||||
break;
|
||||
}
|
||||
|
||||
switch (module.getServerPreviewType()) {
|
||||
case MESSAGE:
|
||||
builder.samplePlayers(module.getPreviewMessages());
|
||||
break;
|
||||
case PLAYERS:
|
||||
builder.samplePlayers(getProxy().getAllPlayers().stream().map(player -> new SamplePlayer(player.getUsername(), player.getUniqueId()))
|
||||
.toArray(SamplePlayer[]::new));
|
||||
break;
|
||||
case EMPTY:
|
||||
break;
|
||||
}
|
||||
|
||||
event.setPing(builder.build());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package me.crypnotic.neutron.module.serverlist;
|
||||
|
||||
import com.moandjiezana.toml.Toml;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing.SamplePlayer;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.crypnotic.neutron.module.AbstractModule;
|
||||
import me.crypnotic.neutron.util.Strings;
|
||||
import net.kyori.text.TextComponent;
|
||||
|
||||
public class ServerListModule extends AbstractModule {
|
||||
|
||||
private Toml toml;
|
||||
@Getter
|
||||
private TextComponent motd;
|
||||
@Getter
|
||||
private PlayerCountType playerCountType;
|
||||
@Getter
|
||||
private int maxPlayerCount;
|
||||
@Getter
|
||||
private ServerPreviewType serverPreviewType;
|
||||
@Getter
|
||||
private SamplePlayer[] previewMessages;
|
||||
|
||||
@Override
|
||||
public boolean init() {
|
||||
this.toml = getModuleManager().getMainConfig().getTable(getName());
|
||||
this.motd = Strings.color(toml.getString("motd"));
|
||||
|
||||
this.playerCountType = PlayerCountType.valueOf(toml.getString("player-count-type"));
|
||||
this.maxPlayerCount = toml.getLong("max-player-count").intValue();
|
||||
|
||||
this.serverPreviewType = ServerPreviewType.valueOf(toml.getString("server-preview-type"));
|
||||
this.previewMessages = toml.getList("preview-messages").stream().map(Object::toString).map(Strings::toSamplePlayer)
|
||||
.toArray(SamplePlayer[]::new);
|
||||
|
||||
getProxy().getEventManager().register(getPlugin(), new ServerListHandler(this));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reload() {
|
||||
return init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shutdown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "serverlist";
|
||||
}
|
||||
|
||||
public enum PlayerCountType {
|
||||
CURRENT,
|
||||
ONEMORE,
|
||||
STATIC;
|
||||
}
|
||||
|
||||
public enum ServerPreviewType {
|
||||
EMPTY,
|
||||
MESSAGE,
|
||||
PLAYERS;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package me.crypnotic.neutron.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import me.crypnotic.neutron.NeutronPlugin;
|
||||
|
||||
public class FileIO {
|
||||
|
||||
public static File getOrCreate(Path path, String name) {
|
||||
File file = new File(path.toFile(), name);
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
try (InputStream input = NeutronPlugin.class.getResourceAsStream("/" + name)) {
|
||||
if (input != null) {
|
||||
Files.copy(input, file.toPath());
|
||||
} else {
|
||||
file.createNewFile();
|
||||
}
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package me.crypnotic.neutron.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing.SamplePlayer;
|
||||
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.serializer.ComponentSerializers;
|
||||
|
||||
public class Strings {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static TextComponent color(String text) {
|
||||
return ComponentSerializers.LEGACY.deserialize(text, '&');
|
||||
}
|
||||
|
||||
public static String format(String text, Object... params) {
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
Object param = params[i];
|
||||
text = text.replace("{" + i + "}", param == null ? "null" : param.toString());
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public static TextComponent formatAndColor(String text, Object... params) {
|
||||
return color(format(text, params));
|
||||
}
|
||||
|
||||
public static Collection<Player> matchPlayer(ProxyServer proxy, String partialName) {
|
||||
// A better error message might be nice. This just mimics the previous output
|
||||
if (partialName == null) {
|
||||
throw new NullPointerException("partialName");
|
||||
}
|
||||
|
||||
Optional<Player> exactMatch = proxy.getPlayer(partialName);
|
||||
if (exactMatch.isPresent()) {
|
||||
return Collections.singleton(exactMatch.get());
|
||||
}
|
||||
|
||||
return proxy.getAllPlayers().stream().filter(player -> player.getUsername().regionMatches(true, 0, partialName, 0, partialName.length()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static Collection<RegisteredServer> matchServer(ProxyServer proxy, String partialName) {
|
||||
// A better error message might be nice. This just mimics the previous output
|
||||
if (partialName == null) {
|
||||
throw new NullPointerException("partialName");
|
||||
}
|
||||
|
||||
Optional<RegisteredServer> exactMatch = proxy.getServer(partialName);
|
||||
if (exactMatch.isPresent()) {
|
||||
return Collections.singleton(exactMatch.get());
|
||||
}
|
||||
|
||||
return proxy.getAllServers().stream()
|
||||
.filter(server -> server.getServerInfo().getName().regionMatches(true, 0, partialName, 0, partialName.length()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static SamplePlayer toSamplePlayer(String text) {
|
||||
return new SamplePlayer(ComponentSerializers.LEGACY.serialize(color(text)), UUID.randomUUID());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
# Add [name] to create a new annoucement list
|
||||
# Every list runs independently of one another
|
||||
#
|
||||
# A list must always contain three variables:
|
||||
#
|
||||
# - interval (how long to wait between messages - in seconds)
|
||||
# - maintain-order (whether the list should be annouced in order or randomly
|
||||
# - messages (the messages to be announced)
|
||||
#
|
||||
# The order in which these appear doesn't matter, but an announcement list will not load without them
|
||||
#
|
||||
# A list can also contain optional values:
|
||||
#
|
||||
# - prefix (the prefix to add before all messages in the list
|
||||
#
|
||||
[example]
|
||||
|
||||
# 5 minutes in seconds
|
||||
interval = 300
|
||||
maintain-order = true
|
||||
|
||||
# Optional
|
||||
prefix = "&7[&bNeutron&7] &7"
|
||||
|
||||
messages = [
|
||||
"Welcome to &bNeutron!",
|
||||
"Neutron is an open-source project willing to welcome contributors with open arms"
|
||||
]
|
|
@ -0,0 +1,31 @@
|
|||
[announcements]
|
||||
enabled = true
|
||||
|
||||
[serverlist]
|
||||
enabled = true
|
||||
|
||||
motd = "&7This velocity proxy is proudly powered by &bNeutron"
|
||||
|
||||
# The server list player count has three different types:
|
||||
#
|
||||
# STATIC - player count will always be the number defined under `max-player-count`
|
||||
# CURRENT - player count matches the number of players online
|
||||
# ONEMORE - player count shows the number of players online plus 1
|
||||
#
|
||||
# `max-player-count` is only used with the STATIC player count type
|
||||
|
||||
player-count-type = "STATIC"
|
||||
max-player-count = 500
|
||||
|
||||
# The server list preview has three different types:
|
||||
#
|
||||
# MESSAGE - preview will show the messages defined under `preview-messages`
|
||||
# PLAYERS - preview matches the vanilla server preview of showing online players
|
||||
# EMPTY - preview is empty
|
||||
#
|
||||
# `preview-messages` is only used with the MESSAGE preview type
|
||||
|
||||
server-preview-type = "MESSAGE"
|
||||
preview-messages = [
|
||||
"&7Powered by a &bNeutron"
|
||||
]
|
Loading…
Reference in New Issue