Merge pull request #22 from FrankHeijden/feature/velocity
Initial Velocity support
This commit is contained in:
commit
f21306021d
39 changed files with 1748 additions and 50 deletions
|
|
@ -5,7 +5,7 @@ archivesBaseName = rootProject.name + '-Bukkit'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'co.aikar:acf-paper:0.5.0-SNAPSHOT'
|
implementation 'co.aikar:acf-paper:0.5.0-SNAPSHOT'
|
||||||
implementation 'org.bstats:bstats-bukkit:1.8'
|
implementation 'org.bstats:bstats-bukkit:2.2.1'
|
||||||
implementation project(":Common")
|
implementation project(":Common")
|
||||||
compileOnly 'com.destroystokyo.paper:paper-api:1.16.4-R0.1-SNAPSHOT'
|
compileOnly 'com.destroystokyo.paper:paper-api:1.16.4-R0.1-SNAPSHOT'
|
||||||
}
|
}
|
||||||
|
|
@ -18,7 +18,7 @@ processResources {
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
relocate 'org.bstats.bukkit', dependencyDir + '.bstats'
|
relocate 'org.bstats', dependencyDir + '.bstats'
|
||||||
relocate 'co.aikar.commands', dependencyDir + '.acf'
|
relocate 'co.aikar.commands', dependencyDir + '.acf'
|
||||||
relocate 'co.aikar.locales', dependencyDir + '.locales'
|
relocate 'co.aikar.locales', dependencyDir + '.locales'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.frankheijden.serverutils.bukkit.entities;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import net.frankheijden.serverutils.bukkit.ServerUtils;
|
import net.frankheijden.serverutils.bukkit.ServerUtils;
|
||||||
import net.frankheijden.serverutils.common.config.YamlConfig;
|
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||||
import net.frankheijden.serverutils.common.providers.ResourceProvider;
|
import net.frankheijden.serverutils.common.providers.ResourceProvider;
|
||||||
|
|
||||||
public class BukkitResourceProvider implements ResourceProvider {
|
public class BukkitResourceProvider implements ResourceProvider {
|
||||||
|
|
@ -20,12 +20,12 @@ public class BukkitResourceProvider implements ResourceProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public YamlConfig load(InputStream is) {
|
public ServerUtilsConfig load(InputStream is) {
|
||||||
return new BukkitYamlConfig(is);
|
return new BukkitYamlConfig(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public YamlConfig load(File file) {
|
public ServerUtilsConfig load(File file) {
|
||||||
return new BukkitYamlConfig(file);
|
return new BukkitYamlConfig(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import net.frankheijden.serverutils.common.config.YamlConfig;
|
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||||
import org.bukkit.configuration.MemorySection;
|
import org.bukkit.configuration.MemorySection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
public class BukkitYamlConfig implements YamlConfig {
|
public class BukkitYamlConfig implements ServerUtilsConfig {
|
||||||
|
|
||||||
private final MemorySection config;
|
private final MemorySection config;
|
||||||
private File file = null;
|
private File file = null;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ repositories {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'co.aikar:acf-bungee:0.5.0-SNAPSHOT'
|
implementation 'co.aikar:acf-bungee:0.5.0-SNAPSHOT'
|
||||||
implementation 'org.bstats:bstats-bungeecord:1.8'
|
implementation 'org.bstats:bstats-bungeecord:2.2.1'
|
||||||
implementation project(":Common")
|
implementation project(":Common")
|
||||||
compileOnly 'net.md-5:bungeecord-api:1.16-R0.5-SNAPSHOT'
|
compileOnly 'net.md-5:bungeecord-api:1.16-R0.5-SNAPSHOT'
|
||||||
}
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ processResources {
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
relocate 'org.bstats.bungeecord', dependencyDir + '.bstats'
|
relocate 'org.bstats', dependencyDir + '.bstats'
|
||||||
relocate 'co.aikar.commands', dependencyDir + '.acf'
|
relocate 'co.aikar.commands', dependencyDir + '.acf'
|
||||||
relocate 'co.aikar.locales', dependencyDir + '.locales'
|
relocate 'co.aikar.locales', dependencyDir + '.locales'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ package net.frankheijden.serverutils.bungee.commands;
|
||||||
import static net.frankheijden.serverutils.common.config.Messenger.sendMessage;
|
import static net.frankheijden.serverutils.common.config.Messenger.sendMessage;
|
||||||
|
|
||||||
import co.aikar.commands.BaseCommand;
|
import co.aikar.commands.BaseCommand;
|
||||||
|
import co.aikar.commands.RegisteredCommand;
|
||||||
|
import co.aikar.commands.RootCommand;
|
||||||
import co.aikar.commands.annotation.CommandAlias;
|
import co.aikar.commands.annotation.CommandAlias;
|
||||||
import co.aikar.commands.annotation.CommandCompletion;
|
import co.aikar.commands.annotation.CommandCompletion;
|
||||||
import co.aikar.commands.annotation.CommandPermission;
|
import co.aikar.commands.annotation.CommandPermission;
|
||||||
|
|
@ -61,16 +63,21 @@ public class CommandServerUtils extends BaseCommand {
|
||||||
|
|
||||||
FormatBuilder builder = FormatBuilder.create(Messenger.getMessage("serverutils.help.format"))
|
FormatBuilder builder = FormatBuilder.create(Messenger.getMessage("serverutils.help.format"))
|
||||||
.orderedKeys("%command%", "%subcommand%", "%help%");
|
.orderedKeys("%command%", "%subcommand%", "%help%");
|
||||||
plugin.getCommandManager().getRegisteredRootCommands().stream()
|
|
||||||
.filter(c -> !ALIASES.contains(c.getCommandName().toLowerCase()))
|
|
||||||
.forEach(rootCommand -> {
|
|
||||||
builder.add(rootCommand.getCommandName(), "", rootCommand.getDescription());
|
|
||||||
|
|
||||||
rootCommand.getSubCommands().forEach((str, cmd) -> {
|
Set<String> rootCommands = new HashSet<>();
|
||||||
if (cmd.getPrefSubCommand().isEmpty()) return;
|
for (RootCommand root : plugin.getCommandManager().getRegisteredRootCommands()) {
|
||||||
builder.add(rootCommand.getCommandName(), " " + cmd.getPrefSubCommand(), cmd.getHelpText());
|
String rootName = root.getDefCommand().getName();
|
||||||
});
|
if (!rootCommands.add(rootName)) continue;
|
||||||
});
|
builder.add(rootName, "", root.getDescription());
|
||||||
|
|
||||||
|
Set<String> subCommands = new HashSet<>();
|
||||||
|
for (RegisteredCommand<?> sub : root.getSubCommands().values()) {
|
||||||
|
String name = sub.getPrefSubCommand().toLowerCase();
|
||||||
|
if (name.isEmpty()) continue;
|
||||||
|
if (!subCommands.add(name)) continue;
|
||||||
|
builder.add(rootName, " " + name, sub.getHelpText());
|
||||||
|
}
|
||||||
|
}
|
||||||
builder.sendTo(sender);
|
builder.sendTo(sender);
|
||||||
Messenger.sendMessage(sender, "serverutils.help.footer");
|
Messenger.sendMessage(sender, "serverutils.help.footer");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import net.frankheijden.serverutils.bungee.ServerUtils;
|
import net.frankheijden.serverutils.bungee.ServerUtils;
|
||||||
import net.frankheijden.serverutils.common.config.YamlConfig;
|
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||||
import net.frankheijden.serverutils.common.providers.ResourceProvider;
|
import net.frankheijden.serverutils.common.providers.ResourceProvider;
|
||||||
|
|
||||||
public class BungeeResourceProvider implements ResourceProvider {
|
public class BungeeResourceProvider implements ResourceProvider {
|
||||||
|
|
@ -21,12 +21,12 @@ public class BungeeResourceProvider implements ResourceProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public YamlConfig load(InputStream is) {
|
public ServerUtilsConfig load(InputStream is) {
|
||||||
return new BungeeYamlConfig(is);
|
return new BungeeYamlConfig(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public YamlConfig load(File file) {
|
public ServerUtilsConfig load(File file) {
|
||||||
try {
|
try {
|
||||||
return new BungeeYamlConfig(file);
|
return new BungeeYamlConfig(file);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@ import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import net.frankheijden.serverutils.common.config.YamlConfig;
|
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||||
import net.md_5.bungee.config.Configuration;
|
import net.md_5.bungee.config.Configuration;
|
||||||
import net.md_5.bungee.config.ConfigurationProvider;
|
import net.md_5.bungee.config.ConfigurationProvider;
|
||||||
import net.md_5.bungee.config.YamlConfiguration;
|
import net.md_5.bungee.config.YamlConfiguration;
|
||||||
|
|
||||||
public class BungeeYamlConfig implements YamlConfig {
|
public class BungeeYamlConfig implements ServerUtilsConfig {
|
||||||
|
|
||||||
private static final ConfigurationProvider provider = ConfigurationProvider.getProvider(YamlConfiguration.class);
|
private static final ConfigurationProvider provider = ConfigurationProvider.getProvider(YamlConfiguration.class);
|
||||||
private final Configuration config;
|
private final Configuration config;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.frankheijden.serverutils.common.config;
|
||||||
/**
|
/**
|
||||||
* The general common config class.
|
* The general common config class.
|
||||||
*/
|
*/
|
||||||
public class Config extends YamlResource {
|
public class Config extends ServerUtilsResource {
|
||||||
|
|
||||||
private static Config instance;
|
private static Config instance;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import net.frankheijden.serverutils.common.utils.StringUtils;
|
||||||
/**
|
/**
|
||||||
* The general common messenger class.
|
* The general common messenger class.
|
||||||
*/
|
*/
|
||||||
public class Messenger extends YamlResource {
|
public class Messenger extends ServerUtilsResource {
|
||||||
|
|
||||||
private static Messenger instance;
|
private static Messenger instance;
|
||||||
private static final ServerUtilsPlugin plugin = ServerUtilsApp.getPlugin();
|
private static final ServerUtilsPlugin plugin = ServerUtilsApp.getPlugin();
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrap for a Yaml Configuration file.
|
* A wrap for a Configuration file.
|
||||||
*/
|
*/
|
||||||
public interface YamlConfig {
|
public interface ServerUtilsConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the value at a given path.
|
* Retrieves the value at a given path.
|
||||||
|
|
@ -69,7 +69,7 @@ public interface YamlConfig {
|
||||||
* @param def The defaults to copy values over from.
|
* @param def The defaults to copy values over from.
|
||||||
* @param conf The configuration to copy the defaults to.
|
* @param conf The configuration to copy the defaults to.
|
||||||
*/
|
*/
|
||||||
static void addDefaults(YamlConfig def, YamlConfig conf) {
|
static void addDefaults(ServerUtilsConfig def, ServerUtilsConfig conf) {
|
||||||
addDefaults(def, conf, "");
|
addDefaults(def, conf, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,13 +79,13 @@ public interface YamlConfig {
|
||||||
* @param conf The configuration to copy the defaults to.
|
* @param conf The configuration to copy the defaults to.
|
||||||
* @param root The current root path of the iteration.
|
* @param root The current root path of the iteration.
|
||||||
*/
|
*/
|
||||||
static void addDefaults(YamlConfig def, YamlConfig conf, String root) {
|
static void addDefaults(ServerUtilsConfig def, ServerUtilsConfig conf, String root) {
|
||||||
if (def == null) return;
|
if (def == null) return;
|
||||||
for (String key : def.getKeys()) {
|
for (String key : def.getKeys()) {
|
||||||
String newKey = (root.isEmpty() ? "" : root + ".") + key;
|
String newKey = (root.isEmpty() ? "" : root + ".") + key;
|
||||||
Object value = def.get(key);
|
Object value = def.get(key);
|
||||||
if (value instanceof YamlConfig) {
|
if (value instanceof ServerUtilsConfig) {
|
||||||
addDefaults((YamlConfig) value, conf, newKey);
|
addDefaults((ServerUtilsConfig) value, conf, newKey);
|
||||||
} else if (conf.get(newKey) == null) {
|
} else if (conf.get(newKey) == null) {
|
||||||
conf.set(newKey, value);
|
conf.set(newKey, value);
|
||||||
}
|
}
|
||||||
|
|
@ -95,22 +95,22 @@ public interface YamlConfig {
|
||||||
/**
|
/**
|
||||||
* Removes unused keys from the configuration.
|
* Removes unused keys from the configuration.
|
||||||
*/
|
*/
|
||||||
static void removeOldKeys(YamlConfig def, YamlConfig conf) {
|
static void removeOldKeys(ServerUtilsConfig def, ServerUtilsConfig conf) {
|
||||||
removeOldKeys(def, conf, "");
|
removeOldKeys(def, conf, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes unused keys from the configuration, starting from the root node.
|
* Removes unused keys from the configuration, starting from the root node.
|
||||||
*/
|
*/
|
||||||
static void removeOldKeys(YamlConfig def, YamlConfig conf, String root) {
|
static void removeOldKeys(ServerUtilsConfig def, ServerUtilsConfig conf, String root) {
|
||||||
if (def == null) return;
|
if (def == null) return;
|
||||||
for (String key : conf.getKeys()) {
|
for (String key : conf.getKeys()) {
|
||||||
String defKey = (root.isEmpty() ? "" : root + ".") + key;
|
String defKey = (root.isEmpty() ? "" : root + ".") + key;
|
||||||
Object value = conf.get(key);
|
Object value = conf.get(key);
|
||||||
if (def.get(defKey) == null) {
|
if (def.get(defKey) == null) {
|
||||||
conf.set(key, null);
|
conf.set(key, null);
|
||||||
} else if (value instanceof YamlConfig) {
|
} else if (value instanceof ServerUtilsConfig) {
|
||||||
removeOldKeys(def, (YamlConfig) value, defKey);
|
removeOldKeys(def, (ServerUtilsConfig) value, defKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -121,9 +121,9 @@ public interface YamlConfig {
|
||||||
* @param conf The Configuration where the defaults will be applied to.
|
* @param conf The Configuration where the defaults will be applied to.
|
||||||
* @return The loaded Configuration of the file with defaults.
|
* @return The loaded Configuration of the file with defaults.
|
||||||
*/
|
*/
|
||||||
static YamlConfig init(YamlConfig def, YamlConfig conf) {
|
static ServerUtilsConfig init(ServerUtilsConfig def, ServerUtilsConfig conf) {
|
||||||
YamlConfig.addDefaults(def, conf);
|
ServerUtilsConfig.addDefaults(def, conf);
|
||||||
YamlConfig.removeOldKeys(def, conf);
|
ServerUtilsConfig.removeOldKeys(def, conf);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
conf.save();
|
conf.save();
|
||||||
|
|
@ -7,13 +7,13 @@ import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||||
import net.frankheijden.serverutils.common.providers.ResourceProvider;
|
import net.frankheijden.serverutils.common.providers.ResourceProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class which provides functionality for loading and setting defaults of Yaml Configurations.
|
* A class which provides functionality for loading and setting defaults of Configurations.
|
||||||
*/
|
*/
|
||||||
public class YamlResource {
|
public class ServerUtilsResource {
|
||||||
|
|
||||||
private static final ServerUtilsPlugin plugin = ServerUtilsApp.getPlugin();
|
private static final ServerUtilsPlugin plugin = ServerUtilsApp.getPlugin();
|
||||||
|
|
||||||
private final YamlConfig config;
|
private final ServerUtilsConfig config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new YamlResource instance.
|
* Creates a new YamlResource instance.
|
||||||
|
|
@ -21,18 +21,18 @@ public class YamlResource {
|
||||||
* @param fileName The destination file.
|
* @param fileName The destination file.
|
||||||
* @param resource The resource from the jar file.
|
* @param resource The resource from the jar file.
|
||||||
*/
|
*/
|
||||||
public YamlResource(String fileName, String resource) {
|
public ServerUtilsResource(String fileName, String resource) {
|
||||||
ResourceProvider provider = plugin.getResourceProvider();
|
ResourceProvider provider = plugin.getResourceProvider();
|
||||||
InputStream is = provider.getResource(resource);
|
InputStream is = provider.getResource(resource);
|
||||||
File file = plugin.copyResourceIfNotExists(fileName, resource);
|
File file = plugin.copyResourceIfNotExists(fileName, resource);
|
||||||
config = YamlConfig.init(provider.load(is), provider.load(file));
|
config = ServerUtilsConfig.init(provider.load(is), provider.load(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the YamlConfig of this resource.
|
* Retrieves the YamlConfig of this resource.
|
||||||
* @return The YamlConfig.
|
* @return The YamlConfig.
|
||||||
*/
|
*/
|
||||||
public YamlConfig getConfig() {
|
public ServerUtilsConfig getConfig() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,13 +2,13 @@ package net.frankheijden.serverutils.common.providers;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import net.frankheijden.serverutils.common.config.YamlConfig;
|
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||||
|
|
||||||
public interface ResourceProvider {
|
public interface ResourceProvider {
|
||||||
|
|
||||||
InputStream getResource(String resource);
|
InputStream getResource(String resource);
|
||||||
|
|
||||||
YamlConfig load(InputStream is);
|
ServerUtilsConfig load(InputStream is);
|
||||||
|
|
||||||
YamlConfig load(File file);
|
ServerUtilsConfig load(File file);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import java.util.logging.Level;
|
||||||
import net.frankheijden.serverutils.common.ServerUtilsApp;
|
import net.frankheijden.serverutils.common.ServerUtilsApp;
|
||||||
import net.frankheijden.serverutils.common.config.Config;
|
import net.frankheijden.serverutils.common.config.Config;
|
||||||
import net.frankheijden.serverutils.common.config.Messenger;
|
import net.frankheijden.serverutils.common.config.Messenger;
|
||||||
import net.frankheijden.serverutils.common.config.YamlConfig;
|
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||||
import net.frankheijden.serverutils.common.entities.LoadResult;
|
import net.frankheijden.serverutils.common.entities.LoadResult;
|
||||||
import net.frankheijden.serverutils.common.entities.Result;
|
import net.frankheijden.serverutils.common.entities.Result;
|
||||||
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||||
|
|
@ -27,7 +27,7 @@ import net.frankheijden.serverutilsupdater.common.Updater;
|
||||||
public class UpdateCheckerTask implements Runnable {
|
public class UpdateCheckerTask implements Runnable {
|
||||||
|
|
||||||
private static final ServerUtilsPlugin plugin = ServerUtilsApp.getPlugin();
|
private static final ServerUtilsPlugin plugin = ServerUtilsApp.getPlugin();
|
||||||
private static final YamlConfig config = Config.getInstance().getConfig();
|
private static final ServerUtilsConfig config = Config.getInstance().getConfig();
|
||||||
|
|
||||||
private final ServerCommandSender sender;
|
private final ServerCommandSender sender;
|
||||||
private final boolean download;
|
private final boolean download;
|
||||||
|
|
|
||||||
34
Velocity/build.gradle
Normal file
34
Velocity/build.gradle
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
plugins {
|
||||||
|
id 'net.kyori.blossom' version '1.3.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
group = rootProject.group + '.velocity'
|
||||||
|
String dependencyDir = group + '.dependencies'
|
||||||
|
version = rootProject.version
|
||||||
|
archivesBaseName = rootProject.name + '-Velocity'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven { url 'https://nexus.velocitypowered.com/repository/maven-public/' }
|
||||||
|
maven { url 'https://libraries.minecraft.net' }
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'com.github.AlexProgrammerDE.commands:acf-velocity:b0792607db'
|
||||||
|
implementation 'org.bstats:bstats-velocity:2.2.1'
|
||||||
|
implementation project(":Common")
|
||||||
|
compileOnly 'com.velocitypowered:velocity-api:3.0.0'
|
||||||
|
compileOnly 'com.velocitypowered:velocity-brigadier:1.0.0-SNAPSHOT'
|
||||||
|
compileOnly 'com.electronwill.night-config:toml:3.6.3'
|
||||||
|
annotationProcessor 'com.velocitypowered:velocity-api:3.0.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
relocate 'org.bstats', dependencyDir + '.bstats'
|
||||||
|
relocate 'co.aikar.commands', dependencyDir + '.acf'
|
||||||
|
relocate 'co.aikar.locales', dependencyDir + '.locales'
|
||||||
|
}
|
||||||
|
|
||||||
|
blossom {
|
||||||
|
replaceTokenIn('src/main/java/net/frankheijden/serverutils/velocity/ServerUtils.java')
|
||||||
|
replaceToken '${version}', version
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
package net.frankheijden.serverutils.velocity;
|
||||||
|
|
||||||
|
import co.aikar.commands.CommandCompletions;
|
||||||
|
import co.aikar.commands.VelocityCommandCompletionContext;
|
||||||
|
import co.aikar.commands.VelocityCommandManager;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||||
|
import com.velocitypowered.api.plugin.Plugin;
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import net.frankheijden.serverutils.common.ServerUtilsApp;
|
||||||
|
import net.frankheijden.serverutils.common.config.Config;
|
||||||
|
import net.frankheijden.serverutils.common.config.Messenger;
|
||||||
|
import net.frankheijden.serverutils.velocity.commands.CommandPlugins;
|
||||||
|
import net.frankheijden.serverutils.velocity.commands.CommandServerUtils;
|
||||||
|
import net.frankheijden.serverutils.velocity.entities.VelocityPlugin;
|
||||||
|
import net.frankheijden.serverutils.velocity.managers.VelocityPluginCommandManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.managers.VelocityPluginManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RVelocityCommandManager;
|
||||||
|
import org.bstats.velocity.Metrics;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
@Plugin(
|
||||||
|
id = "serverutils",
|
||||||
|
name = "ServerUtils",
|
||||||
|
version = "${version}",
|
||||||
|
description = "A server utility",
|
||||||
|
url = "https://github.com/FrankHeijden/ServerUtils",
|
||||||
|
authors = "FrankHeijden"
|
||||||
|
)
|
||||||
|
public class ServerUtils {
|
||||||
|
|
||||||
|
private static ServerUtils instance;
|
||||||
|
private static final String CONFIG_RESOURCE = "velocity-config.toml";
|
||||||
|
private static final String MESSAGES_RESOURCE = "velocity-messages.toml";
|
||||||
|
private static final String PLUGIN_COMMANDS_CACHE = ".pluginCommandsCache.json";
|
||||||
|
|
||||||
|
private VelocityPlugin plugin;
|
||||||
|
private VelocityCommandManager commandManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ProxyServer proxy;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Logger logger;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@DataDirectory
|
||||||
|
private Path dataDirectory;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Metrics.Factory metricsFactory;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@Named("serverutils")
|
||||||
|
private PluginContainer pluginContainer;
|
||||||
|
|
||||||
|
private final VelocityPluginCommandManager pluginCommandManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises ServerUtils.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
public ServerUtils(ProxyServer proxy, @DataDirectory Path dataDirectory) {
|
||||||
|
try {
|
||||||
|
this.pluginCommandManager = VelocityPluginCommandManager.load(dataDirectory.resolve(PLUGIN_COMMANDS_CACHE));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
RVelocityCommandManager.proxyRegistrars(
|
||||||
|
proxy,
|
||||||
|
getClass().getClassLoader(),
|
||||||
|
(container, meta) -> pluginCommandManager.getPluginCommands().putAll(
|
||||||
|
container.getDescription().getId(),
|
||||||
|
meta.getAliases()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises and enables ServerUtils.
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void onEnable(ProxyInitializeEvent event) {
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
this.plugin = new VelocityPlugin(this);
|
||||||
|
ServerUtilsApp.init(this, plugin);
|
||||||
|
|
||||||
|
metricsFactory.make(this, ServerUtilsApp.BSTATS_METRICS_ID);
|
||||||
|
|
||||||
|
this.commandManager = new VelocityCommandManager(proxy, this);
|
||||||
|
commandManager.registerCommand(new CommandPlugins());
|
||||||
|
commandManager.registerCommand(new CommandServerUtils(this));
|
||||||
|
|
||||||
|
VelocityPluginManager manager = plugin.getPluginManager();
|
||||||
|
CommandCompletions<VelocityCommandCompletionContext> completions = commandManager.getCommandCompletions();
|
||||||
|
completions.registerAsyncCompletion("plugins", context -> manager.getPluginNames());
|
||||||
|
completions.registerAsyncCompletion("pluginJars", context -> manager.getPluginFileNames());
|
||||||
|
completions.registerAsyncCompletion("commands", context -> manager.getCommands());
|
||||||
|
|
||||||
|
reload();
|
||||||
|
plugin.enable();
|
||||||
|
|
||||||
|
ServerUtilsApp.tryCheckForUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* De-initialises and disables ServerUtils.
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void onDisable(ProxyShutdownEvent event) {
|
||||||
|
try {
|
||||||
|
pluginCommandManager.save();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerUtils getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyServer getProxy() {
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Logger getLogger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getDataDirectory() {
|
||||||
|
return dataDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VelocityCommandManager getCommandManager() {
|
||||||
|
return commandManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VelocityPlugin getPlugin() {
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VelocityPluginCommandManager getPluginCommandManager() {
|
||||||
|
return pluginCommandManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reload() {
|
||||||
|
new Config("config.toml", CONFIG_RESOURCE);
|
||||||
|
new Messenger("messages.toml", MESSAGES_RESOURCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.commands;
|
||||||
|
|
||||||
|
import co.aikar.commands.BaseCommand;
|
||||||
|
import co.aikar.commands.annotation.CommandAlias;
|
||||||
|
import co.aikar.commands.annotation.CommandCompletion;
|
||||||
|
import co.aikar.commands.annotation.CommandPermission;
|
||||||
|
import co.aikar.commands.annotation.Default;
|
||||||
|
import co.aikar.commands.annotation.Description;
|
||||||
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
|
import net.frankheijden.serverutils.common.commands.Plugins;
|
||||||
|
import net.frankheijden.serverutils.common.config.Messenger;
|
||||||
|
import net.frankheijden.serverutils.velocity.managers.VelocityPluginManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.utils.VelocityUtils;
|
||||||
|
|
||||||
|
@CommandAlias("vpl|vplugins|velocitypl")
|
||||||
|
public class CommandPlugins extends BaseCommand {
|
||||||
|
|
||||||
|
private static final VelocityPluginManager manager = VelocityPluginManager.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the plugin list to the sender.
|
||||||
|
* The `-v` flag will output the plugins with version.
|
||||||
|
* The `-m` flag will also output modules in the plugin list.
|
||||||
|
* @param sender The sender of the command.
|
||||||
|
*/
|
||||||
|
@Default
|
||||||
|
@CommandCompletion("-v")
|
||||||
|
@CommandPermission("serverutils.plugins")
|
||||||
|
@Description("Shows the plugins of this proxy.")
|
||||||
|
public void onPlugins(CommandSource sender, String... args) {
|
||||||
|
boolean version = contains(args, "-v");
|
||||||
|
Plugins.sendPlugins(VelocityUtils.wrap(sender), manager.getPluginsSorted(), pl -> {
|
||||||
|
String ver = version ? Messenger.getMessage("serverutils.plugins.version",
|
||||||
|
"%version%", pl.getDescription().getVersion().orElse("<UNKNOWN>")) : "";
|
||||||
|
return Messenger.getMessage("serverutils.plugins.format",
|
||||||
|
"%plugin%", pl.getDescription().getId()) + ver;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean contains(String[] arr, String val) {
|
||||||
|
for (String s : arr) {
|
||||||
|
if (s.equalsIgnoreCase(val)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,275 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.commands;
|
||||||
|
|
||||||
|
import co.aikar.commands.BaseCommand;
|
||||||
|
import co.aikar.commands.RegisteredCommand;
|
||||||
|
import co.aikar.commands.RootCommand;
|
||||||
|
import co.aikar.commands.annotation.CommandAlias;
|
||||||
|
import co.aikar.commands.annotation.CommandCompletion;
|
||||||
|
import co.aikar.commands.annotation.CommandPermission;
|
||||||
|
import co.aikar.commands.annotation.Default;
|
||||||
|
import co.aikar.commands.annotation.Description;
|
||||||
|
import co.aikar.commands.annotation.Subcommand;
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.plugin.PluginDescription;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import net.frankheijden.serverutils.common.config.Messenger;
|
||||||
|
import net.frankheijden.serverutils.common.entities.AbstractResult;
|
||||||
|
import net.frankheijden.serverutils.common.entities.CloseableResult;
|
||||||
|
import net.frankheijden.serverutils.common.entities.Result;
|
||||||
|
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||||
|
import net.frankheijden.serverutils.common.utils.FormatBuilder;
|
||||||
|
import net.frankheijden.serverutils.common.utils.HexUtils;
|
||||||
|
import net.frankheijden.serverutils.common.utils.ListBuilder;
|
||||||
|
import net.frankheijden.serverutils.common.utils.ListFormat;
|
||||||
|
import net.frankheijden.serverutils.velocity.ServerUtils;
|
||||||
|
import net.frankheijden.serverutils.velocity.entities.VelocityLoadResult;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RVelocityCommandManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.utils.VelocityUtils;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
|
||||||
|
@CommandAlias("vsu|vserverutils")
|
||||||
|
public class CommandServerUtils extends BaseCommand {
|
||||||
|
|
||||||
|
private static final Set<String> ALIASES;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ALIASES = new HashSet<>();
|
||||||
|
ALIASES.add("vserverutils");
|
||||||
|
ALIASES.add("vplugins");
|
||||||
|
ALIASES.add("velocitypl");
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ServerUtils plugin;
|
||||||
|
|
||||||
|
public CommandServerUtils(ServerUtils plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the help page to the sender.
|
||||||
|
* @param source The sender of the command.
|
||||||
|
*/
|
||||||
|
@Default
|
||||||
|
@Subcommand("help")
|
||||||
|
@CommandPermission("serverutils.help")
|
||||||
|
@Description("Shows a help page with a few commands.")
|
||||||
|
public void onHelp(CommandSource source) {
|
||||||
|
ServerCommandSender sender = VelocityUtils.wrap(source);
|
||||||
|
Messenger.sendMessage(sender, "serverutils.help.header");
|
||||||
|
|
||||||
|
FormatBuilder builder = FormatBuilder.create(Messenger.getMessage("serverutils.help.format"))
|
||||||
|
.orderedKeys("%command%", "%subcommand%", "%help%");
|
||||||
|
|
||||||
|
Set<String> rootCommands = new HashSet<>();
|
||||||
|
for (RootCommand root : plugin.getCommandManager().getRegisteredRootCommands()) {
|
||||||
|
String rootName = root.getDefCommand().getName();
|
||||||
|
if (!rootCommands.add(rootName)) continue;
|
||||||
|
builder.add(rootName, "", root.getDescription());
|
||||||
|
|
||||||
|
Set<String> subCommands = new HashSet<>();
|
||||||
|
for (RegisteredCommand<?> sub : root.getSubCommands().values()) {
|
||||||
|
String name = sub.getPrefSubCommand().toLowerCase();
|
||||||
|
if (name.isEmpty()) continue;
|
||||||
|
if (!subCommands.add(name)) continue;
|
||||||
|
builder.add(rootName, " " + name, sub.getHelpText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.sendTo(sender);
|
||||||
|
Messenger.sendMessage(sender, "serverutils.help.footer");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads the configurations of ServerUtils.
|
||||||
|
* @param sender The sender of the command.
|
||||||
|
*/
|
||||||
|
@Subcommand("reload")
|
||||||
|
@CommandPermission("serverutils.reload")
|
||||||
|
@Description("Reloads the ServerUtils plugin.")
|
||||||
|
public void onReload(CommandSource sender) {
|
||||||
|
plugin.reload();
|
||||||
|
Messenger.sendMessage(VelocityUtils.wrap(sender), "serverutils.success",
|
||||||
|
"%action%", "reload",
|
||||||
|
"%what%", "ServerUtils Bungee configurations");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the specified plugin on the proxy.
|
||||||
|
* @param source The sender of the command.
|
||||||
|
* @param jarFile The filename of the plugin in the plugins/ directory.
|
||||||
|
*/
|
||||||
|
@Subcommand("loadplugin|lp")
|
||||||
|
@CommandCompletion("@pluginJars")
|
||||||
|
@CommandPermission("serverutils.loadplugin")
|
||||||
|
@Description("Loads the specified jar file as a plugin.")
|
||||||
|
public void onLoadPlugin(CommandSource source, String jarFile) {
|
||||||
|
ServerCommandSender sender = VelocityUtils.wrap(source);
|
||||||
|
|
||||||
|
VelocityLoadResult loadResult = plugin.getPlugin().getPluginManager().loadPlugin(jarFile);
|
||||||
|
if (!loadResult.isSuccess()) {
|
||||||
|
loadResult.getResult().sendTo(sender, "load", jarFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginContainer container = loadResult.get();
|
||||||
|
Result result = plugin.getPlugin().getPluginManager().enablePlugin(container);
|
||||||
|
result.sendTo(sender, "load", container.getDescription().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unloads the specified plugin from the proxy.
|
||||||
|
* @param source The sender of the command.
|
||||||
|
* @param pluginName The plugin name.
|
||||||
|
*/
|
||||||
|
@Subcommand("unloadplugin|up")
|
||||||
|
@CommandCompletion("@plugins")
|
||||||
|
@CommandPermission("serverutils.unloadplugin")
|
||||||
|
@Description("Disables and unloads the specified plugin.")
|
||||||
|
public void onUnloadPlugin(CommandSource source, String pluginName) {
|
||||||
|
CloseableResult result = plugin.getPlugin().getPluginManager().unloadPlugin(pluginName);
|
||||||
|
result.getResult().sendTo(VelocityUtils.wrap(source), "unload", pluginName);
|
||||||
|
result.tryClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads the specified plugin on the proxy.
|
||||||
|
* @param sender The sender of the command.
|
||||||
|
* @param pluginName The plugin name.
|
||||||
|
*/
|
||||||
|
@Subcommand("reloadplugin|rp")
|
||||||
|
@CommandCompletion("@plugins")
|
||||||
|
@CommandPermission("serverutils.reloadplugin")
|
||||||
|
@Description("Reloads a specified plugin.")
|
||||||
|
public void onReloadPlugin(CommandSource sender, String pluginName) {
|
||||||
|
// Wacky method to have the resources needed for the reload in memory, in case of a self reload.
|
||||||
|
HexUtils utils = new HexUtils();
|
||||||
|
Map<String, Object> section = Messenger.getInstance().getConfig().getMap("serverutils");
|
||||||
|
String result = plugin.getPlugin().getPluginManager().reloadPlugin(pluginName).toString();
|
||||||
|
|
||||||
|
String msg = (String) section.get(result.toLowerCase());
|
||||||
|
if (msg != null && !msg.isEmpty()) {
|
||||||
|
sender.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(utils.convertHexString(
|
||||||
|
msg.replace("%action%", "reload").replace("%what%", pluginName))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watches the given plugin and reloads it when a change is detected to the file.
|
||||||
|
* @param source The sender of the command.
|
||||||
|
* @param pluginName The plugin name.
|
||||||
|
*/
|
||||||
|
@Subcommand("watchplugin|wp")
|
||||||
|
@CommandCompletion("@plugins")
|
||||||
|
@CommandPermission("serverutils.watchplugin")
|
||||||
|
@Description("Watches the specified plugin for changes.")
|
||||||
|
public void onWatchPlugin(CommandSource source, String pluginName) {
|
||||||
|
ServerCommandSender sender = VelocityUtils.wrap(source);
|
||||||
|
AbstractResult result = plugin.getPlugin().getPluginManager().watchPlugin(sender, pluginName);
|
||||||
|
result.sendTo(sender, "watch", pluginName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops watching the given plugin.
|
||||||
|
* @param source The sender of the command.
|
||||||
|
* @param pluginName The plugin name.
|
||||||
|
*/
|
||||||
|
@Subcommand("unwatchplugin|uwp")
|
||||||
|
@CommandCompletion("@plugins")
|
||||||
|
@CommandPermission("serverutils.watchplugin")
|
||||||
|
@Description("Stops watching the specified plugin for changes.")
|
||||||
|
public void onUnwatchPlugin(CommandSource source, String pluginName) {
|
||||||
|
AbstractResult result = plugin.getPlugin().getPluginManager().unwatchPlugin(pluginName);
|
||||||
|
result.sendTo(VelocityUtils.wrap(source), "unwatch", pluginName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows information about the specified plugin.
|
||||||
|
* @param source The sender of the command.
|
||||||
|
* @param pluginName The plugin name.
|
||||||
|
*/
|
||||||
|
@Subcommand("plugininfo|pi")
|
||||||
|
@CommandCompletion("@plugins")
|
||||||
|
@CommandPermission("serverutils.plugininfo")
|
||||||
|
@Description("Shows information about the specified plugin.")
|
||||||
|
public void onPluginInfo(CommandSource source, String pluginName) {
|
||||||
|
ServerCommandSender sender = VelocityUtils.wrap(source);
|
||||||
|
|
||||||
|
Optional<PluginContainer> container = plugin.getProxy().getPluginManager().getPlugin(pluginName);
|
||||||
|
if (!container.isPresent()) {
|
||||||
|
Result.NOT_EXISTS.sendTo(sender, "fetch", pluginName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginDescription desc = container.get().getDescription();
|
||||||
|
String format = Messenger.getMessage("serverutils.plugininfo.format");
|
||||||
|
String listFormatString = Messenger.getMessage("serverutils.plugininfo.list_format");
|
||||||
|
String seperator = Messenger.getMessage("serverutils.plugininfo.seperator");
|
||||||
|
String lastSeperator = Messenger.getMessage("serverutils.plugininfo.last_seperator");
|
||||||
|
|
||||||
|
ListFormat<String> listFormat = str -> listFormatString.replace("%value%", str);
|
||||||
|
|
||||||
|
Messenger.sendMessage(sender, "serverutils.plugininfo.header");
|
||||||
|
|
||||||
|
FormatBuilder builder = FormatBuilder.create(format)
|
||||||
|
.orderedKeys("%key%", "%value%")
|
||||||
|
.add("Id", desc.getId())
|
||||||
|
.add("Name", desc.getName().orElse(null))
|
||||||
|
.add("Version", desc.getVersion().orElse("<UNKNOWN>"))
|
||||||
|
.add("Author" + (desc.getAuthors().size() == 1 ? "" : "s"), ListBuilder.create(desc.getAuthors())
|
||||||
|
.format(listFormat)
|
||||||
|
.seperator(seperator)
|
||||||
|
.lastSeperator(lastSeperator)
|
||||||
|
.toString())
|
||||||
|
.add("Description", desc.getDescription().orElse(null))
|
||||||
|
.add("URL", desc.getUrl().orElse(null))
|
||||||
|
.add("Source", desc.getSource().map(Path::toString).orElse(null))
|
||||||
|
.add("Dependencies", ListBuilder.create(desc.getDependencies())
|
||||||
|
.format(d -> listFormat.format(d.getId()))
|
||||||
|
.seperator(seperator)
|
||||||
|
.lastSeperator(lastSeperator)
|
||||||
|
.toString());
|
||||||
|
|
||||||
|
builder.sendTo(sender);
|
||||||
|
Messenger.sendMessage(sender, "serverutils.plugininfo.footer");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows information about a provided command.
|
||||||
|
* @param source The sender of the command.
|
||||||
|
* @param command The command to lookup.
|
||||||
|
*/
|
||||||
|
@Subcommand("commandinfo|ci")
|
||||||
|
@CommandCompletion("@commands")
|
||||||
|
@CommandPermission("serverutils.commandinfo")
|
||||||
|
@Description("Shows information about the specified command.")
|
||||||
|
public void onCommandInfo(CommandSource source, String command) {
|
||||||
|
ServerCommandSender sender = VelocityUtils.wrap(source);
|
||||||
|
|
||||||
|
CommandDispatcher<CommandSource> dispatcher = RVelocityCommandManager.getDispatcher(
|
||||||
|
plugin.getProxy().getCommandManager()
|
||||||
|
);
|
||||||
|
|
||||||
|
CommandNode<CommandSource> node = dispatcher.getRoot().getChild(command);
|
||||||
|
if (node == null) {
|
||||||
|
Messenger.sendMessage(sender, "serverutils.commandinfo.not_exists");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String format = Messenger.getMessage("serverutils.commandinfo.format");
|
||||||
|
|
||||||
|
Messenger.sendMessage(sender, "serverutils.commandinfo.header");
|
||||||
|
FormatBuilder builder = FormatBuilder.create(format)
|
||||||
|
.orderedKeys("%key%", "%value%")
|
||||||
|
.add("Name", node.getName())
|
||||||
|
.add("Plugin", plugin.getPluginCommandManager().findPluginId(command).orElse("<UNKNOWN>"));
|
||||||
|
|
||||||
|
builder.sendTo(sender);
|
||||||
|
Messenger.sendMessage(sender, "serverutils.commandinfo.footer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.entities;
|
||||||
|
|
||||||
|
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||||
|
import net.frankheijden.serverutils.common.providers.ChatProvider;
|
||||||
|
import net.frankheijden.serverutils.common.utils.HexUtils;
|
||||||
|
import net.frankheijden.serverutils.velocity.ServerUtils;
|
||||||
|
import net.frankheijden.serverutils.velocity.utils.VelocityUtils;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
|
||||||
|
public class VelocityChatProvider extends ChatProvider {
|
||||||
|
|
||||||
|
private final ServerUtils plugin;
|
||||||
|
|
||||||
|
public VelocityChatProvider(ServerUtils plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerCommandSender getConsoleSender() {
|
||||||
|
return VelocityUtils.wrap(plugin.getProxy().getConsoleCommandSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String color(String str) {
|
||||||
|
return HexUtils.convertHexString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void broadcast(String permission, String message) {
|
||||||
|
Component msg = LegacyComponentSerializer.legacyAmpersand().deserialize(message);
|
||||||
|
plugin.getProxy().getAllPlayers().stream()
|
||||||
|
.filter(p -> p.hasPermission(permission))
|
||||||
|
.forEach(p -> p.sendMessage(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.entities;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
|
||||||
|
public class VelocityCommandSender implements ServerCommandSender {
|
||||||
|
|
||||||
|
private final CommandSource source;
|
||||||
|
|
||||||
|
public VelocityCommandSender(CommandSource source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String message) {
|
||||||
|
source.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String permission) {
|
||||||
|
return source.hasPermission(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the given instance is a player.
|
||||||
|
* @return Boolean true or false.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isPlayer() {
|
||||||
|
return source instanceof Player;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.entities;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import net.frankheijden.serverutils.common.entities.LoadResult;
|
||||||
|
import net.frankheijden.serverutils.common.entities.Result;
|
||||||
|
|
||||||
|
public class VelocityLoadResult extends LoadResult<PluginContainer> {
|
||||||
|
|
||||||
|
public VelocityLoadResult(PluginContainer obj, Result result) {
|
||||||
|
super(obj, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VelocityLoadResult(PluginContainer obj) {
|
||||||
|
super(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VelocityLoadResult(Result result) {
|
||||||
|
super(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.entities;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.plugin.PluginDescription;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin;
|
||||||
|
import net.frankheijden.serverutils.velocity.ServerUtils;
|
||||||
|
import net.frankheijden.serverutils.velocity.managers.VelocityPluginManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.managers.VelocityTaskManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RJavaPluginLoader;
|
||||||
|
|
||||||
|
public class VelocityPlugin extends ServerUtilsPlugin {
|
||||||
|
|
||||||
|
private final ServerUtils plugin;
|
||||||
|
private final VelocityPluginManager pluginManager;
|
||||||
|
private final VelocityTaskManager taskManager;
|
||||||
|
private final VelocityResourceProvider resourceProvider;
|
||||||
|
private final VelocityChatProvider chatProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new BungeePlugin instance of ServerUtils.
|
||||||
|
* @param plugin The ServerUtils plugin.
|
||||||
|
*/
|
||||||
|
public VelocityPlugin(ServerUtils plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.pluginManager = new VelocityPluginManager();
|
||||||
|
this.taskManager = new VelocityTaskManager(plugin);
|
||||||
|
this.resourceProvider = new VelocityResourceProvider(plugin);
|
||||||
|
this.chatProvider = new VelocityChatProvider(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public VelocityPluginManager getPluginManager() {
|
||||||
|
return pluginManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public VelocityTaskManager getTaskManager() {
|
||||||
|
return taskManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VelocityResourceProvider getResourceProvider() {
|
||||||
|
return resourceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VelocityChatProvider getChatProvider() {
|
||||||
|
return chatProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Logger getLogger() {
|
||||||
|
return Logger.getLogger(plugin.getLogger().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getDataFolder() {
|
||||||
|
return plugin.getDataDirectory().toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public PluginDescription fetchUpdaterData() {
|
||||||
|
Path pluginPath = pluginManager.getPluginFile("ServerUtils").toPath();
|
||||||
|
Object javaPluginLoader = RJavaPluginLoader.newInstance(plugin.getProxy(), pluginPath.getParent());
|
||||||
|
return RJavaPluginLoader.loadPluginDescription(javaPluginLoader, pluginPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.entities;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||||
|
import net.frankheijden.serverutils.common.providers.ResourceProvider;
|
||||||
|
import net.frankheijden.serverutils.velocity.ServerUtils;
|
||||||
|
|
||||||
|
public class VelocityResourceProvider implements ResourceProvider {
|
||||||
|
|
||||||
|
private final ServerUtils plugin;
|
||||||
|
|
||||||
|
public VelocityResourceProvider(ServerUtils plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getResource(String resource) {
|
||||||
|
return plugin.getClass().getClassLoader().getResourceAsStream(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerUtilsConfig load(InputStream is) {
|
||||||
|
try {
|
||||||
|
Path tmpFile = Files.createTempFile(null, null);
|
||||||
|
Files.copy(is, tmpFile, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
|
||||||
|
VelocityTomlConfig config = new VelocityTomlConfig(tmpFile.toFile());
|
||||||
|
Files.delete(tmpFile);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerUtilsConfig load(File file) {
|
||||||
|
return new VelocityTomlConfig(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.entities;
|
||||||
|
|
||||||
|
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||||
|
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||||
|
import com.electronwill.nightconfig.toml.TomlFormat;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import net.frankheijden.serverutils.common.config.ServerUtilsConfig;
|
||||||
|
|
||||||
|
public class VelocityTomlConfig implements ServerUtilsConfig {
|
||||||
|
|
||||||
|
private final CommentedConfig config;
|
||||||
|
private final File file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new VelocityTomlConfig instance.
|
||||||
|
*/
|
||||||
|
public VelocityTomlConfig(File file) {
|
||||||
|
CommentedFileConfig config = CommentedFileConfig.of(file, TomlFormat.instance());
|
||||||
|
config.load();
|
||||||
|
|
||||||
|
this.config = config;
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VelocityTomlConfig(CommentedConfig config, File file) {
|
||||||
|
this.config = config;
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object get(String path) {
|
||||||
|
Object obj = config.get(path);
|
||||||
|
if (obj instanceof CommentedConfig) {
|
||||||
|
return new VelocityTomlConfig((CommentedConfig) obj, file);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getStringList(String path) {
|
||||||
|
return config.getOrElse(path, new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getMap(String path) {
|
||||||
|
CommentedConfig section = config.get(path);
|
||||||
|
if (section == null) return new HashMap<>();
|
||||||
|
return section.valueMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(String path, Object value) {
|
||||||
|
config.set(path, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getString(String path) {
|
||||||
|
return config.get(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getBoolean(String path) {
|
||||||
|
return config.get(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends String> getKeys() {
|
||||||
|
return config.valueMap().keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() throws IOException {
|
||||||
|
if (config instanceof CommentedFileConfig) {
|
||||||
|
((CommentedFileConfig) config).save();
|
||||||
|
} else {
|
||||||
|
throw new IOException("Config is not an instance of CommentedFileConfig!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.managers;
|
||||||
|
|
||||||
|
import com.google.common.collect.HashMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.common.collect.Multimaps;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class VelocityPluginCommandManager {
|
||||||
|
|
||||||
|
private static final Gson gson = new Gson();
|
||||||
|
|
||||||
|
private final Multimap<String, String> pluginCommands;
|
||||||
|
private final Path path;
|
||||||
|
|
||||||
|
public VelocityPluginCommandManager(Path path) {
|
||||||
|
this.pluginCommands = Multimaps.synchronizedSetMultimap(HashMultimap.create());
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads and constructs a new {@link VelocityPluginCommandManager} from the given {@link Path}.
|
||||||
|
*/
|
||||||
|
public static VelocityPluginCommandManager load(Path path) throws IOException {
|
||||||
|
VelocityPluginCommandManager manager = new VelocityPluginCommandManager(path);
|
||||||
|
if (Files.exists(path)) {
|
||||||
|
Map<String, Collection<String>> rawMap = gson.fromJson(
|
||||||
|
Files.newBufferedReader(path),
|
||||||
|
new TypeToken<Map<String, Collection<String>>>(){}.getType()
|
||||||
|
);
|
||||||
|
rawMap.forEach(manager.pluginCommands::putAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to find the plugin id for a given command alias.
|
||||||
|
*/
|
||||||
|
public Optional<String> findPluginId(String alias) {
|
||||||
|
for (Map.Entry<String, String> entry : pluginCommands.entries()) {
|
||||||
|
if (alias.equals(entry.getValue())) {
|
||||||
|
return Optional.of(entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Multimap<String, String> getPluginCommands() {
|
||||||
|
return pluginCommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the map to the {@link Path} it was loaded from.
|
||||||
|
*/
|
||||||
|
public void save() throws IOException {
|
||||||
|
Files.write(
|
||||||
|
path,
|
||||||
|
gson.toJson(pluginCommands.asMap()).getBytes(StandardCharsets.UTF_8),
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.TRUNCATE_EXISTING
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,283 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.managers;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
import com.google.inject.name.Names;
|
||||||
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
|
import com.velocitypowered.api.command.CommandManager;
|
||||||
|
import com.velocitypowered.api.event.EventManager;
|
||||||
|
import com.velocitypowered.api.event.permission.PermissionsSetupEvent;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||||
|
import com.velocitypowered.api.permission.PermissionFunction;
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.plugin.PluginDescription;
|
||||||
|
import com.velocitypowered.api.plugin.PluginManager;
|
||||||
|
import com.velocitypowered.api.plugin.meta.PluginDependency;
|
||||||
|
import com.velocitypowered.api.proxy.ConsoleCommandSource;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
|
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import net.frankheijden.serverutils.common.entities.CloseableResult;
|
||||||
|
import net.frankheijden.serverutils.common.entities.Result;
|
||||||
|
import net.frankheijden.serverutils.common.managers.AbstractPluginManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.ServerUtils;
|
||||||
|
import net.frankheijden.serverutils.velocity.entities.VelocityLoadResult;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RJavaPluginLoader;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RVelocityCommandManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RVelocityConsole;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RVelocityEventManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RVelocityPluginContainer;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RVelocityPluginManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.reflection.RVelocityScheduler;
|
||||||
|
|
||||||
|
public class VelocityPluginManager extends AbstractPluginManager<PluginContainer> {
|
||||||
|
|
||||||
|
private static VelocityPluginManager instance;
|
||||||
|
private final ProxyServer proxy;
|
||||||
|
|
||||||
|
public VelocityPluginManager() {
|
||||||
|
instance = this;
|
||||||
|
this.proxy = ServerUtils.getInstance().getProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VelocityPluginManager get() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VelocityLoadResult loadPlugin(String pluginFile) {
|
||||||
|
return loadPlugin(new File(getPluginsFolder(), pluginFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VelocityLoadResult loadPlugin(File file) {
|
||||||
|
if (!file.exists() || file.isDirectory()) return new VelocityLoadResult(Result.NOT_EXISTS);
|
||||||
|
|
||||||
|
Object javaPluginLoader = RJavaPluginLoader.newInstance(proxy, file.toPath().getParent());
|
||||||
|
PluginDescription candidate = RJavaPluginLoader.loadPluginDescription(javaPluginLoader, file.toPath());
|
||||||
|
if (proxy.getPluginManager().isLoaded(candidate.getId())) return new VelocityLoadResult(Result.ALREADY_LOADED);
|
||||||
|
|
||||||
|
for (PluginDependency dependency : candidate.getDependencies()) {
|
||||||
|
if (!dependency.isOptional() && !proxy.getPluginManager().isLoaded(dependency.getId())) {
|
||||||
|
ServerUtils.getInstance().getLogger().error(
|
||||||
|
"Can't load plugin {} due to missing dependency {}",
|
||||||
|
candidate.getId(),
|
||||||
|
dependency.getId()
|
||||||
|
);
|
||||||
|
return new VelocityLoadResult(Result.UNKNOWN_DEPENDENCY.arg(dependency.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginDescription realPlugin = RJavaPluginLoader.loadPlugin(javaPluginLoader, candidate);
|
||||||
|
PluginContainer container = RVelocityPluginContainer.newInstance(realPlugin);
|
||||||
|
|
||||||
|
return new VelocityLoadResult(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result enablePlugin(PluginContainer container) {
|
||||||
|
if (proxy.getPluginManager().isLoaded(container.getDescription().getId())) return Result.ALREADY_ENABLED;
|
||||||
|
|
||||||
|
Object javaPluginLoader = RJavaPluginLoader.newInstance(
|
||||||
|
proxy,
|
||||||
|
container.getDescription().getSource().map(Path::getParent).orElse(null)
|
||||||
|
);
|
||||||
|
PluginDescription realPlugin = container.getDescription();
|
||||||
|
Module module = RJavaPluginLoader.createModule(javaPluginLoader, container);
|
||||||
|
|
||||||
|
AbstractModule commonModule = new AbstractModule() {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(ProxyServer.class).toInstance(proxy);
|
||||||
|
bind(PluginManager.class).toInstance(proxy.getPluginManager());
|
||||||
|
bind(EventManager.class).toInstance(proxy.getEventManager());
|
||||||
|
bind(CommandManager.class).toInstance(proxy.getCommandManager());
|
||||||
|
for (PluginContainer container : proxy.getPluginManager().getPlugins()) {
|
||||||
|
bind(PluginContainer.class)
|
||||||
|
.annotatedWith(Names.named(container.getDescription().getId()))
|
||||||
|
.toInstance(container);
|
||||||
|
}
|
||||||
|
bind(PluginContainer.class)
|
||||||
|
.annotatedWith(Names.named(realPlugin.getId()))
|
||||||
|
.toInstance(container);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
RJavaPluginLoader.createPlugin(javaPluginLoader, container, module, commonModule);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ServerUtils.getInstance().getLogger().error(
|
||||||
|
String.format("Can't create plugin %s", container.getDescription().getId()),
|
||||||
|
ex
|
||||||
|
);
|
||||||
|
return Result.ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerUtils.getInstance().getLogger().info(
|
||||||
|
"Loaded plugin {} {} by {}",
|
||||||
|
realPlugin.getId(),
|
||||||
|
realPlugin.getVersion().orElse("<UNKNOWN>"),
|
||||||
|
Joiner.on(", ").join(realPlugin.getAuthors())
|
||||||
|
);
|
||||||
|
|
||||||
|
RVelocityPluginManager.registerPlugin(proxy.getPluginManager(), container);
|
||||||
|
container.getInstance().ifPresent(instance -> {
|
||||||
|
RVelocityEventManager.registerInternally(proxy.getEventManager(), container, instance);
|
||||||
|
RVelocityEventManager.fireForPlugin(
|
||||||
|
proxy.getEventManager(),
|
||||||
|
new ProxyInitializeEvent(),
|
||||||
|
instance
|
||||||
|
).join();
|
||||||
|
|
||||||
|
ConsoleCommandSource console = proxy.getConsoleCommandSource();
|
||||||
|
PermissionsSetupEvent event = new PermissionsSetupEvent(
|
||||||
|
console,
|
||||||
|
s -> PermissionFunction.ALWAYS_TRUE
|
||||||
|
);
|
||||||
|
PermissionFunction permissionFunction = RVelocityEventManager.fireForPlugin(
|
||||||
|
proxy.getEventManager(),
|
||||||
|
event,
|
||||||
|
instance
|
||||||
|
).join().createFunction(console);
|
||||||
|
|
||||||
|
if (permissionFunction == null) {
|
||||||
|
ServerUtils.getInstance().getLogger().error(
|
||||||
|
"A plugin permission provider {} provided an invalid permission function for the console."
|
||||||
|
+ " This is a bug in the plugin, not in Velocity."
|
||||||
|
+ " Falling back to the default permission function.",
|
||||||
|
event.getProvider().getClass().getName()
|
||||||
|
);
|
||||||
|
permissionFunction = PermissionFunction.ALWAYS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
RVelocityConsole.setPermissionFunction(console, permissionFunction);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Result.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result disablePlugin(PluginContainer plugin) {
|
||||||
|
Object pluginInstance = plugin.getInstance().orElse(null);
|
||||||
|
if (pluginInstance == null) return Result.NOT_EXISTS;
|
||||||
|
|
||||||
|
RVelocityEventManager.fireForPlugin(
|
||||||
|
proxy.getEventManager(),
|
||||||
|
pluginInstance,
|
||||||
|
new ProxyShutdownEvent()
|
||||||
|
);
|
||||||
|
|
||||||
|
return Result.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result reloadPlugin(String pluginName) {
|
||||||
|
Optional<PluginContainer> pluginOptional = proxy.getPluginManager().getPlugin(pluginName);
|
||||||
|
if (!pluginOptional.isPresent()) return Result.NOT_EXISTS;
|
||||||
|
return reloadPlugin(pluginOptional.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result reloadPlugin(PluginContainer plugin) {
|
||||||
|
CloseableResult result = unloadPlugin(plugin);
|
||||||
|
if (result.getResult() != Result.SUCCESS) return result.getResult();
|
||||||
|
result.tryClose();
|
||||||
|
|
||||||
|
File file = getPluginFile(plugin.getDescription().getId());
|
||||||
|
if (file == null) return Result.FILE_DELETED;
|
||||||
|
|
||||||
|
VelocityLoadResult loadResult = loadPlugin(file);
|
||||||
|
if (!loadResult.isSuccess()) return loadResult.getResult();
|
||||||
|
|
||||||
|
return enablePlugin(loadResult.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CloseableResult unloadPlugin(String pluginName) {
|
||||||
|
Optional<PluginContainer> pluginOptional = proxy.getPluginManager().getPlugin(pluginName);
|
||||||
|
if (!pluginOptional.isPresent()) return new CloseableResult(Result.NOT_EXISTS);
|
||||||
|
return unloadPlugin(pluginOptional.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CloseableResult unloadPlugin(PluginContainer plugin) {
|
||||||
|
Optional<?> pluginInstanceOptional = plugin.getInstance();
|
||||||
|
if (!pluginInstanceOptional.isPresent()) return new CloseableResult(Result.INVALID_PLUGIN);
|
||||||
|
Object pluginInstance = pluginInstanceOptional.get();
|
||||||
|
|
||||||
|
proxy.getEventManager().unregisterListeners(pluginInstance);
|
||||||
|
for (ScheduledTask task : RVelocityScheduler.getTasksByPlugin(proxy.getScheduler()).removeAll(pluginInstance)) {
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
String pluginId = plugin.getDescription().getId();
|
||||||
|
VelocityPluginCommandManager pluginCommandManager = ServerUtils.getInstance().getPluginCommandManager();
|
||||||
|
for (String alias : pluginCommandManager.getPluginCommands().removeAll(pluginId)) {
|
||||||
|
proxy.getCommandManager().unregister(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
RVelocityPluginManager.getPlugins(proxy.getPluginManager()).remove(pluginId);
|
||||||
|
RVelocityPluginManager.getPluginInstances(proxy.getPluginManager()).remove(pluginInstance);
|
||||||
|
|
||||||
|
List<Closeable> closeables = new ArrayList<>();
|
||||||
|
|
||||||
|
ClassLoader loader = pluginInstance.getClass().getClassLoader();
|
||||||
|
if (loader instanceof Closeable) {
|
||||||
|
closeables.add((Closeable) loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CloseableResult(closeables);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PluginContainer> getPlugins() {
|
||||||
|
return new ArrayList<>(proxy.getPluginManager().getPlugins());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginName(PluginContainer plugin) {
|
||||||
|
return plugin.getDescription().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getPluginFile(PluginContainer plugin) {
|
||||||
|
return plugin.getDescription().getSource()
|
||||||
|
.map(Path::toFile)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getPluginFile(String pluginName) {
|
||||||
|
Object javaPluginLoader = RJavaPluginLoader.newInstance(instance.proxy, getPluginsFolder().toPath());
|
||||||
|
|
||||||
|
for (File file : getPluginJars()) {
|
||||||
|
PluginDescription desc = RJavaPluginLoader.loadPluginDescription(javaPluginLoader, file.toPath());
|
||||||
|
|
||||||
|
if (desc.getId().equals(pluginName)) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PluginContainer getPlugin(String pluginName) {
|
||||||
|
return proxy.getPluginManager().getPlugin(pluginName).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getCommands() {
|
||||||
|
return RVelocityCommandManager.getDispatcher(proxy.getCommandManager()).getRoot().getChildren().stream()
|
||||||
|
.map(CommandNode::getName)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.managers;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||||
|
import java.time.Duration;
|
||||||
|
import net.frankheijden.serverutils.common.managers.AbstractTaskManager;
|
||||||
|
import net.frankheijden.serverutils.velocity.ServerUtils;
|
||||||
|
|
||||||
|
public class VelocityTaskManager extends AbstractTaskManager<ScheduledTask> {
|
||||||
|
|
||||||
|
private final ServerUtils plugin;
|
||||||
|
|
||||||
|
public VelocityTaskManager(ServerUtils plugin) {
|
||||||
|
super(ScheduledTask::cancel);
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ScheduledTask runTaskImpl(Runnable runnable) {
|
||||||
|
return runTaskAsynchronously(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScheduledTask runTaskLater(Runnable runnable, long delay) {
|
||||||
|
return plugin.getProxy().getScheduler()
|
||||||
|
.buildTask(plugin, runnable)
|
||||||
|
.delay(Duration.ofMillis(delay * 50))
|
||||||
|
.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ScheduledTask runTaskAsynchronouslyImpl(Runnable runnable) {
|
||||||
|
return plugin.getProxy().getScheduler()
|
||||||
|
.buildTask(plugin, runnable)
|
||||||
|
.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelTask(ScheduledTask task) {
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.reflection;
|
||||||
|
|
||||||
|
import com.google.inject.Module;
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.plugin.PluginDescription;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
|
import dev.frankheijden.minecraftreflection.ClassObject;
|
||||||
|
import dev.frankheijden.minecraftreflection.MinecraftReflection;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class RJavaPluginLoader {
|
||||||
|
|
||||||
|
private static final MinecraftReflection reflection = MinecraftReflection
|
||||||
|
.of("com.velocitypowered.proxy.plugin.loader.java.JavaPluginLoader");
|
||||||
|
|
||||||
|
private RJavaPluginLoader() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance of a JavaPluginLoader.
|
||||||
|
*/
|
||||||
|
public static Object newInstance(ProxyServer proxy, Path baseDirectory) {
|
||||||
|
return reflection.newInstance(
|
||||||
|
ClassObject.of(ProxyServer.class, proxy),
|
||||||
|
ClassObject.of(Path.class, baseDirectory)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PluginDescription loadPluginDescription(Object javaPluginLoader, Path source) {
|
||||||
|
return reflection.invoke(javaPluginLoader, "loadPluginDescription", ClassObject.of(Path.class, source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the plugin from their candidate PluginDescription.
|
||||||
|
*/
|
||||||
|
public static PluginDescription loadPlugin(Object javaPluginLoader, PluginDescription candidate) {
|
||||||
|
return reflection.invoke(
|
||||||
|
javaPluginLoader,
|
||||||
|
"loadPlugin",
|
||||||
|
ClassObject.of(PluginDescription.class, candidate)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Module createModule(Object javaPluginLoader, PluginContainer container) {
|
||||||
|
return reflection.invoke(javaPluginLoader, "createModule", ClassObject.of(PluginContainer.class, container));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the plugin.
|
||||||
|
*/
|
||||||
|
public static void createPlugin(Object javaPluginLoader, PluginContainer container, Module... modules) {
|
||||||
|
reflection.invoke(
|
||||||
|
javaPluginLoader,
|
||||||
|
"createPlugin",
|
||||||
|
ClassObject.of(PluginContainer.class, container),
|
||||||
|
ClassObject.of(Array.newInstance(Module.class, 0).getClass(), modules)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.reflection;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.velocitypowered.api.command.CommandManager;
|
||||||
|
import com.velocitypowered.api.command.CommandMeta;
|
||||||
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
|
import dev.frankheijden.minecraftreflection.MinecraftReflection;
|
||||||
|
import dev.frankheijden.minecraftreflection.Reflection;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import net.frankheijden.serverutils.velocity.ServerUtils;
|
||||||
|
import net.frankheijden.serverutils.velocity.utils.ReflectionUtils;
|
||||||
|
|
||||||
|
public class RVelocityCommandManager {
|
||||||
|
|
||||||
|
private static final MinecraftReflection reflection = MinecraftReflection
|
||||||
|
.of("com.velocitypowered.proxy.command.VelocityCommandManager");
|
||||||
|
|
||||||
|
private RVelocityCommandManager() {}
|
||||||
|
|
||||||
|
public static CommandDispatcher<CommandSource> getDispatcher(CommandManager manager) {
|
||||||
|
return reflection.get(manager, "dispatcher");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxies the registrars.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static void proxyRegistrars(
|
||||||
|
ProxyServer proxy,
|
||||||
|
ClassLoader loader,
|
||||||
|
BiConsumer<PluginContainer, CommandMeta> registrationConsumer
|
||||||
|
) {
|
||||||
|
List<Object> proxiedRegistrars = new ArrayList<>();
|
||||||
|
|
||||||
|
Class<?> commandRegistrarClass;
|
||||||
|
try {
|
||||||
|
commandRegistrarClass = Class.forName("com.velocitypowered.proxy.command.registrar.CommandRegistrar");
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object registrar : (List) reflection.get(proxy.getCommandManager(), "registrars")) {
|
||||||
|
proxiedRegistrars.add(Proxy.newProxyInstance(
|
||||||
|
loader,
|
||||||
|
new Class[]{ commandRegistrarClass },
|
||||||
|
new CommandRegistrarInvocationHandler(
|
||||||
|
proxy,
|
||||||
|
registrar,
|
||||||
|
registrationConsumer
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Field registrarsField = Reflection.getAccessibleField(reflection.getClazz(), "registrars");
|
||||||
|
ReflectionUtils.doPrivilegedWithUnsafe(unsafe -> {
|
||||||
|
long offset = unsafe.objectFieldOffset(registrarsField);
|
||||||
|
unsafe.putObject(proxy.getCommandManager(), offset, proxiedRegistrars);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CommandRegistrarInvocationHandler implements InvocationHandler {
|
||||||
|
|
||||||
|
private final ProxyServer proxy;
|
||||||
|
private final Object commandRegistrar;
|
||||||
|
private final BiConsumer<PluginContainer, CommandMeta> registrationConsumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link CommandRegistrarInvocationHandler}.
|
||||||
|
*/
|
||||||
|
public CommandRegistrarInvocationHandler(
|
||||||
|
ProxyServer proxy,
|
||||||
|
Object commandRegistrar,
|
||||||
|
BiConsumer<PluginContainer, CommandMeta> registrationConsumer
|
||||||
|
) {
|
||||||
|
this.proxy = proxy;
|
||||||
|
this.commandRegistrar = commandRegistrar;
|
||||||
|
this.registrationConsumer = registrationConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
|
Object obj = method.invoke(commandRegistrar, args);
|
||||||
|
if (method.getName().equals("register")) {
|
||||||
|
handleRegisterMethod((CommandMeta) args[0]);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRegisterMethod(CommandMeta commandMeta) {
|
||||||
|
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
|
||||||
|
|
||||||
|
// Skip the first four elements, which is our overhead here
|
||||||
|
for (int i = 4; i < elements.length; i++) {
|
||||||
|
Class<?> clazz;
|
||||||
|
try {
|
||||||
|
clazz = Class.forName(elements[i].getClassName());
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassLoader classLoader = clazz.getClassLoader();
|
||||||
|
for (PluginContainer container : proxy.getPluginManager().getPlugins()) {
|
||||||
|
if (container.getInstance().filter(o -> o.getClass().getClassLoader() == classLoader).isPresent()) {
|
||||||
|
registrationConsumer.accept(container, commandMeta);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerUtils.getInstance().getLogger().warn(
|
||||||
|
"Couldn't find the registering plugin for the following aliases: {}",
|
||||||
|
commandMeta.getAliases()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.reflection;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.permission.PermissionFunction;
|
||||||
|
import com.velocitypowered.api.proxy.ConsoleCommandSource;
|
||||||
|
import dev.frankheijden.minecraftreflection.MinecraftReflection;
|
||||||
|
|
||||||
|
public class RVelocityConsole {
|
||||||
|
|
||||||
|
private static final MinecraftReflection reflection = MinecraftReflection
|
||||||
|
.of("com.velocitypowered.proxy.console.VelocityConsole");
|
||||||
|
|
||||||
|
private RVelocityConsole() {}
|
||||||
|
|
||||||
|
public static void setPermissionFunction(ConsoleCommandSource velocityConsole, PermissionFunction function) {
|
||||||
|
reflection.set(velocityConsole, "permissionFunction", function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.reflection;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.velocitypowered.api.event.EventHandler;
|
||||||
|
import com.velocitypowered.api.event.EventManager;
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import dev.frankheijden.minecraftreflection.ClassObject;
|
||||||
|
import dev.frankheijden.minecraftreflection.MinecraftReflection;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class RVelocityEventManager {
|
||||||
|
|
||||||
|
private static final MinecraftReflection reflection = MinecraftReflection
|
||||||
|
.of("com.velocitypowered.proxy.event.VelocityEventManager");
|
||||||
|
|
||||||
|
private RVelocityEventManager() {}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Multimap getHandlersByType(EventManager manager) {
|
||||||
|
return reflection.get(manager, "handlersByType");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the registrations from a plugin for a specific event.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static List<Object> getRegistrationsByPlugin(EventManager manager, Object plugin, Class<?> eventClass) {
|
||||||
|
return (List<Object>) getHandlersByType(manager).get(eventClass).stream()
|
||||||
|
.filter(r -> RHandlerRegistration.getPlugin(r).getInstance().orElse(null) == plugin)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the listener for a given plugin.
|
||||||
|
*/
|
||||||
|
public static void registerInternally(EventManager manager, PluginContainer container, Object listener) {
|
||||||
|
reflection.invoke(
|
||||||
|
manager,
|
||||||
|
"registerInternally",
|
||||||
|
ClassObject.of(PluginContainer.class, container),
|
||||||
|
ClassObject.of(Object.class, listener)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires an event specifically for one plugin.
|
||||||
|
*/
|
||||||
|
public static <E> CompletableFuture<E> fireForPlugin(
|
||||||
|
EventManager manager,
|
||||||
|
E event,
|
||||||
|
Object plugin
|
||||||
|
) {
|
||||||
|
List<Object> registrations = getRegistrationsByPlugin(manager, plugin, event.getClass());
|
||||||
|
CompletableFuture<E> future = new CompletableFuture<>();
|
||||||
|
|
||||||
|
Object registrationsEmptyArray = Array.newInstance(RHandlerRegistration.reflection.getClazz(), 0);
|
||||||
|
Class<?> registrationsArrayClass = registrationsEmptyArray.getClass();
|
||||||
|
|
||||||
|
reflection.invoke(
|
||||||
|
manager,
|
||||||
|
"fire",
|
||||||
|
ClassObject.of(CompletableFuture.class, future),
|
||||||
|
ClassObject.of(Object.class, event),
|
||||||
|
ClassObject.of(int.class, 0),
|
||||||
|
ClassObject.of(boolean.class, false),
|
||||||
|
ClassObject.of(registrationsArrayClass, registrations.toArray((Object[]) registrationsEmptyArray))
|
||||||
|
);
|
||||||
|
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RHandlerRegistration {
|
||||||
|
|
||||||
|
private static final MinecraftReflection reflection = MinecraftReflection
|
||||||
|
.of("com.velocitypowered.proxy.event.VelocityEventManager$HandlerRegistration");
|
||||||
|
|
||||||
|
private RHandlerRegistration() {}
|
||||||
|
|
||||||
|
public static PluginContainer getPlugin(Object registration) {
|
||||||
|
return reflection.get(registration, "plugin");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventHandler<Object> getEventHandler(Object registration) {
|
||||||
|
return reflection.get(registration, "handler");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.reflection;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.plugin.PluginDescription;
|
||||||
|
import dev.frankheijden.minecraftreflection.ClassObject;
|
||||||
|
import dev.frankheijden.minecraftreflection.MinecraftReflection;
|
||||||
|
|
||||||
|
public class RVelocityPluginContainer {
|
||||||
|
|
||||||
|
private static final MinecraftReflection reflection = MinecraftReflection
|
||||||
|
.of("com.velocitypowered.proxy.plugin.loader.VelocityPluginContainer");
|
||||||
|
|
||||||
|
private RVelocityPluginContainer() {}
|
||||||
|
|
||||||
|
public static PluginContainer newInstance(PluginDescription description) {
|
||||||
|
return reflection.newInstance(ClassObject.of(PluginDescription.class, description));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.reflection;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.plugin.PluginManager;
|
||||||
|
import dev.frankheijden.minecraftreflection.ClassObject;
|
||||||
|
import dev.frankheijden.minecraftreflection.MinecraftReflection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RVelocityPluginManager {
|
||||||
|
|
||||||
|
private static final MinecraftReflection reflection = MinecraftReflection
|
||||||
|
.of("com.velocitypowered.proxy.plugin.VelocityPluginManager");
|
||||||
|
|
||||||
|
private RVelocityPluginManager() {}
|
||||||
|
|
||||||
|
public static Map<String, PluginContainer> getPlugins(PluginManager manager) {
|
||||||
|
return reflection.get(manager, "plugins");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Object, PluginContainer> getPluginInstances(PluginManager manager) {
|
||||||
|
return reflection.get(manager, "pluginInstances");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerPlugin(PluginManager manager, PluginContainer container) {
|
||||||
|
reflection.invoke(manager, "registerPlugin", ClassObject.of(PluginContainer.class, container));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.reflection;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||||
|
import com.velocitypowered.api.scheduler.Scheduler;
|
||||||
|
import dev.frankheijden.minecraftreflection.MinecraftReflection;
|
||||||
|
|
||||||
|
public class RVelocityScheduler {
|
||||||
|
|
||||||
|
private static final MinecraftReflection reflection = MinecraftReflection
|
||||||
|
.of("com.velocitypowered.proxy.scheduler.VelocityScheduler");
|
||||||
|
|
||||||
|
private RVelocityScheduler() {}
|
||||||
|
|
||||||
|
public static Multimap<Object, ScheduledTask> getTasksByPlugin(Scheduler scheduler) {
|
||||||
|
return reflection.get(scheduler, "tasksByPlugin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.utils;
|
||||||
|
|
||||||
|
import dev.frankheijden.minecraftreflection.Reflection;
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
|
public class ReflectionUtils {
|
||||||
|
|
||||||
|
private static MethodHandle theUnsafeFieldMethodHandle;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
theUnsafeFieldMethodHandle = MethodHandles.lookup().unreflectGetter(Reflection.getAccessibleField(
|
||||||
|
Unsafe.class,
|
||||||
|
"theUnsafe"
|
||||||
|
));
|
||||||
|
} catch (Throwable th) {
|
||||||
|
th.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReflectionUtils() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a privileged action while accessing {@link Unsafe}.
|
||||||
|
*/
|
||||||
|
public static void doPrivilegedWithUnsafe(Consumer<Unsafe> privilegedAction) {
|
||||||
|
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||||
|
try {
|
||||||
|
privilegedAction.accept((Unsafe) theUnsafeFieldMethodHandle.invoke());
|
||||||
|
} catch (Throwable th) {
|
||||||
|
th.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package net.frankheijden.serverutils.velocity.utils;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
|
import net.frankheijden.serverutils.common.entities.ServerCommandSender;
|
||||||
|
import net.frankheijden.serverutils.velocity.entities.VelocityCommandSender;
|
||||||
|
|
||||||
|
public class VelocityUtils {
|
||||||
|
|
||||||
|
public static ServerCommandSender wrap(CommandSource source) {
|
||||||
|
return new VelocityCommandSender(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
7
Velocity/src/main/resources/velocity-config.toml
Normal file
7
Velocity/src/main/resources/velocity-config.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[settings]
|
||||||
|
check-updates-boot = true
|
||||||
|
check-updates-login = false
|
||||||
|
download-updates-boot = false
|
||||||
|
download-updates-login = false
|
||||||
|
install-updates-boot = false
|
||||||
|
install-updates-login = false
|
||||||
67
Velocity/src/main/resources/velocity-messages.toml
Normal file
67
Velocity/src/main/resources/velocity-messages.toml
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
[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!"
|
||||||
|
not_enabled = "&cAn error occurred while %action%ing &4%what%&c, plugin is not enabled!"
|
||||||
|
already_loaded = "&cAn error occurred while %action%ing &4%what%&c, plugin is already loaded!"
|
||||||
|
already_enabled = "&cAn error occurred while %action%ing &4%what%&c, plugin is already enabled!"
|
||||||
|
already_disabled = "&cAn error occurred while %action%ing &4%what%&c, plugin is already disabled!"
|
||||||
|
file_deleted = "&cAccessing the jar file while %action%ing &4%what%&c went wrong, plugin has been deleted!"
|
||||||
|
invalid_description = "&cAn error occurred while %action%ing &4%what%&c, plugin doesn't have a valid description, please check the console!"
|
||||||
|
invalid_plugin = "&cAn error occurred while %action%ing &4%what%&c, plugin is invalid!"
|
||||||
|
unknown_dependency = "&cAn error occurred while %action%ing &4%what%&c, plugin has a dependeny which is not loaded: &4%arg%"
|
||||||
|
|
||||||
|
[serverutils.watcher]
|
||||||
|
start = "&3Started watching &b%what%&3!"
|
||||||
|
change = "&3Change detected for plugin &b%what%&3, reloading now..."
|
||||||
|
stopped = "&3Stopped watching &b%what%&3!"
|
||||||
|
not_watching = "&cWe aren't watching that plugin!"
|
||||||
|
|
||||||
|
[serverutils.update]
|
||||||
|
available = """
|
||||||
|
&8&m--------=&r&8[ &b&lServerUtils Velocity Update&r &8]&m=---------
|
||||||
|
&3Current version: &b%old%
|
||||||
|
&3New version: &b%new%
|
||||||
|
&3Release info: &b%info%
|
||||||
|
&8&m-------------------------------------------------"""
|
||||||
|
downloading = """
|
||||||
|
&8&m--------=&r&8[ &b&lServerUtils Velocity Update&r &8]&m=----------
|
||||||
|
&3A new version of ServerUtils will be downloaded and installed after a restart!
|
||||||
|
&3Current version: &b%old%
|
||||||
|
&3New version: &b%new%
|
||||||
|
&3Release info: &b%info%
|
||||||
|
&8&m-------------------------------------------------"""
|
||||||
|
download_failed = "&cFailed to download version %new% of ServerUtils. Please update manually."
|
||||||
|
download_success = "&3ServerUtils has been downloaded and will be installed on the next restart."
|
||||||
|
|
||||||
|
[serverutils.help]
|
||||||
|
header = "&8&m---------=&r&8[ &b&lServerUtils Velocity Help&r &8]&m=---------"
|
||||||
|
format = "&8/&3%command%&b%subcommand% &f(&7%help%&f)"
|
||||||
|
footer = "&8&m-------------------------------------------------"
|
||||||
|
|
||||||
|
[serverutils.plugins]
|
||||||
|
header = "&8&m--------=&r&8[ &b&lServerUtils Velocity Plugins&r &8]&m=-------"
|
||||||
|
prefix = " &3Plugins &8(&a%count%&8)&b: "
|
||||||
|
format = "&3%plugin%"
|
||||||
|
seperator = "&b, "
|
||||||
|
last_seperator = " &band "
|
||||||
|
version = " &8(&a%version%&8)"
|
||||||
|
footer = "&8&m-------------------------------------------------"
|
||||||
|
|
||||||
|
[serverutils.plugininfo]
|
||||||
|
header = "&8&m------=&r&8[ &b&lServerUtils Velocity PluginInfo&r &8]&m=------"
|
||||||
|
format = " &3%key%&8: &b%value%"
|
||||||
|
list_format = "&b%value%"
|
||||||
|
seperator = "&8, "
|
||||||
|
last_seperator = " &8and "
|
||||||
|
footer = "&8&m-------------------------------------------------"
|
||||||
|
|
||||||
|
[serverutils.commandinfo]
|
||||||
|
header = "&8&m-----=&r&8[ &b&lServerUtils Velocity CommandInfo&r &8]&m=------"
|
||||||
|
format = " &3%key%&8: &b%value%"
|
||||||
|
list_format = "&b%value%"
|
||||||
|
seperator = "&8, "
|
||||||
|
last_seperator = " &8and "
|
||||||
|
footer = "&8&m-------------------------------------------------"
|
||||||
|
not_exists = "&cThat command is not a valid registered command."
|
||||||
|
|
@ -62,6 +62,7 @@ dependencies {
|
||||||
implementation project(path: ':Common', configuration: 'shadow')
|
implementation project(path: ':Common', configuration: 'shadow')
|
||||||
implementation project(path: ':Bukkit', configuration: 'shadow')
|
implementation project(path: ':Bukkit', configuration: 'shadow')
|
||||||
implementation project(path: ':Bungee', configuration: 'shadow')
|
implementation project(path: ':Bungee', configuration: 'shadow')
|
||||||
|
implementation project(path: ':Velocity', configuration: 'shadow')
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
|
|
@ -71,7 +72,12 @@ shadowJar {
|
||||||
}
|
}
|
||||||
|
|
||||||
def outputTasks() {
|
def outputTasks() {
|
||||||
["shadowJar", ":Bukkit:shadowJar", ":Bungee:shadowJar"].stream().map({ tasks.findByPath(it) })
|
[
|
||||||
|
"shadowJar",
|
||||||
|
":Bukkit:shadowJar",
|
||||||
|
":Bungee:shadowJar",
|
||||||
|
":Velocity:shadowJar",
|
||||||
|
].stream().map({ tasks.findByPath(it) })
|
||||||
}
|
}
|
||||||
|
|
||||||
task copyJars(type: Copy) {
|
task copyJars(type: Copy) {
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@ rootProject.name = 'ServerUtils'
|
||||||
include 'Common'
|
include 'Common'
|
||||||
include 'Bukkit'
|
include 'Bukkit'
|
||||||
include 'Bungee'
|
include 'Bungee'
|
||||||
|
include 'Velocity'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue