commit 392479abde8dfc890af012b9a8d1bdb02a4eb0cf Author: Frank van der Heijden Date: Tue Jun 2 21:07:31 2020 +0200 Initial commit diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..1b1bec2 --- /dev/null +++ b/build.gradle @@ -0,0 +1,40 @@ +plugins { + id 'java' + id 'com.github.johnrengelman.shadow' version '5.2.0' +} + +String packagePath = 'net.frankheijden.serverutils' +group = packagePath +version '1.0.0' +sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 + +repositories { + mavenCentral() + maven { url 'https://repo.aikar.co/content/groups/aikar/' } + maven { url 'https://papermc.io/repo/repository/maven-public/' } +} + +dependencies { + implementation 'co.aikar:acf-paper:0.5.0-SNAPSHOT' + compileOnly 'com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT' +} + +processResources { + from('src/main/resources') { + include 'plugin.yml' + expand(version: project.version) + } +} + +compileJava { + options.compilerArgs += ["-parameters"] + options.fork = true + options.forkOptions.executable = 'javac' +} + +shadowJar { + relocate 'co.aikar.commands', packagePath + '.acf' + relocate 'co.aikar.locales', packagePath + '.locales' +} + +build.dependsOn shadowJar \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f3d88b1 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..c70f986 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Jun 01 13:25:07 CEST 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..2fe81a7 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## 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='"-Xmx64m" "-Xms64m"' + +# 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 or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..9618d8d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@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="-Xmx64m" "-Xms64m" + +@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 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..2f0d576 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'ServerUtils' + diff --git a/src/main/java/net/frankheijden/serverutils/ServerUtils.java b/src/main/java/net/frankheijden/serverutils/ServerUtils.java new file mode 100644 index 0000000..c1fdd7b --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/ServerUtils.java @@ -0,0 +1,97 @@ +package net.frankheijden.serverutils; + +import co.aikar.commands.PaperCommandManager; +import net.frankheijden.serverutils.commands.CommandPlugins; +import net.frankheijden.serverutils.commands.CommandServerUtils; +import net.frankheijden.serverutils.config.Messenger; +import net.frankheijden.serverutils.reflection.*; +import org.bukkit.Bukkit; +import org.bukkit.command.*; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +public class ServerUtils extends JavaPlugin implements CommandExecutor { + + private static ServerUtils instance; + private PaperCommandManager commandManager; + + public static ServerUtils getInstance() { + return instance; + } + + @Override + public void onEnable() { + super.onEnable(); + instance = this; + + this.removeCommands("pl", "plugins"); + + commandManager = new PaperCommandManager(this); + commandManager.registerCommand(new CommandServerUtils()); + commandManager.registerCommand(new CommandPlugins()); + commandManager.getCommandCompletions().registerAsyncCompletion("plugins", context -> Arrays.stream(Bukkit.getPluginManager().getPlugins()) + .map(Plugin::getName) + .collect(Collectors.toList())); + commandManager.getCommandCompletions().registerAsyncCompletion("pluginJars", context -> Arrays.stream(getJars()) + .map(File::getName) + .collect(Collectors.toList())); + commandManager.getCommandCompletions().registerAsyncCompletion("supportedConfigs", context -> CommandServerUtils.getSupportedConfigs()); + reload(); + } + + @Override + public void onDisable() { + super.onDisable(); + } + + private void removeCommands(String... commands) { + Map map; + try { + map = RCommandMap.getKnownCommands(RCraftServer.getCommandMap()); + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + + for (String command : commands) { + map.remove(command); + } + } + + public void reload() { + new Messenger(copyResourceIfNotExists("messages.yml")); + } + + public PaperCommandManager getCommandManager() { + return commandManager; + } + + private File[] getJars() { + File parent = getDataFolder().getParentFile(); + if (parent == null) return new File[0]; + return parent.listFiles(f -> f.getName().endsWith(".jar")); + } + + private void createDataFolderIfNotExists() { + if (!getDataFolder().exists()) { + getDataFolder().mkdirs(); + } + } + + private File copyResourceIfNotExists(String resource) { + createDataFolderIfNotExists(); + + File file = new File(getDataFolder(), resource); + if (!file.exists()) { + getLogger().info(String.format("'%s' not found, creating!", resource)); + saveResource(resource, false); + } + return file; + } +} diff --git a/src/main/java/net/frankheijden/serverutils/commands/CommandPlugins.java b/src/main/java/net/frankheijden/serverutils/commands/CommandPlugins.java new file mode 100644 index 0000000..8a41a54 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/commands/CommandPlugins.java @@ -0,0 +1,41 @@ +package net.frankheijden.serverutils.commands; + +import co.aikar.commands.BaseCommand; +import co.aikar.commands.annotation.*; +import net.frankheijden.serverutils.config.Messenger; +import net.frankheijden.serverutils.utils.ListBuilder; +import net.frankheijden.serverutils.utils.ListFormat; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; + +import java.util.Arrays; + +@CommandAlias("plugins|pl") +public class CommandPlugins extends BaseCommand { + + @Default + @CommandPermission("serverutils.plugins") + @Description("Shows the plugins of this server.") + public void onPlugins(CommandSender sender) { + sendPlugins(sender, plugin -> Messenger.getMessage("serverutils.plugins.format", "%plugin%", plugin.getName())); + } + + @Subcommand("-v") + @CommandPermission("serverutils.plugins.version") + @Description("Shows the plugins of this server with version.") + public void onPluginsWithVersion(CommandSender sender) { + sendPlugins(sender, plugin -> Messenger.getMessage("serverutils.plugins.format", "%plugin%", plugin.getName()) + + Messenger.getMessage("serverutils.plugins.version", "%version%", plugin.getDescription().getVersion())); + } + + private static void sendPlugins(CommandSender sender, ListFormat pluginFormat) { + Messenger.sendMessage(sender, "serverutils.plugins.header"); + sender.sendMessage(Messenger.color(ListBuilder.create(Arrays.asList(Bukkit.getPluginManager().getPlugins())) + .seperator(Messenger.getMessage("serverutils.plugins.seperator")) + .lastSeperator(Messenger.getMessage("serverutils.plugins.last_seperator")) + .format(pluginFormat) + .toString())); + Messenger.sendMessage(sender, "serverutils.plugins.footer"); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/commands/CommandServerUtils.java b/src/main/java/net/frankheijden/serverutils/commands/CommandServerUtils.java new file mode 100644 index 0000000..fe3274e --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/commands/CommandServerUtils.java @@ -0,0 +1,139 @@ +package net.frankheijden.serverutils.commands; + +import co.aikar.commands.BaseCommand; +import co.aikar.commands.annotation.*; +import net.frankheijden.serverutils.ServerUtils; +import net.frankheijden.serverutils.config.Messenger; +import net.frankheijden.serverutils.managers.PluginManager; +import net.frankheijden.serverutils.reflection.*; +import net.frankheijden.serverutils.utils.ForwardFilter; +import net.frankheijden.serverutils.utils.ReloadHandler; +import org.bukkit.Bukkit; +import org.bukkit.command.*; + +import java.util.*; + +import static net.frankheijden.serverutils.config.Messenger.sendMessage; + +@CommandAlias("serverutils|su") +public class CommandServerUtils extends BaseCommand { + + private static final Set ALIASES; + private static final Map supportedConfigs; + static { + ALIASES = new HashSet<>(); + ALIASES.add("serverutils"); + ALIASES.add("plugins"); + + supportedConfigs = new HashMap<>(); + supportedConfigs.put("bukkit", RCraftServer::reloadBukkitConfiguration); + supportedConfigs.put("commands.yml", RCraftServer::reloadCommandsConfiguration); + supportedConfigs.put("server-icon.png", RCraftServer::loadIcon); + supportedConfigs.put("banned-ips.json", RCraftServer::reloadIPBans); + supportedConfigs.put("banned-players.json", RCraftServer::reloadProfileBans); + } + + @Dependency + private ServerUtils plugin; + + public static Set getSupportedConfigs() { + return supportedConfigs.keySet(); + } + + @Default + @Subcommand("help") + @CommandPermission("serverutils.help") + @Description("Shows a help page with a few commands.") + public void onHelp(CommandSender sender) { + Messenger.sendMessage(sender, "serverutils.help.header"); + plugin.getCommandManager().getRegisteredRootCommands().stream() + .filter(c -> !ALIASES.contains(c.getCommandName().toLowerCase())) + .forEach(rootCommand -> { + Messenger.sendMessage(sender, "serverutils.help.format", + "%command%", rootCommand.getCommandName(), + "%subcommand%", "", + "%help%", rootCommand.getDescription()); + + rootCommand.getSubCommands().forEach((str, cmd) -> { + if (cmd.getPrefSubCommand().isEmpty()) return; + Messenger.sendMessage(sender, "serverutils.help.format", + "%command%", rootCommand.getCommandName(), + "%subcommand%", " " + cmd.getPrefSubCommand(), + "%help%", cmd.getHelpText()); + }); + }); + Messenger.sendMessage(sender, "serverutils.help.footer"); + } + + @Subcommand("reload") + @CommandPermission("serverutils.reload") + @Description("Reloads the ServerUtils plugin.") + public void onReload(CommandSender sender) { + plugin.reload(); + sendMessage(sender, "serverutils.success", + "%action%", "reload", + "%what%", "ServerUtils configurations"); + } + + @Subcommand("reloadconfig") + @CommandCompletion("@supportedConfigs") + @CommandPermission("serverutils.reloadconfig.commands") + @Description("Reloads individual Server configurations.") + public void onReloadCommands(CommandSender sender, String config) { + ReloadHandler handler = supportedConfigs.get(config); + if (handler == null) { + this.doHelp(sender); + return; + } + + String[] replacements = new String[]{ "%action%", "reload", "%what%", config }; + + ForwardFilter filter = new ForwardFilter(sender); + filter.start(Bukkit.getLogger()); + try { + handler.handle(); + filter.stop(Bukkit.getLogger()); + + String path = "serverutils." + (filter.hasWarnings() ? "warning" : "success"); + sendMessage(sender, path, replacements); + } catch (Exception ex) { + filter.stop(Bukkit.getLogger()); + + ex.printStackTrace(); + sendMessage(sender, "serverutils.error", replacements); + } + } + + @Subcommand("loadplugin") + @CommandCompletion("@pluginJars") + @CommandPermission("serverutils.loadplugin") + @Description("Loads the specified jar file as a plugin.") + public void onLoadPlugin(CommandSender sender, String jarFile) { + PluginManager.LoadResult loadResult = PluginManager.loadPlugin(jarFile); + if (!loadResult.isSuccess()) { + loadResult.getResult().sendTo(sender, "load", jarFile); + return; + } + + PluginManager.Result result = PluginManager.enablePlugin(loadResult.getPlugin()); + result.sendTo(sender, "load", jarFile); + } + + @Subcommand("unloadplugin") + @CommandCompletion("@plugins") + @CommandPermission("serverutils.unloadplugin") + @Description("Unloads the specified plugin.") + public void onUnloadPlugin(CommandSender sender, String pluginName) { + PluginManager.Result result = PluginManager.disablePlugin(pluginName); + result.sendTo(sender, "unload", pluginName); + } + + @Subcommand("reloadplugin") + @CommandCompletion("@plugins") + @CommandPermission("serverutils.reloadplugin") + @Description("Reloads a specified plugin.") + public void onReloadPlugin(CommandSender sender, String pluginName) { + PluginManager.Result result = PluginManager.reloadPlugin(pluginName); + result.sendTo(sender, "reload", pluginName); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/config/Messenger.java b/src/main/java/net/frankheijden/serverutils/config/Messenger.java new file mode 100644 index 0000000..0942362 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/config/Messenger.java @@ -0,0 +1,49 @@ +package net.frankheijden.serverutils.config; + +import net.frankheijden.serverutils.ServerUtils; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; + +public class Messenger { + + private static final ServerUtils plugin = ServerUtils.getInstance(); + private static Messenger instance; + private final YamlConfiguration messages; + + public Messenger(File file) { + instance = this; + messages = YamlConfiguration.loadConfiguration(file); + } + + public static String getMessage(String path, String... replacements) { + String message = instance.messages.getString(path); + if (message != null) { + return apply(message, replacements); + } else { + plugin.getLogger().severe("Missing locale in messages.yml at path '" + path + "'!"); + } + return null; + } + + public static String apply(String message, String... replacements) { + if (message == null || message.isEmpty()) return null; + for (int i = 0; i < replacements.length; i++, i++) { + message = message.replace(replacements[i], replacements[i + 1]); + } + return message; + } + + public static void sendMessage(CommandSender sender, String path, String... replacements) { + String message = getMessage(path, replacements); + if (message != null) { + sender.sendMessage(color(message)); + } + } + + public static String color(String str) { + return ChatColor.translateAlternateColorCodes('&', str); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/managers/PluginManager.java b/src/main/java/net/frankheijden/serverutils/managers/PluginManager.java new file mode 100644 index 0000000..d42b73d --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/managers/PluginManager.java @@ -0,0 +1,148 @@ +package net.frankheijden.serverutils.managers; + +import net.frankheijden.serverutils.ServerUtils; +import net.frankheijden.serverutils.config.Messenger; +import net.frankheijden.serverutils.reflection.*; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.InvalidPluginException; +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Map; + +public class PluginManager { + + public static LoadResult loadPlugin(String jarFile) { + return loadPlugin(new File(ServerUtils.getInstance().getDataFolder().getParent(), jarFile)); + } + + public static LoadResult loadPlugin(File file) { + if (!file.exists()) return new LoadResult(Result.NOT_EXISTS); + try { + return new LoadResult(Bukkit.getPluginManager().loadPlugin(file), Result.SUCCESS); + } catch (InvalidPluginException ex) { + if (ex.getCause() instanceof IllegalArgumentException) { + IllegalArgumentException e = (IllegalArgumentException) ex.getCause(); + if (e.getMessage().equalsIgnoreCase("Plugin already initialized!")) { + return new LoadResult(Result.ALREADY_ENABLED); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return new LoadResult(Result.ERROR); + } + + public static Result disablePlugin(String pluginName) { + return disablePlugin(Bukkit.getPluginManager().getPlugin(pluginName)); + } + + public static Result disablePlugin(Plugin plugin) { + if (plugin == null) return Result.NOT_EXISTS; + try { + Bukkit.getPluginManager().disablePlugin(plugin); + RSimplePluginManager.getPlugins(Bukkit.getPluginManager()).remove(plugin); + } catch (Exception ex) { + ex.printStackTrace(); + return Result.ERROR; + } + unregisterCommands(plugin); + return Result.SUCCESS; + } + + public static Result enablePlugin(Plugin plugin) { + if (plugin == null) return Result.NOT_EXISTS; + if (Bukkit.getPluginManager().isPluginEnabled(plugin.getName())) return Result.ALREADY_ENABLED; + Bukkit.getPluginManager().enablePlugin(plugin); + if (Bukkit.getPluginManager().isPluginEnabled(plugin.getName())) { + return Result.SUCCESS; + } + return Result.ERROR; + } + + public static Result reloadPlugin(String pluginName) { + Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName); + if (plugin == null) return Result.NOT_EXISTS; + return reloadPlugin(plugin); + } + + public static Result reloadPlugin(Plugin plugin) { + Result disableResult = disablePlugin(plugin); + if (disableResult != Result.SUCCESS) return disableResult; + + File pluginFile; + try { + pluginFile = RPlugin.getPluginFile(plugin); + } catch (InvocationTargetException | IllegalAccessException ex) { + ex.printStackTrace(); + return Result.ERROR; + } + + LoadResult loadResult = loadPlugin(pluginFile); + if (!loadResult.isSuccess()) return loadResult.getResult(); + return enablePlugin(loadResult.getPlugin()); + } + + public static void unregisterCommands(Plugin plugin) { + Map map; + try { + map = RCommandMap.getKnownCommands(RCraftServer.getCommandMap()); + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + + plugin.getDescription().getCommands().forEach((cmd, data) -> { + map.remove(cmd); + + @SuppressWarnings("unchecked") + List aliases = (List) data.get("aliases"); + if (aliases != null) { + aliases.forEach(map::remove); + } + }); + } + + public static class LoadResult { + private final Plugin plugin; + private final Result result; + + public LoadResult(Plugin plugin, Result result) { + this.plugin = plugin; + this.result = result; + } + + public LoadResult(Result result) { + this(null, result); + } + + public Result getResult() { + return result; + } + + public Plugin getPlugin() { + return plugin; + } + + public boolean isSuccess() { + return plugin != null && result == Result.SUCCESS; + } + } + + public enum Result { + NOT_EXISTS, + ALREADY_ENABLED, + ERROR, + SUCCESS; + + public void sendTo(CommandSender sender, String action, String what) { + Messenger.sendMessage(sender, "serverutils." + this.name().toLowerCase(), + "%action%", action, + "%what%", what); + } + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RCommandMap.java b/src/main/java/net/frankheijden/serverutils/reflection/RCommandMap.java new file mode 100644 index 0000000..ebe6188 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RCommandMap.java @@ -0,0 +1,31 @@ +package net.frankheijden.serverutils.reflection; + +import org.bukkit.command.Command; +import org.bukkit.command.SimpleCommandMap; + +import java.lang.reflect.*; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getDeclaredField; + +public class RCommandMap { + + private static Field knownCommands = null; + private static Method getKnownCommands = null; + static { + try { + try { + knownCommands = getDeclaredField(SimpleCommandMap.class, "knownCommands"); + } catch (NoSuchFieldException ignored) { + getKnownCommands = SimpleCommandMap.class.getDeclaredMethod("getKnownCommands"); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + @SuppressWarnings("unchecked") + public static Map getKnownCommands(SimpleCommandMap map) throws IllegalAccessException, InvocationTargetException { + return (Map) (knownCommands == null ? getKnownCommands.invoke(map) : knownCommands.get(map)); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RCraftServer.java b/src/main/java/net/frankheijden/serverutils/reflection/RCraftServer.java new file mode 100644 index 0000000..4d3581a --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RCraftServer.java @@ -0,0 +1,132 @@ +package net.frankheijden.serverutils.reflection; + +import org.bukkit.Bukkit; +import org.bukkit.Warning; +import org.bukkit.command.*; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.lang.reflect.*; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.*; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.FieldParam.fieldOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.MethodParam.methodOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.*; + +public class RCraftServer { + + private static Class craftServerClass; + private static Object craftServer; + private static File configFile; + private static File commandsConfigFile; + private static SimpleCommandMap commandMap; + + private static Map fields; + private static Map methods; + + static { + try { + craftServerClass = Class.forName(String.format("org.bukkit.craftbukkit.%s.CraftServer", ReflectionUtils.NMS)); + craftServer = craftServerClass.cast(Bukkit.getServer()); + + commandsConfigFile = (File) getDeclaredMethod(craftServerClass, "getCommandsConfigFile").invoke(craftServer); + configFile = (File) getDeclaredMethod(craftServerClass, "getConfigFile").invoke(craftServer); + commandMap = (SimpleCommandMap) getDeclaredField(craftServerClass, "commandMap").get(Bukkit.getServer()); + + fields = getAllFields(craftServerClass, + fieldOf("configuration", ALL_VERSIONS), + fieldOf("console", ALL_VERSIONS), + fieldOf("commandsConfiguration", ALL_VERSIONS), + fieldOf("overrideAllCommandBlockCommands", ALL_VERSIONS), + fieldOf("unrestrictedAdvancements", max(12)), + fieldOf("ignoreVanillaPermissions", min(13)), + fieldOf("monsterSpawn", ALL_VERSIONS), + fieldOf("animalSpawn", ALL_VERSIONS), + fieldOf("waterAnimalSpawn", ALL_VERSIONS), + fieldOf("ambientSpawn", ALL_VERSIONS), + fieldOf("warningState", ALL_VERSIONS), + fieldOf("minimumAPI", min(13)), + fieldOf("printSaveWarning", ALL_VERSIONS), + fieldOf("chunkGCPeriod", max(12)), + fieldOf("chunkGCLoadThresh", max(12)), + fieldOf("playerList", ALL_VERSIONS)); + methods = getAllMethods(craftServerClass, + methodOf("loadIcon", ALL_VERSIONS)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static Object getCraftServer() { + return craftServer; + } + + public static File getConfigFile() { + return configFile; + } + + public static File getOptionsFile(String option) throws IllegalAccessException, InvocationTargetException { + Object console = get(fields, craftServer, "console"); + Object options = get(RDedicatedServer.getFields(), console, "options"); + return (File) invoke(ROptionSet.getMethods(), options, "valueOf", option); + } + + public static File getCommandsConfigFile() { + return commandsConfigFile; + } + + public static SimpleCommandMap getCommandMap() { + return commandMap; + } + + public static void reloadBukkitConfiguration() throws Exception { + YamlConfiguration bukkit = YamlConfiguration.loadConfiguration(getConfigFile()); + set(fields, craftServer, "configuration", bukkit); + + Object console = get(fields, craftServer, "console"); + RDedicatedServer.reload(console); + + set(fields, craftServer, "monsterSpawn", bukkit.getInt("spawn-limits.monsters")); + set(fields, craftServer, "animalSpawn", bukkit.getInt("spawn-limits.animals")); + set(fields, craftServer, "waterAnimalSpawn", bukkit.getInt("spawn-limits.water-animals")); + set(fields, craftServer, "ambientSpawn", bukkit.getInt("spawn-limits.ambient")); + set(fields, craftServer, "warningState", Warning.WarningState.value(bukkit.getString("settings.deprecated-verbose"))); + set(fields, craftServer, "minimumAPI", bukkit.getString("settings.minimum-api")); + set(fields, craftServer, "printSaveWarning", false); + + set(RDedicatedServer.getFields(), console, "autosavePeriod", bukkit.getInt("ticks-per.autosave")); + + set(fields, craftServer, "chunkGCPeriod", bukkit.getInt("chunk-gc.period-in-ticks")); + set(fields, craftServer, "chunkGCLoadThresh", bukkit.getInt("chunk-gc.load-threshold")); + } + + public static void loadIcon() throws InvocationTargetException, IllegalAccessException { + invoke(methods, craftServer, "loadIcon"); + } + + public static void reloadCommandsConfiguration() throws IllegalAccessException, InvocationTargetException { + Map map = RCommandMap.getKnownCommands(commandMap); + Bukkit.getCommandAliases().keySet().forEach(map::remove); + + YamlConfiguration commands = YamlConfiguration.loadConfiguration(getCommandsConfigFile()); + set(fields, craftServer, "commandsConfiguration", commands); + set(fields, craftServer, "overrideAllCommandBlockCommands", commands.getStringList("command-block-overrides").contains("*")); + set(fields, craftServer, "ignoreVanillaPermissions", commands.getBoolean("ignore-vanilla-permissions")); + set(fields, craftServer, "unrestrictedAdvancements", commands.getBoolean("unrestricted-advancements")); + + commandMap.registerServerAliases(); + } + + public static void reloadIPBans() throws IllegalAccessException, InvocationTargetException { + Object playerList = get(fields, craftServer, "playerList"); + Object jsonList = invoke(RPlayerList.getMethods(), playerList, "getIPBans"); + RJsonList.load(jsonList); + } + + public static void reloadProfileBans() throws IllegalAccessException, InvocationTargetException { + Object playerList = get(fields, craftServer, "playerList"); + Object jsonList = invoke(RPlayerList.getMethods(), playerList, "getProfileBans"); + RJsonList.load(jsonList); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RDedicatedServer.java b/src/main/java/net/frankheijden/serverutils/reflection/RDedicatedServer.java new file mode 100644 index 0000000..dcf24bb --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RDedicatedServer.java @@ -0,0 +1,75 @@ +package net.frankheijden.serverutils.reflection; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.*; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.FieldParam.fieldOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.MethodParam.methodOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.*; + +public class RDedicatedServer { + + private static Class dedicatedServerClass; + private static Map fields; + private static Map methods; + + static { + try { + dedicatedServerClass = Class.forName(String.format("net.minecraft.server.%s.DedicatedServer", ReflectionUtils.NMS)); + + fields = getAllFields(dedicatedServerClass, + fieldOf("propertyManager", ALL_VERSIONS), + fieldOf("options", ALL_VERSIONS), + fieldOf("autosavePeriod", ALL_VERSIONS), + fieldOf("o", min(13))); + methods = getAllMethods(dedicatedServerClass, + methodOf("setSpawnAnimals", ALL_VERSIONS, boolean.class), + methodOf("getSpawnAnimals", ALL_VERSIONS), + methodOf("setPVP", ALL_VERSIONS, boolean.class), + methodOf("getPVP", ALL_VERSIONS), + methodOf("setAllowFlight", ALL_VERSIONS, boolean.class), + methodOf("getAllowFlight", ALL_VERSIONS), + methodOf("setMotd", ALL_VERSIONS, String.class), + methodOf("getMotd", ALL_VERSIONS), + methodOf("setSpawnNPCs", ALL_VERSIONS, boolean.class), + methodOf("setAllowFlight", ALL_VERSIONS, boolean.class), + methodOf("setResourcePack", ALL_VERSIONS, String.class, String.class), + methodOf("setForceGamemode", ALL_VERSIONS, boolean.class), + methodOf("n", min(13), boolean.class)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static Map getFields() { + return fields; + } + + public static void reload(Object console) throws Exception { + Object options = get(fields, console, "options"); + + if (MINOR >= 13) { + Object propertyManager = RDedicatedServerSettings.newInstance(options); + set(fields, console, "propertyManager", propertyManager); + Object config = invoke(RDedicatedServerSettings.getMethods(), propertyManager, "getProperties"); + invoke(methods, console, "setSpawnAnimals", get(RDedicatedServerProperties.getFields(), config, "spawnAnimals")); + invoke(methods, console, "setSpawnNPCs", get(RDedicatedServerProperties.getFields(), config, "spawnNpcs")); + invoke(methods, console, "setPVP", get(RDedicatedServerProperties.getFields(), config, "pvp")); + invoke(methods, console, "setAllowFlight", get(RDedicatedServerProperties.getFields(), config, "allowFlight")); + invoke(methods, console, "setResourcePack", get(RDedicatedServerProperties.getFields(), config, "resourcePack"), invoke(methods, console, "aZ")); + invoke(methods, console, "setMotd", get(RDedicatedServerProperties.getFields(), config, "motd")); + invoke(methods, console, "setForceGamemode", get(RDedicatedServerProperties.getFields(), config, "forceGamemode")); + invoke(methods, console, "n", get(RDedicatedServerProperties.getFields(), config, "enforceWhitelist")); + set(fields, console, "o", get(RDedicatedServerProperties.getFields(), config, "gamemode")); + } else { + Object config = RPropertyManager.newInstance(options); + set(fields, console, "propertyManager", config); + invoke(methods, console, "setSpawnAnimals", invoke(RPropertyManager.getMethods(), config, "getBoolean", "spawn-animals", invoke(methods, console, "getSpawnAnimals"))); + invoke(methods, console, "setPVP", invoke(RPropertyManager.getMethods(), config, "getBoolean", "pvp", invoke(methods, console, "getPVP"))); + invoke(methods, console, "setAllowFlight", invoke(RPropertyManager.getMethods(), config, "getBoolean", "allow-flight", invoke(methods, console, "getAllowFlight"))); + invoke(methods, console, "setMotd", invoke(RPropertyManager.getMethods(), config, "getString", "motd", invoke(methods, console, "getMotd"))); + } + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RDedicatedServerProperties.java b/src/main/java/net/frankheijden/serverutils/reflection/RDedicatedServerProperties.java new file mode 100644 index 0000000..93f370f --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RDedicatedServerProperties.java @@ -0,0 +1,36 @@ +package net.frankheijden.serverutils.reflection; + +import java.lang.reflect.Field; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.FieldParam.fieldOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllFields; + +public class RDedicatedServerProperties { + + private static Class dedicatedServerPropertiesClass; + private static Map fields; + + static { + try { + dedicatedServerPropertiesClass = Class.forName(String.format("net.minecraft.server.%s.DedicatedServerProperties", ReflectionUtils.NMS)); + fields = getAllFields(dedicatedServerPropertiesClass, + fieldOf("spawnAnimals", ALL_VERSIONS), + fieldOf("spawnNpcs", ALL_VERSIONS), + fieldOf("pvp", ALL_VERSIONS), + fieldOf("allowFlight", ALL_VERSIONS), + fieldOf("resourcePack", ALL_VERSIONS), + fieldOf("motd", ALL_VERSIONS), + fieldOf("forceGamemode", ALL_VERSIONS), + fieldOf("enforceWhitelist", ALL_VERSIONS), + fieldOf("gamemode", ALL_VERSIONS)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static Map getFields() { + return fields; + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RDedicatedServerSettings.java b/src/main/java/net/frankheijden/serverutils/reflection/RDedicatedServerSettings.java new file mode 100644 index 0000000..fe00903 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RDedicatedServerSettings.java @@ -0,0 +1,32 @@ +package net.frankheijden.serverutils.reflection; + +import java.lang.reflect.Method; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.MethodParam.methodOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllMethods; + +public class RDedicatedServerSettings { + + private static Class dedicatedServerSettingsClass; + private static Map methods; + + static { + try { + dedicatedServerSettingsClass = Class.forName(String.format("net.minecraft.server.%s.DedicatedServerSettings", ReflectionUtils.NMS)); + methods = getAllMethods(dedicatedServerSettingsClass, + methodOf("getProperties", ALL_VERSIONS)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static Object newInstance(Object options) throws Exception { + return dedicatedServerSettingsClass.getDeclaredConstructor(Class.forName("joptsimple.OptionSet")).newInstance(options); + } + + public static Map getMethods() { + return methods; + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RJsonList.java b/src/main/java/net/frankheijden/serverutils/reflection/RJsonList.java new file mode 100644 index 0000000..feb045d --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RJsonList.java @@ -0,0 +1,29 @@ +package net.frankheijden.serverutils.reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.MethodParam.methodOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllMethods; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.invoke; + +public class RJsonList { + + private static Class jsonListClass; + private static Map methods; + static { + try { + jsonListClass = Class.forName(String.format("net.minecraft.server.%s.JsonList", ReflectionUtils.NMS)); + methods = getAllMethods(jsonListClass, + methodOf("load", ALL_VERSIONS)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static void load(Object jsonList) throws InvocationTargetException, IllegalAccessException { + invoke(methods, jsonList, "load"); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/ROptionSet.java b/src/main/java/net/frankheijden/serverutils/reflection/ROptionSet.java new file mode 100644 index 0000000..ef0d326 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/ROptionSet.java @@ -0,0 +1,28 @@ +package net.frankheijden.serverutils.reflection; + +import java.lang.reflect.Method; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.MethodParam.methodOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllMethods; + +public class ROptionSet { + + private static Class optionSetClass; + private static Map methods; + + static { + try { + optionSetClass = Class.forName("joptsimple.OptionSet"); + methods = getAllMethods(optionSetClass, + methodOf("valueOf", ALL_VERSIONS, String.class)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static Map getMethods() { + return methods; + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RPlayerList.java b/src/main/java/net/frankheijden/serverutils/reflection/RPlayerList.java new file mode 100644 index 0000000..811afef --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RPlayerList.java @@ -0,0 +1,29 @@ +package net.frankheijden.serverutils.reflection; + +import java.lang.reflect.Method; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.MethodParam.methodOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllMethods; + +public class RPlayerList { + + private static Class playerListClass; + private static Map methods; + + static { + try { + playerListClass = Class.forName(String.format("net.minecraft.server.%s.PlayerList", ReflectionUtils.NMS)); + methods = getAllMethods(playerListClass, + methodOf("getIPBans", ALL_VERSIONS), + methodOf("getProfileBans", ALL_VERSIONS)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static Map getMethods() { + return methods; + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RPlugin.java b/src/main/java/net/frankheijden/serverutils/reflection/RPlugin.java new file mode 100644 index 0000000..025a292 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RPlugin.java @@ -0,0 +1,26 @@ +package net.frankheijden.serverutils.reflection; + +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getDeclaredMethod; + +public class RPlugin { + + private static Method getFile; + static { + try { + getFile = getDeclaredMethod(JavaPlugin.class, "getFile"); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static File getPluginFile(Plugin plugin) throws InvocationTargetException, IllegalAccessException { + return (File) getFile.invoke(plugin); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RPropertyManager.java b/src/main/java/net/frankheijden/serverutils/reflection/RPropertyManager.java new file mode 100644 index 0000000..d8ccd39 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RPropertyManager.java @@ -0,0 +1,33 @@ +package net.frankheijden.serverutils.reflection; + +import java.lang.reflect.Method; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.MethodParam.methodOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllMethods; + +public class RPropertyManager { + + private static Class propertyManagerClass; + private static Map methods; + + static { + try { + propertyManagerClass = Class.forName(String.format("net.minecraft.server.%s.PropertyManager", ReflectionUtils.NMS)); + methods = getAllMethods(propertyManagerClass, + methodOf("getBoolean", ALL_VERSIONS, String.class, boolean.class), + methodOf("getString", ALL_VERSIONS, String.class, String.class)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static Object newInstance(Object options) throws Exception { + return propertyManagerClass.getDeclaredConstructor(Class.forName("joptsimple.OptionSet")).newInstance(options); + } + + public static Map getMethods() { + return methods; + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RSimplePluginManager.java b/src/main/java/net/frankheijden/serverutils/reflection/RSimplePluginManager.java new file mode 100644 index 0000000..00130f4 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RSimplePluginManager.java @@ -0,0 +1,33 @@ +package net.frankheijden.serverutils.reflection; + +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.SimplePluginManager; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.FieldParam.fieldOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllFields; + +public class RSimplePluginManager { + + private static Class simplePluginManagerClass; + private static Map fields; + + static { + try { + simplePluginManagerClass = SimplePluginManager.class; + fields = getAllFields(simplePluginManagerClass, + fieldOf("plugins", ALL_VERSIONS)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + @SuppressWarnings("unchecked") + public static List getPlugins(Object manager) throws IllegalAccessException { + return (List) fields.get("plugins").get(manager); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/ReflectionUtils.java b/src/main/java/net/frankheijden/serverutils/reflection/ReflectionUtils.java new file mode 100644 index 0000000..7958afe --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/ReflectionUtils.java @@ -0,0 +1,161 @@ +package net.frankheijden.serverutils.reflection; + +import org.bukkit.Bukkit; + +import java.lang.reflect.*; +import java.util.*; + +public class ReflectionUtils { + + public static String NMS; + public static int MAJOR; + public static int MINOR; + public static int PATCH; + static { + String bukkitPackage = Bukkit.getServer().getClass().getPackage().getName(); + NMS = bukkitPackage.substring(bukkitPackage.lastIndexOf('.') + 1); + + String[] split = NMS.split("_"); + MAJOR = Integer.parseInt(split[0].substring(1)); + MINOR = Integer.parseInt(split[1]); + PATCH = Integer.parseInt(split[2].substring(1, 2)); + } + + public static Field getDeclaredField(Class clazz, String field) throws NoSuchFieldException { + Field f = clazz.getDeclaredField(field); + f.setAccessible(true); + return f; + } + + public static Field getField(Class clazz, String field) throws NoSuchFieldException { + Field f = clazz.getField(field); + f.setAccessible(true); + return f; + } + + public static Method getDeclaredMethod(Class clazz, String method, Class... params) throws NoSuchMethodException { + Method m = clazz.getDeclaredMethod(method, params); + m.setAccessible(true); + return m; + } + + public static Method getMethod(Class clazz, String method, Class... params) throws NoSuchMethodException { + Method m = clazz.getMethod(method, params); + m.setAccessible(true); + return m; + } + + public static Map getAllFields(Class clazz, FieldParam... fields) { + Map map = new HashMap<>(); + for (FieldParam fieldParam : fields) { + if (!fieldParam.versionParam.isCompatible()) continue; + try { + map.put(fieldParam.field, getDeclaredField(clazz, fieldParam.field)); + } catch (NoSuchFieldException ignored) { + try { + map.put(fieldParam.field, getField(clazz, fieldParam.field)); + } catch (NoSuchFieldException ex) { + ex.printStackTrace(); + } + } + } + return map; + } + + public static Map getAllMethods(Class clazz, MethodParam... methodParams) { + Map map = new HashMap<>(); + for (MethodParam methodParam : methodParams) { + if (!methodParam.versionParam.isCompatible()) continue; + try { + map.put(methodParam.method, getDeclaredMethod(clazz, methodParam.method, methodParam.params)); + } catch (NoSuchMethodException ignored) { + try { + map.put(methodParam.method, getMethod(clazz, methodParam.method, methodParam.params)); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + } + return map; + } + + public static Object invoke(Map map, Object instance, String methodName, Object... params) throws InvocationTargetException, IllegalAccessException { + Method method = map.get(methodName); + if (method == null) return null; + return method.invoke(instance, params); + } + + public static Object get(Map map, Object instance, String fieldName) throws IllegalAccessException { + Field field = map.get(fieldName); + if (field == null) return null; + return field.get(instance); + } + + public static void set(Map map, Object instance, String fieldName, Object value) throws IllegalAccessException { + Field field = map.get(fieldName); + if (field == null) return; + field.set(instance, value); + } + + public static class VersionParam { + public static VersionParam ALL_VERSIONS = new VersionParam(Integer.MIN_VALUE, Integer.MAX_VALUE); + + public int min; + public int max; + + private VersionParam(int min, int max) { + this.min = min; + this.max = max; + } + + public static VersionParam versionOf(int min, int max) { + return new VersionParam(min, max); + } + + public static VersionParam min(int min) { + return versionOf(min, Integer.MAX_VALUE); + } + + public static VersionParam max(int max) { + return versionOf(Integer.MIN_VALUE, max); + } + + public boolean isCompatible() { + return VersionParam.isCompatible(this); + } + + public static boolean isCompatible(VersionParam versionParam) { + return versionParam.min <= MINOR && MINOR <= versionParam.max; + } + } + + public static class FieldParam { + public String field; + public VersionParam versionParam; + + private FieldParam(String field, VersionParam versionParam) { + this.field = field; + this.versionParam = versionParam; + } + + public static FieldParam fieldOf(String field, VersionParam versionParam) { + return new FieldParam(field, versionParam); + } + } + + public static class MethodParam { + public String method; + public VersionParam versionParam; + public Class[] params; + + private MethodParam(String method, VersionParam versionParam, Class... params) { + this.method = method; + this.versionParam = versionParam; + this.params = params; + } + + public static MethodParam methodOf(String method, VersionParam versionParam, Class... params) { + return new MethodParam(method, versionParam, params); + } + } +} diff --git a/src/main/java/net/frankheijden/serverutils/utils/ForwardFilter.java b/src/main/java/net/frankheijden/serverutils/utils/ForwardFilter.java new file mode 100644 index 0000000..a1caa0b --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/utils/ForwardFilter.java @@ -0,0 +1,46 @@ +package net.frankheijden.serverutils.utils; + +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +import java.util.logging.*; + +public class ForwardFilter extends PredicateFilter { + + private boolean warnings; + + public ForwardFilter(CommandSender sender) { + this.warnings = false; + + setPredicate(rec -> { + ChatColor color = getColor(rec.getLevel()); + if (color != ChatColor.GREEN) warnings = true; + sender.sendMessage(color + format(rec)); + return true; + }); + } + + public boolean hasWarnings() { + return warnings; + } + + private static ChatColor getColor(Level level) { + if (Level.SEVERE.equals(level)) { + return ChatColor.RED; + } else if (Level.WARNING.equals(level)) { + return ChatColor.GOLD; + } + return ChatColor.GREEN; + } + + private static String format(LogRecord record) { + String msg = record.getMessage(); + + Object[] params = record.getParameters(); + if (params == null) return msg; + for (int i = 0; i < params.length; i++) { + msg = msg.replace("{" + i + "}", String.valueOf(params[i])); + } + return msg; + } +} diff --git a/src/main/java/net/frankheijden/serverutils/utils/ListBuilder.java b/src/main/java/net/frankheijden/serverutils/utils/ListBuilder.java new file mode 100644 index 0000000..6e830af --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/utils/ListBuilder.java @@ -0,0 +1,55 @@ +package net.frankheijden.serverutils.utils; + +import java.util.Collection; + +public class ListBuilder { + + private final Collection collection; + private ListFormat formatter; + private String seperator; + private String lastSeperator; + + private ListBuilder(Collection collection) { + this.collection = collection; + } + + public static ListBuilder create(Collection collection) { + return new ListBuilder<>(collection); + } + + public ListBuilder format(ListFormat formatter) { + this.formatter = formatter; + return this; + } + + public ListBuilder seperator(String seperator) { + this.seperator = seperator; + return this; + } + + public ListBuilder lastSeperator(String lastSeperator) { + this.lastSeperator = lastSeperator; + return this; + } + + @Override + public String toString() { + if (collection.size() == 1) { + return formatter.format(collection.iterator().next()); + } else { + StringBuilder sb = new StringBuilder(); + + int i = 1; + for (T t : collection) { + sb.append(formatter.format(t)); + if (i == collection.size() - 1) { + sb.append(lastSeperator); + } else if (i != collection.size()) { + sb.append(seperator); + } + i++; + } + return sb.toString(); + } + } +} diff --git a/src/main/java/net/frankheijden/serverutils/utils/ListFormat.java b/src/main/java/net/frankheijden/serverutils/utils/ListFormat.java new file mode 100644 index 0000000..aa4e6bb --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/utils/ListFormat.java @@ -0,0 +1,7 @@ +package net.frankheijden.serverutils.utils; + +public interface ListFormat { + + String format(T t); + +} diff --git a/src/main/java/net/frankheijden/serverutils/utils/PredicateFilter.java b/src/main/java/net/frankheijden/serverutils/utils/PredicateFilter.java new file mode 100644 index 0000000..6e26c5f --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/utils/PredicateFilter.java @@ -0,0 +1,28 @@ +package net.frankheijden.serverutils.utils; + +import java.util.function.Predicate; +import java.util.logging.*; + +public class PredicateFilter implements Filter { + + private Predicate predicate; + private Filter filter; + + public void setPredicate(Predicate predicate) { + this.predicate = predicate; + } + + public void start(Logger logger) { + this.filter = logger.getFilter(); + logger.setFilter(this); + } + + public void stop(Logger logger) { + logger.setFilter(filter); + } + + @Override + public boolean isLoggable(LogRecord record) { + return predicate.test(record); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/utils/ReloadHandler.java b/src/main/java/net/frankheijden/serverutils/utils/ReloadHandler.java new file mode 100644 index 0000000..80e88ef --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/utils/ReloadHandler.java @@ -0,0 +1,7 @@ +package net.frankheijden.serverutils.utils; + +public interface ReloadHandler { + + void handle() throws Exception; + +} diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml new file mode 100644 index 0000000..106b200 --- /dev/null +++ b/src/main/resources/messages.yml @@ -0,0 +1,17 @@ +serverutils: + success: "&3Successfully %action%ed &b%what%&3!" + warning: "&3Successfully %action%ed &b%what%&3, but with warnings." + error: "&cAn error occurred while %action%ing &4%what%&c, please check the console!" + not_exists: "&cAn error occurred while %action%ing &4%what%&c, plugin does not exist!" + already_enabled: "&cAn error occurred while %action%ing &4%what%&c, plugin is already enabled!" + help: + header: "&8&m-------------=&r&8[ &b&lServerUtils Help&r &8]&m=---------------" + format: "&8/&3%command%&b%subcommand% &f(&7%help%&f)" + footer: "&8&m-------------------------------------------------" + plugins: + header: "&8&m------------=&r&8[ &b&lServerUtils Plugins&r &8]&m=-------------" + format: "&3%plugin%" + seperator: "&b, " + last_seperator: " &band " + version: " &8(&a%version%&8)" + footer: "&8&m-------------------------------------------------" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..9b91d1b --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,12 @@ +name: ServerUtils +main: net.frankheijden.serverutils.ServerUtils +version: ${version} +author: FrankHeijden +api-version: '1.13' + +commands: + serverutils: + usage: "/" + aliases: + - "su" +