Skip to content

Commit c8e744c

Browse files
committed
feat: initial Velocity support
1 parent a3e6820 commit c8e744c

File tree

11 files changed

+264
-336
lines changed

11 files changed

+264
-336
lines changed

src/main/java/net/okocraft/serverconnector/ServerConnectorPlugin.java

Lines changed: 68 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,57 @@
33
import com.github.siroshun09.configapi.api.util.ResourceUtils;
44
import com.github.siroshun09.configapi.yaml.YamlConfiguration;
55
import com.github.siroshun09.translationloader.directory.TranslationDirectory;
6+
import com.google.inject.Inject;
7+
import com.velocitypowered.api.event.PostOrder;
8+
import com.velocitypowered.api.event.Subscribe;
9+
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
10+
import com.velocitypowered.api.event.proxy.ProxyReloadEvent;
11+
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
12+
import com.velocitypowered.api.plugin.annotation.DataDirectory;
13+
import com.velocitypowered.api.proxy.ProxyServer;
14+
import com.velocitypowered.api.proxy.server.RegisteredServer;
615
import net.kyori.adventure.key.Key;
7-
import net.md_5.bungee.api.plugin.Plugin;
816
import net.okocraft.serverconnector.command.SlashServerCommand;
917
import net.okocraft.serverconnector.config.ConfigValues;
1018
import net.okocraft.serverconnector.listener.FirstJoinListener;
1119
import net.okocraft.serverconnector.listener.PlayerListener;
12-
import net.okocraft.serverconnector.listener.ServerListener;
13-
import net.okocraft.serverconnector.listener.SnapshotClientListener;
14-
import net.okocraft.serverconnector.util.AudienceUtil;
1520
import org.jetbrains.annotations.NotNull;
21+
import org.slf4j.Logger;
1622

1723
import java.io.IOException;
1824
import java.nio.file.Path;
25+
import java.util.ArrayList;
26+
import java.util.List;
1927
import java.util.Locale;
2028

21-
public final class ServerConnectorPlugin extends Plugin {
29+
public final class ServerConnectorPlugin {
2230

23-
private final YamlConfiguration config = YamlConfiguration.create(getDataFolder().toPath().resolve("config.yml"));
24-
private final TranslationDirectory translationDirectory =
25-
TranslationDirectory.newBuilder()
26-
.setDirectory(getDataFolder().toPath().resolve("languages"))
27-
.setKey(Key.key("serverconnector", "language"))
28-
.setDefaultLocale(Locale.ENGLISH)
29-
.onDirectoryCreated(this::saveDefaultLanguages)
30-
.build();
31+
private final ProxyServer proxy;
32+
private final Logger logger;
33+
private final YamlConfiguration config;
34+
private final TranslationDirectory translationDirectory;
35+
private final List<SlashServerCommand> registeredSlashServerCommands = new ArrayList<>();
3136

3237
private FirstJoinListener firstJoinListener;
3338

34-
@Override
35-
public void onLoad() {
39+
@Inject
40+
public ServerConnectorPlugin(@NotNull ProxyServer proxy, @NotNull Logger logger,
41+
@DataDirectory Path dataDirectory) {
42+
this.proxy = proxy;
43+
this.logger = logger;
44+
45+
this.config = YamlConfiguration.create(dataDirectory.resolve("config.yml"));
46+
this.translationDirectory =
47+
TranslationDirectory.newBuilder()
48+
.setDirectory(dataDirectory.resolve("languages"))
49+
.setKey(Key.key("serverconnector", "language"))
50+
.setDefaultLocale(Locale.ENGLISH)
51+
.onDirectoryCreated(this::saveDefaultLanguages)
52+
.build();
53+
}
54+
55+
@Subscribe(order = PostOrder.FIRST)
56+
public void onEnable(ProxyInitializeEvent ignored) {
3657
try {
3758
ResourceUtils.copyFromClassLoaderIfNotExists(getClass().getClassLoader(), "config.yml", config.getPath());
3859
config.load();
@@ -45,74 +66,74 @@ public void onLoad() {
4566
} catch (IOException e) {
4667
throw new IllegalStateException("Failed to load languages", e);
4768
}
48-
}
49-
50-
@Override
51-
public void onEnable() {
52-
AudienceUtil.init(this);
5369

5470
enablePlayerListener();
55-
enableServerListener();
5671
enableSlashServer();
5772
enableFirstJoinDetector();
58-
enableSnapshotListenerIfConfigured();
5973
}
6074

61-
@Override
62-
public void onDisable() {
75+
@Subscribe(order = PostOrder.LAST)
76+
public void onDisable(ProxyShutdownEvent ignored) {
6377
if (firstJoinListener != null) {
6478
firstJoinListener.unsubscribe();
6579
}
6680

67-
getProxy().getPluginManager().unregisterListeners(this);
68-
getProxy().getPluginManager().unregisterCommands(this);
81+
getProxy().getEventManager().unregisterListeners(this);
82+
83+
registeredSlashServerCommands.forEach(SlashServerCommand::unregister);
84+
6985
translationDirectory.unload();
7086
}
7187

88+
@Subscribe
89+
public void onReload(ProxyReloadEvent ignored) {
90+
if (!registeredSlashServerCommands.isEmpty()) {
91+
registeredSlashServerCommands.forEach(SlashServerCommand::unregister);
92+
enableSlashServer();
93+
}
94+
}
95+
96+
public @NotNull ProxyServer getProxy() {
97+
return proxy;
98+
}
99+
100+
public @NotNull Logger getLogger() {
101+
return logger;
102+
}
103+
72104
public @NotNull YamlConfiguration getConfig() {
73105
return config;
74106
}
75107

76108
private void enablePlayerListener() {
77109
var playerListener = new PlayerListener(this);
78-
getProxy().getPluginManager().registerListener(this, playerListener);
79-
}
80-
81-
private void enableServerListener() {
82-
var serverListener = new ServerListener(this);
83-
getProxy().getPluginManager().registerListener(this, serverListener);
110+
getProxy().getEventManager().register(this, playerListener);
84111
}
85112

86113
public void enableSlashServer() {
87-
getProxy().getServers().values().stream()
88-
.map(SlashServerCommand::new)
89-
.forEach(cmd -> getProxy().getPluginManager().registerCommand(this, cmd));
114+
getProxy().getAllServers().stream()
115+
.map(server -> new SlashServerCommand(this, server))
116+
.forEach(command -> {
117+
command.register();
118+
registeredSlashServerCommands.add(command);
119+
});
90120
}
91121

92122
private void enableFirstJoinDetector() {
93-
if (getProxy().getPluginManager().getPlugin("LuckPerms") != null && config.get(ConfigValues.SEND_FIRST_JOIN_MESSAGE)) {
123+
if (getProxy().getPluginManager().getPlugin("LuckPerms").isPresent() && config.get(ConfigValues.SEND_FIRST_JOIN_MESSAGE)) {
94124
firstJoinListener = new FirstJoinListener(this);
95125
}
96126
}
97127

98-
private void enableSnapshotListenerIfConfigured() {
99-
if (config.get(ConfigValues.ENABLE_SNAPSHOT_SERVER)) {
100-
var snapshotListener = new SnapshotClientListener(this);
101-
getProxy().getPluginManager().registerListener(this, snapshotListener);
102-
}
103-
}
104-
105128
private void saveDefaultLanguages(@NotNull Path directory) throws IOException {
106-
var jarPath = getFile().toPath();
107-
108129
var defaultFileName = "en.yml";
109130
var defaultFile = directory.resolve(defaultFileName);
110131

111-
ResourceUtils.copyFromJarIfNotExists(jarPath, defaultFileName, defaultFile);
132+
ResourceUtils.copyFromClassLoaderIfNotExists(getClass().getClassLoader(), defaultFileName, defaultFile);
112133

113134
var japaneseFileName = "ja_JP.yml";
114135
var japaneseFile = directory.resolve(japaneseFileName);
115136

116-
ResourceUtils.copyFromJarIfNotExists(jarPath, japaneseFileName, japaneseFile);
137+
ResourceUtils.copyFromClassLoaderIfNotExists(getClass().getClassLoader(), japaneseFileName, japaneseFile);
117138
}
118139
}
Lines changed: 69 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,111 @@
11
package net.okocraft.serverconnector.command;
22

3-
import net.md_5.bungee.api.CommandSender;
4-
import net.md_5.bungee.api.ProxyServer;
5-
import net.md_5.bungee.api.config.ServerInfo;
6-
import net.md_5.bungee.api.connection.ProxiedPlayer;
7-
import net.md_5.bungee.api.plugin.Command;
8-
import net.md_5.bungee.api.plugin.TabExecutor;
3+
import com.velocitypowered.api.command.CommandMeta;
4+
import com.velocitypowered.api.command.SimpleCommand;
5+
import com.velocitypowered.api.proxy.Player;
6+
import com.velocitypowered.api.proxy.ServerConnection;
7+
import com.velocitypowered.api.proxy.server.RegisteredServer;
8+
import com.velocitypowered.api.proxy.server.ServerInfo;
9+
import net.okocraft.serverconnector.ServerConnectorPlugin;
910
import net.okocraft.serverconnector.lang.Messages;
10-
import net.okocraft.serverconnector.util.AudienceUtil;
1111

1212
import java.util.Collections;
13-
import java.util.Locale;
13+
import java.util.List;
14+
import java.util.function.Predicate;
1415
import java.util.stream.Collectors;
1516

16-
public class SlashServerCommand extends Command implements TabExecutor {
17+
public class SlashServerCommand implements SimpleCommand {
1718

1819
private static final String GLOBAL_OTHER_PLAYER_PERMISSION = "serverconnector.slashserver.other-players";
1920

20-
private final ServerInfo server;
21+
private final ServerConnectorPlugin plugin;
22+
private final RegisteredServer server;
23+
private final ServerInfo serverInfo;
24+
private final String permission;
25+
private final String otherPermission;
26+
private final CommandMeta meta;
27+
28+
public SlashServerCommand(ServerConnectorPlugin plugin, RegisteredServer server) {
29+
this.plugin = plugin;
30+
this.server = server;
31+
this.serverInfo = server.getServerInfo();
32+
this.permission = "serverconnector.slashserver." + serverInfo.getName();
33+
this.otherPermission = permission + ".other";
34+
this.meta = plugin.getProxy().getCommandManager().metaBuilder(serverInfo.getName()).plugin(plugin).build();
35+
}
2136

22-
public SlashServerCommand(ServerInfo serverInfo) {
23-
super(serverInfo.getName(), "serverconnector.slashserver." + serverInfo.getName());
24-
server = serverInfo;
37+
public void register() {
38+
plugin.getProxy().getCommandManager().register(meta, this);
2539
}
2640

27-
@Override
28-
public void execute(CommandSender sender, String[] args) {
29-
var audience = AudienceUtil.sender(sender);
41+
public void unregister() {
42+
plugin.getProxy().getCommandManager().unregister(meta);
43+
}
3044

31-
if (!(sender instanceof ProxiedPlayer)) {
32-
audience.sendMessage(Messages.SLASH_SERVER_ONLY_PLAYER);
33-
return;
34-
}
45+
@Override
46+
public void execute(Invocation invocation) {
47+
var sender = invocation.source();
3548

36-
if (!sender.hasPermission(getPermission())) {
37-
audience.sendMessage(Messages.SLASH_SERVER_NO_PERMISSION.apply(getPermission()));
49+
if (!sender.hasPermission(permission)) {
50+
sender.sendMessage(Messages.SLASH_SERVER_NO_PERMISSION.apply(permission));
3851
return;
3952
}
4053

41-
ProxiedPlayer player;
42-
boolean otherPlayer;
54+
Player target;
55+
var args = invocation.arguments();
4356

44-
if (0 < args.length && !sender.getName().equalsIgnoreCase(args[0])) {
45-
var permission = getPermission() + ".other";
46-
if (!sender.hasPermission(GLOBAL_OTHER_PLAYER_PERMISSION) && !sender.hasPermission(permission)) {
47-
audience.sendMessage(Messages.SLASH_SERVER_NO_PERMISSION.apply(permission));
57+
if (0 < args.length) {
58+
if (!sender.hasPermission(GLOBAL_OTHER_PLAYER_PERMISSION) && !sender.hasPermission(otherPermission)) {
59+
sender.sendMessage(Messages.SLASH_SERVER_NO_PERMISSION.apply(otherPermission));
4860
return;
4961
}
5062

51-
player = ProxyServer.getInstance().getPlayer(args[0]);
52-
otherPlayer = true;
63+
target = plugin.getProxy().getPlayer(args[0]).orElse(null);
5364

54-
if (player == null) {
55-
audience.sendMessage(Messages.SLASH_SERVER_PLAYER_NOT_FOUND.apply(args[0]));
65+
if (target == null) {
66+
sender.sendMessage(Messages.SLASH_SERVER_PLAYER_NOT_FOUND.apply(args[0]));
5667
return;
5768
}
5869
} else {
59-
player = (ProxiedPlayer) sender;
60-
otherPlayer = false;
70+
if (sender instanceof Player) {
71+
target = (Player) sender;
72+
} else {
73+
sender.sendMessage(Messages.SLASH_SERVER_ONLY_PLAYER);
74+
return;
75+
}
6176
}
6277

63-
var currentServerName = player.getServer().getInfo().getName();
78+
var currentServer = target.getCurrentServer().map(ServerConnection::getServerInfo);
6479

65-
if (currentServerName.equalsIgnoreCase(server.getName())) {
66-
audience.sendMessage(Messages.SLASH_SERVER_ALREADY_CONNECTED);
80+
if (serverInfo.equals(currentServer.orElse(null))) {
81+
sender.sendMessage(Messages.SLASH_SERVER_ALREADY_CONNECTED);
6782
return;
6883
}
6984

70-
if (!server.canAccess(player)) {
71-
audience.sendMessage(Messages.SLASH_SERVER_COULD_NOT_CONNECT.apply(server.getName()));
72-
return;
73-
}
85+
target.createConnectionRequest(server).fireAndForget();
7486

75-
if (otherPlayer) {
76-
AudienceUtil.player(player).sendMessage(Messages.SLASH_SERVER_CONNECTING.apply(server.getName()));
77-
audience.sendMessage(Messages.SLASH_SERVER_CONNECTING_OTHER.apply(player, server.getName()));
87+
if (sender != target) {
88+
target.sendMessage(Messages.SLASH_SERVER_CONNECTING.apply(serverInfo.getName()));
89+
sender.sendMessage(Messages.SLASH_SERVER_CONNECTING_OTHER.apply(target, serverInfo.getName()));
7890
} else {
79-
audience.sendMessage(Messages.SLASH_SERVER_CONNECTING.apply(server.getName()));
91+
sender.sendMessage(Messages.SLASH_SERVER_CONNECTING.apply(serverInfo.getName()));
8092
}
81-
82-
player.connect(server);
8393
}
8494

8595
@Override
86-
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
87-
if (args.length == 1 &&
88-
(sender.hasPermission(GLOBAL_OTHER_PLAYER_PERMISSION) || sender.hasPermission(getPermission() + ".other"))) {
89-
var filter = args[0].toLowerCase(Locale.ENGLISH);
90-
return ProxyServer.getInstance()
91-
.getPlayers()
92-
.stream()
93-
.map(CommandSender::getName)
94-
.map(name -> name.toLowerCase(Locale.ENGLISH))
95-
.filter(name -> !name.equalsIgnoreCase(sender.getName()))
96-
.filter(name -> name.startsWith(filter))
96+
public List<String> suggest(Invocation invocation) {
97+
var sender = invocation.source();
98+
var args = invocation.arguments();
99+
100+
if (args.length <= 1 && (sender.hasPermission(GLOBAL_OTHER_PLAYER_PERMISSION) || sender.hasPermission(otherPermission))) {
101+
return plugin.getProxy().getAllPlayers().stream()
102+
.filter(Predicate.not(sender::equals))
103+
.filter(Predicate.not(player -> serverInfo.equals(player.getCurrentServer().map(ServerConnection::getServerInfo).orElse(null))))
104+
.map(Player::getUsername)
105+
.filter(name -> args.length == 0 || name.regionMatches(true, 0, args[0], 0, args[0].length()))
97106
.collect(Collectors.toList());
98-
} else {
99-
return Collections.emptyList();
100107
}
108+
109+
return Collections.emptyList();
101110
}
102111
}

src/main/java/net/okocraft/serverconnector/lang/Messages.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import com.github.siroshun09.translationloader.argument.DoubleArgument;
44
import com.github.siroshun09.translationloader.argument.SingleArgument;
5+
import com.velocitypowered.api.proxy.Player;
56
import net.kyori.adventure.text.Component;
67
import net.kyori.adventure.text.TranslatableComponent;
7-
import net.md_5.bungee.api.connection.ProxiedPlayer;
88

99
import java.util.function.BiFunction;
1010
import java.util.function.Function;
@@ -145,12 +145,12 @@ public final class Messages {
145145
)
146146
.build();
147147

148-
public static final DoubleArgument<ProxiedPlayer, String> SLASH_SERVER_CONNECTING_OTHER =
148+
public static final DoubleArgument<Player, String> SLASH_SERVER_CONNECTING_OTHER =
149149
(player, serverName) ->
150150
PREFIX.append(
151151
translatable()
152152
.key("serverconnector.command.slash-server.connecting-other")
153-
.args(text(player.getName(), AQUA), text(serverName, AQUA))
153+
.args(text(player.getUsername(), AQUA), text(serverName, AQUA))
154154
.color(GRAY)
155155
.build()
156156
);

0 commit comments

Comments
 (0)