diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 79a67bc..d3f6889 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,7 +34,7 @@ jobs: run: ./gradlew build -PVERSION="${{ env.VERSION }}" - name: Archive artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: geyser-voice-artifact path: build/libs/ @@ -52,7 +52,7 @@ jobs: uses: actions/checkout@v2 - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: geyser-voice-artifact path: build/libs/ @@ -78,3 +78,19 @@ jobs: build/libs/GeyserVoice-*.jar env: GITHUB_REPOSITORY: AvionBlock/GeyserVoice + + - name: Create Modrinth release + if: github.event.inputs.status == 'stable' + uses: dsx137/modrinth-release-action@main + env: + MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} + with: + name: GeyserVoice ${{ github.event.inputs.tag }} + project_id: WtPu56Wa + loaders: paper, spigot, bukkit, purpur, velocity, bungeecord + game_versions: 1.20.2:1.21.4 + version_number: ${{ github.event.inputs.tag }} + featured: github.event.inputs.status == 'stable' + version_type: ${{ github.event.inputs.status == 'stable' && 'release' || 'beta' }} + files: | + ./build/libs/GeyserVoice-*.jar diff --git a/src/main/java/io/greitan/avion/bungeecord/GeyserVoice.java b/src/main/java/io/greitan/avion/bungeecord/GeyserVoice.java index 4f4387f..317e558 100644 --- a/src/main/java/io/greitan/avion/bungeecord/GeyserVoice.java +++ b/src/main/java/io/greitan/avion/bungeecord/GeyserVoice.java @@ -7,6 +7,8 @@ import net.md_5.bungee.config.ConfigurationProvider; import net.md_5.bungee.config.Configuration; import net.md_5.bungee.config.YamlConfiguration; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.connection.ProxiedPlayer; import com.fasterxml.jackson.databind.ObjectMapper; @@ -97,7 +99,8 @@ public void reload() { port = getConfig().getInt("config.port"); serverKey = getConfig().getString("config.server-key"); - isConnected = connect(true); + if (getConfig().getBoolean("config.auto-reconnect")) + isConnected = reconnect(true); int positionTaskInterval = getConfig().getInt("config.voice.position-task-interval", 1); taskRunner.cancel(); @@ -112,26 +115,52 @@ public void reload() { updateSettings(proximityDistance, proximityToggle, voiceEffects); } + /** + * Connects to a new server. + * + * @param host The host to connect to. + * @param port The port to connect to. + * @param serverKey The server key. + * @return True if connected successfully, otherwise false. + */ + public Boolean connect(String host, int port, String serverKey) { + if (Objects.nonNull(host) && Objects.nonNull(serverKey)) { + getConfig().set("config.host", host); + getConfig().set("config.port", port); + getConfig().set("config.server-key", serverKey); + saveConfig(); + reloadConfig(); + reload(); + + return isConnected; + } else { + Logger.warn(Language.getMessage(lang, "plugin-connect-invalid-data")); + return false; + } + } + /** * Connects to the server. * * @param force Indicates whether to force a connection. * @return True if connected successfully, otherwise false. */ - public Boolean connect(Boolean force) { + public Boolean reconnect(Boolean force) { if (isConnected && !force) return true; - isConnected = false; + if (isConnected) { + disconnect("Reconnecting to another server."); + } if (Objects.nonNull(host) && Objects.nonNull(serverKey)) { String link = "http://" + host + ":" + port; String Token = network.sendLoginRequest(link, serverKey); if (Objects.nonNull(Token)) { - Logger.info(Language.getMessage(lang, "plugin-connect-connect")); + Logger.info(Language.getMessage(lang, "plugin-connect-connected")); isConnected = true; token = Token; } else { - Logger.warn(Language.getMessage(lang, "plugin-connect-disconnect")); + Logger.warn(Language.getMessage(lang, "plugin-connect-failed")); } return isConnected; } else { @@ -140,6 +169,39 @@ public Boolean connect(Boolean force) { } } + /** + * Disconnects from the server. + * + * @param reason The reason why we disconnected + */ + public void disconnect(String reason) { + if (!isConnected) + return; + + if (Objects.nonNull(host) && Objects.nonNull(serverKey)) { + String link = "http://" + host + ":" + port; + network.sendLogoutRequest(link, token); + isConnected = false; + + String disconnectMessage = Language.getMessage(lang, "plugin-connection-disconnect").replace("$reason", reason); + Logger.info(disconnectMessage); + + boolean sendVoipDisconnectMessage = getConfig().getBoolean("config.voice.send-voip-disconnect-message"); + if (sendVoipDisconnectMessage) { + getProxy().broadcast(new ComponentBuilder(disconnectMessage).color(ChatColor.YELLOW).create()); + } + } else { + Logger.warn(Language.getMessage(lang, "plugin-connect-invalid-data")); + } + } + + /** + * Disconnects from the server. + */ + public void disconnect() { + disconnect("N.A."); + } + /** * Binds a player to the voice chat server. * @@ -150,6 +212,11 @@ public Boolean connect(Boolean force) { public Boolean bind(int playerKey, ProxiedPlayer player, int tries) { if (!isConnected || Objects.isNull(host) || Objects.isNull(serverKey)) return false; + + if (playerBinds.containsKey(player.getName()) && playerBinds.get(player.getName())) { + return true; + } + String link = "http://" + host + ":" + port; getConfig().set("config.players." + player.getName(), playerKey); @@ -162,13 +229,28 @@ public Boolean bind(int playerKey, ProxiedPlayer player, int tries) { if (result == "SUCCESS") { playerBinds.put(player.getName(), true); messageHandler.sendPlayerBindSync(player); - return true; - } else { - if (result == "Invalid Token!" && tries == 0) { - Logger.info("Invalid Token detected, reconnecting..."); - isConnected = connect(true); - return bind(playerKey, player, 1); + + Logger.info(Language.getMessage(lang, "player-binded").replace("$player",player.getName())); + + boolean sendBindedMessage = getConfig().getBoolean("config.voice.send-binded-message"); + if (sendBindedMessage) { + getProxy().broadcast( + new ComponentBuilder(player.getName()).bold(true) + .append( + new ComponentBuilder( + Language.getMessage(lang, "player-binded") + .replace("$player", "") + ) + .color(ChatColor.DARK_GREEN) + .create() + ).create() + ); } + return true; + } else if (result == "Invalid Token!" && tries == 0) { + Logger.info("Invalid Token detected, reconnecting..."); + isConnected = reconnect(true); + return bind(playerKey, player, 1); } } messageHandler.sendPlayerBindSync(player); @@ -179,6 +261,60 @@ public Boolean bind(int playerKey, ProxiedPlayer player) { return bind(playerKey, player, 0); } + /** + * Bind a fake player + * @param bindKey + * @param name + * @return + */ + public Boolean bindFake(int playerKey, String name, int tries) { + if (!isConnected || Objects.isNull(host) || Objects.isNull(serverKey)) + return false; + + if (playerBinds.containsKey(name) && playerBinds.get(name)) { + return true; + } + + String link = "http://" + host + ":" + port; + + String result = network.sendBindRequest(link, token, playerKey, String.format("%0", playerKey), name); + playerBinds.put(name, false); + if (result != null) { + if (result == "SUCCESS") { + playerBinds.put(name, true); + // messageHandler.sendPlayerBindSync(player); + + Logger.info(Language.getMessage(lang, "player-binded").replace("$player", name)); + + boolean sendBindedMessage = getConfig().getBoolean("config.voice.send-binded-message"); + if (sendBindedMessage) { + getProxy().broadcast( + new ComponentBuilder(name).bold(true) + .append( + new ComponentBuilder( + Language.getMessage(lang, "player-binded") + .replace("$player", "") + ) + .color(ChatColor.DARK_GREEN) + .create() + ).create() + ); + } + return true; + } else if (result == "Invalid Token!" && tries == 0) { + Logger.info("Invalid Token detected, reconnecting..."); + isConnected = reconnect(true); + return bindFake(playerKey, name, 1); + } + } + // messageHandler.sendPlayerBindSync(player); + return false; + } + + public Boolean bindFake(int playerKey, String name) { + return bindFake(playerKey, name, 0); + } + /** * Disconnects a player from the voice chat server. * @@ -198,7 +334,7 @@ public Boolean disconnectPlayer(ProxiedPlayer player, int tries) { return true; } else if (result == "Invalid Token!" && tries == 0) { Logger.info("Invalid Token detected, reconnecting..."); - isConnected = connect(true); + isConnected = reconnect(true); return disconnectPlayer(player, 1); } } diff --git a/src/main/java/io/greitan/avion/bungeecord/commands/VoiceCommand.java b/src/main/java/io/greitan/avion/bungeecord/commands/VoiceCommand.java index 9aaddbe..d0011de 100644 --- a/src/main/java/io/greitan/avion/bungeecord/commands/VoiceCommand.java +++ b/src/main/java/io/greitan/avion/bungeecord/commands/VoiceCommand.java @@ -1,10 +1,5 @@ package io.greitan.avion.bungeecord.commands; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -import java.lang.NumberFormatException; - import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.plugin.TabExecutor; @@ -15,159 +10,88 @@ import io.greitan.avion.bungeecord.GeyserVoice; import io.greitan.avion.bungeecord.utils.Language; +import io.greitan.avion.common.commands.BaseVoiceCommand; +import io.greitan.avion.common.utils.IntegerOperation; +import io.greitan.avion.common.utils.StringOperation; +import io.greitan.avion.common.utils.DoubleStringOperation; +import io.greitan.avion.common.utils.EmptyOperation; public class VoiceCommand extends Command implements TabExecutor { + private final BaseVoiceCommand voiceCommand; private final GeyserVoice plugin; private final String lang; - private boolean isConnected = false; // Get the plugin and lang interfaces. public VoiceCommand(GeyserVoice plugin, String lang) { super("voice"); + this.voiceCommand = new BaseVoiceCommand(plugin); this.plugin = plugin; this.lang = lang; } @Override public void execute(CommandSender sender, String[] args) { - isConnected = plugin.isConnected(); - - if (sender instanceof ProxiedPlayer) { - ProxiedPlayer player = (ProxiedPlayer) sender; - if (args.length >= 1) { - // Bind command - bind player. - if (args[0].equalsIgnoreCase("bind") && player.hasPermission("voice.bind") && isConnected) { - if (args.length >= 2 && Objects.nonNull(args[1])) { - int bindKey; - try { - bindKey = Integer.parseInt(args[1]); - } catch (NumberFormatException e) { - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-invalid-args")) - .color(ChatColor.RED).create()); - return; - } - /* - * if (bindKey == 0) { - * player.sendMessage("Here is your open key!"); - * return; - * } - */ - Boolean isBound = plugin.bind(bindKey, player); - if (isBound) { - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-bind-connect")) - .color(ChatColor.AQUA).create()); - } else { - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-bind-disconnect")) - .color(ChatColor.RED).create()); - } - } else { - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-invalid-args")) - .color(ChatColor.RED).create()); - } + this.voiceCommand.onCommand( + args, + plugin.isConnected(), + sender instanceof ProxiedPlayer, + new StringOperation() { + @Override + public boolean execute(String permission) { + if (sender instanceof ProxiedPlayer) + return sender.hasPermission(permission); + else + return true; } - // Setup command - setup the configuration. - else if (args[0].equalsIgnoreCase("setup") && player.hasPermission("voice.setup")) { - String newHost = args[1]; - String newPort = args[2]; - String newKey = args[3]; - - if (Objects.nonNull(newHost) && Objects.nonNull(newPort) && Objects.nonNull(newKey)) { - GeyserVoice.getConfig().set("config.host", newHost); - GeyserVoice.getConfig().set("config.port", newPort); - GeyserVoice.getConfig().set("config.server-key", newKey); - plugin.saveConfig(); - plugin.reloadConfig(); - plugin.reload(); - - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-setup-success")) - .color(ChatColor.AQUA).create()); - } else { - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-setup-invalid-data")) - .color(ChatColor.RED).create()); - } - } - // Connect command - connect to the VoiceCraft server. - else if (args[0].equalsIgnoreCase("connect") && player.hasPermission("voice.connect")) { - if (Objects.nonNull(args[1])) { - Boolean force = Boolean.valueOf(args[1]); - - Boolean connected = plugin.connect(force); - if (connected) { - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "plugin-connect-connect")) - .color(ChatColor.AQUA).create()); - } else { - player.sendMessage( - new ComponentBuilder(Language.getMessage(lang, "plugin-connect-disconnect")) - .color(ChatColor.RED).create()); - } - } else { - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-invalid-args")) - .color(ChatColor.RED).create()); - } + }, + new DoubleStringOperation() { + @Override + public void execute(String text, String rawColor) { + ChatColor color = ChatColor.RED; + if (rawColor == "red") color = ChatColor.RED; + else if (rawColor == "aqua") color = ChatColor.AQUA; + else if (rawColor == "green") color = ChatColor.GREEN; + else if (rawColor == "yellow") color = ChatColor.YELLOW; + + var message = new ComponentBuilder(Language.getMessage(lang, text)).color(color).create(); + if (sender instanceof ProxiedPlayer) + sender.sendMessage(message); + else + plugin.Logger.log(message); } - // Reload command - reload the configs. - else if (args[0].equalsIgnoreCase("reload") && player.hasPermission("voice.reload")) { - plugin.reload(); - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-reload")) - .color(ChatColor.GREEN).create()); - } else if (args[0].equalsIgnoreCase("settings") && player.hasPermission("voice.settings")) { - int proximityDistance = 1; - Boolean proximityToggle = true; - Boolean voiceEffects = true; - - plugin.updateSettings(proximityDistance, proximityToggle, voiceEffects); + }, + new IntegerOperation() { + @Override + public boolean execute(int key) { + if (sender instanceof ProxiedPlayer) { + ProxiedPlayer player = (ProxiedPlayer) sender; + return plugin.bind(key, player); + } + return false; } - // Command select invalid. - else { - player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-invalid-args")) - .color(ChatColor.RED).create()); + }, + new EmptyOperation() { + @Override + public boolean execute() { + if (sender instanceof ProxiedPlayer) { + ProxiedPlayer player = (ProxiedPlayer) sender; + GeyserVoice.getConfig().set("config.players." + player.getName(), null); + return true; + } + return false; } } - } - // Commands runned by console. - else if (args.length >= 1) { - // Reload command - reload the configs. - if (args[0].equalsIgnoreCase("reload")) { - plugin.reload(); - plugin.Logger.log( - new ComponentBuilder(Language.getMessage(lang, "cmd-reload")).color(ChatColor.GREEN).create()); - } - // Command not for console. - else { - sender.sendMessage(new ComponentBuilder(Language.getMessage(lang, "cmd-not-player")) - .color(ChatColor.RED).create()); - } - } - // Invalid command arguments. - else { - sender.sendMessage( - new ComponentBuilder(Language.getMessage(lang, "cmd-invalid-args")).color(ChatColor.RED).create()); - } + ); } @Override public Iterable onTabComplete(CommandSender sender, String[] args) { - List completions = List.of(); - - // Main command arguments. - if (args.length == 1) { - List options = List.of("bind", "setup", "connect", "reload"); - completions = options.stream().filter(val -> val.startsWith(args[0])).collect(Collectors.toList()); - } - - // Setup command arguments. - if (args.length == 2 && args[0].equalsIgnoreCase("setup")) { - List options = List.of("host port key"); - completions = options.stream().filter(val -> val.startsWith(args[1])).collect(Collectors.toList()); - } - - // Connect command arguments. - if (args.length == 2 && args[0].equalsIgnoreCase("connect")) { - List options = List.of("true", "false"); - completions = options.stream().filter(val -> val.startsWith(args[1])).collect(Collectors.toList()); - } - - return completions; + return voiceCommand.onTabComplete(args, new StringOperation() { + @Override + public boolean execute(String permission) { + return sender.hasPermission(permission); + } + }); } } diff --git a/src/main/java/io/greitan/avion/bungeecord/listeners/PlayerJoinHandler.java b/src/main/java/io/greitan/avion/bungeecord/listeners/PlayerJoinHandler.java index 0ee52bf..9421cd8 100644 --- a/src/main/java/io/greitan/avion/bungeecord/listeners/PlayerJoinHandler.java +++ b/src/main/java/io/greitan/avion/bungeecord/listeners/PlayerJoinHandler.java @@ -5,11 +5,12 @@ import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.ServerConnectedEvent; -import io.greitan.avion.bungeecord.GeyserVoice; -import io.greitan.avion.bungeecord.utils.Language; import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.ChatColor; +import io.greitan.avion.bungeecord.GeyserVoice; +import io.greitan.avion.bungeecord.utils.Language; + import java.util.Objects; public class PlayerJoinHandler implements Listener { @@ -43,19 +44,16 @@ public void onPlayerConnect(ServerConnectedEvent event) { } private void handleAutoBind(int playerBindKey, ProxiedPlayer player) { - boolean isBound = plugin.bind(playerBindKey, player); + player.sendMessage( + new ComponentBuilder(Language.getMessage(lang, "plugin-autobind-enabled")).color(ChatColor.GREEN) + .append(new ComponentBuilder(" ").create()) + .append( + new ComponentBuilder(Language.getMessage(lang, "plugin-autobind-binding")).color(ChatColor.YELLOW).create() + ).create()); - if (isBound) { - String playerName = player.getName(); - String connectMessage = Language.getMessage(lang, "player-connect").replace("$player", playerName); - - plugin.Logger.info(connectMessage); + boolean isBound = plugin.bind(playerBindKey, player); - boolean sendConnectMessage = GeyserVoice.getConfig().getBoolean("config.voice.send-connect-message"); - if (sendConnectMessage) { - plugin.getProxy().broadcast(new ComponentBuilder(connectMessage).color(ChatColor.YELLOW).create()); - } - } else { + if (!isBound) { player.sendMessage(new ComponentBuilder(Language.getMessage(lang, "plugin-autobind-failed")) .color(ChatColor.RED).create()); } diff --git a/src/main/java/io/greitan/avion/bungeecord/tasks/PositionsTask.java b/src/main/java/io/greitan/avion/bungeecord/tasks/PositionsTask.java index ea0872a..3d68b3a 100644 --- a/src/main/java/io/greitan/avion/bungeecord/tasks/PositionsTask.java +++ b/src/main/java/io/greitan/avion/bungeecord/tasks/PositionsTask.java @@ -105,7 +105,7 @@ private Boolean Reconnect() { plugin.Logger.warn(Language.getMessage(lang, "plugin-connection-reconnecting-attempt").replace("$attempt", ReconnectRetries.toString())); - if (plugin.connect(true)) { + if (plugin.reconnect(true)) { plugin.Logger.warn(Language.getMessage(lang, "plugin-connection-reconnecting-success")); if (GeyserVoice.getConfig().getBoolean("config.voice.send-connection-lost-message")) { diff --git a/src/main/java/io/greitan/avion/common/BaseGeyserVoice.java b/src/main/java/io/greitan/avion/common/BaseGeyserVoice.java index 89b7a3c..e4b70be 100644 --- a/src/main/java/io/greitan/avion/common/BaseGeyserVoice.java +++ b/src/main/java/io/greitan/avion/common/BaseGeyserVoice.java @@ -19,12 +19,51 @@ public interface BaseGeyserVoice { abstract public void reload(); /** - * Connects to the server. + * Connects to a new server. + * + * @param host The host to connect to. + * @param port The port to connect to. + * @param serverKey The server key. + * @return True if connected successfully, otherwise false. + */ + abstract public Boolean connect(String host, int port, String serverKey); + + /** + * Reconnects to the server. * * @param force Indicates whether to force a connection. * @return True if connected successfully, otherwise false. */ - abstract public Boolean connect(Boolean force); + abstract public Boolean reconnect(Boolean force); + + /** + * Disconnects from the server. + * + * @param reason The reason why we disconnected + */ + abstract public void disconnect(String reason); + + /** + * Disconnects from the server. + */ + abstract public void disconnect(); + + /** + * Bind a fake player + * @param bindKey + * @param name + * @param tries + * @return + */ + abstract public Boolean bindFake(int bindKey, String name, int tries); + + /** + * Bind a fake player + * @param bindKey + * @param name + * @return + */ + abstract public Boolean bindFake(int bindKey, String name); /** * Updates the voice chat settings. @@ -42,4 +81,7 @@ public interface BaseGeyserVoice { abstract public void setNotConnected(); abstract public void saveResource(String resourcePath); + + abstract public void saveConfig(); + abstract public void reloadConfig(); } diff --git a/src/main/java/io/greitan/avion/common/commands/BaseVoiceCommand.java b/src/main/java/io/greitan/avion/common/commands/BaseVoiceCommand.java new file mode 100644 index 0000000..8acbd9f --- /dev/null +++ b/src/main/java/io/greitan/avion/common/commands/BaseVoiceCommand.java @@ -0,0 +1,219 @@ +package io.greitan.avion.common.commands; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.lang.NumberFormatException; + +import io.greitan.avion.common.BaseGeyserVoice; +import io.greitan.avion.common.utils.IntegerOperation; +import io.greitan.avion.common.utils.StringOperation; +import io.greitan.avion.common.utils.DoubleStringOperation; +import io.greitan.avion.common.utils.EmptyOperation; + +public class BaseVoiceCommand { + private final BaseGeyserVoice plugin; + + // Get the plugin and lang interfaces. + public BaseVoiceCommand(T plugin) { + this.plugin = plugin; + } + + public boolean onCommand(String[] args, boolean isConnected, boolean isPlayer, StringOperation hasPermission, DoubleStringOperation sendMessage, IntegerOperation bindUser, EmptyOperation clearAutoBind) { + if (args.length >= 1) { + // Connect command - connect to the server. + if (args[0].equalsIgnoreCase("connect") && hasPermission.execute("voice.connect")) { + if (args.length >= 4) { + String newHost = args[1]; + String newPortString = args[2]; + Integer newPort = -1; + String newKey = args[3]; + try { + if (Objects.nonNull(newPortString)) { + newPort = Integer.parseInt(newPortString); + } + } catch (NumberFormatException e) { + newPort = -1; + } + + if (Objects.nonNull(newHost) && Objects.nonNull(newPortString) && Objects.nonNull(newKey) && newPort != -1) { + sendMessage.execute("plugin-connect-connecting", "yellow"); + Boolean connected = plugin.connect(newHost, newPort, newKey); + + // Console will always get a message, so only send message when player sending command! + if (isPlayer) { + if (connected) + sendMessage.execute("plugin-connect-connected", "green"); + else + sendMessage.execute("plugin-connect-failed", "red"); + } + return true; + } + } + sendMessage.execute("commands.connect.invalid-args", "red"); + } + // Reconnect command - (re)connect to the VoiceCraft server. + else if (args[0].equalsIgnoreCase("reconnect") && hasPermission.execute("voice.reconnect")) { + Boolean force = false; + if (args.length >= 2 && Objects.nonNull(args[1])) { + force = Boolean.valueOf(args[1]); + } + + sendMessage.execute("plugin-connect-connecting", "yellow"); + Boolean connected = plugin.reconnect(force); + // Console will always get a message, so only send message when player sending command! + if (isPlayer) { + if (connected) + sendMessage.execute("plugin-connect-connected", "green"); + else + sendMessage.execute("plugin-connect-failed", "red"); + } + } + // Disconnect command - disconnect from the VoiceCraft server. + else if (args[0].equalsIgnoreCase("disconnect") && hasPermission.execute("voice.disconnect")) { + sendMessage.execute("commands.disconnect.disconnecting", "yellow"); + if (!isConnected) { + sendMessage.execute("commands.disconnect.already-disconnected", "red"); + return true; + } + + plugin.disconnect("Disconnection Request."); + } + // Settings command - allows to change settings? + else if (args[0].equalsIgnoreCase("settings") && hasPermission.execute("voice.settings") && isConnected) { + int proximityDistance = 1; + Boolean proximityToggle = true; + Boolean voiceEffects = true; + + // Show a menu? + plugin.updateSettings(proximityDistance, proximityToggle, voiceEffects); + } + // Bind command - bind player. + else if (args[0].equalsIgnoreCase("bind") && hasPermission.execute("voice.bind") && isConnected) { + if (isPlayer) { + if (args.length >= 2 && Objects.nonNull(args[1])) { + int bindKey; + try { + bindKey = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + sendMessage.execute("commands.bind.invalid-args", "red"); + return true; + } + + sendMessage.execute("commands.bind.binding", "yellow"); + Boolean isBound = bindUser.execute(bindKey); + if (isBound) { + sendMessage.execute("commands.bind.binded", "green"); + } else { + sendMessage.execute("commands.bind.failed", "red"); + } + } else { + sendMessage.execute("commands.bind.invalid-args", "red"); + } + } + // Player only command. + else { + sendMessage.execute("cmd-not-player", "red"); + } + } + // Bind fake command - bind fake player. + else if (args[0].equalsIgnoreCase("bindfake") && hasPermission.execute("voice.bindfake") && isConnected) { + if (args.length >= 3 && Objects.nonNull(args[1]) && Objects.nonNull(args[2])) { + int bindKey; + try { + bindKey = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + sendMessage.execute("commands.bind.fake-invalid-args", "red"); + return true; + } + String name = args[2]; + + sendMessage.execute("commands.bind.binding-fake", "yellow"); + Boolean isBound = plugin.bindFake(bindKey, name); + if (isBound) { + sendMessage.execute("commands.bind.binded", "green"); + } else { + sendMessage.execute("commands.bind.failed", "red"); + } + } else { + sendMessage.execute("commands.bind.fake-invalid-args", "red"); + } + } + // Update fake command - update fake player. + else if (args[0].equalsIgnoreCase("updatefake") && hasPermission.execute("voice.bindfake") && isConnected) { + if (isPlayer) { + if (args.length >= 2 && Objects.nonNull(args[1])) { + int bindKey; + try { + bindKey = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + sendMessage.execute("commands.updatefake.invalid-args", "red"); + return true; + } + + // Not doing this now, since this isn't needed nor simple to implement + sendMessage.execute("commands.updatefake.updating", "yellow"); + Boolean updated = bindKey == -1; // updateFake.execute(bindKey); + if (updated) { + sendMessage.execute("commands.updatefake.updated", "green"); + } else { + sendMessage.execute("commands.updatefake.failed", "red"); + } + } else { + sendMessage.execute("commands.updatefake.invalid-args", "red"); + } + } else { + sendMessage.execute("cmd-not-player", "red"); + } + } + // Clear auto bind command - clear auto bind player. + else if (args[0].equalsIgnoreCase("clearautobind") && hasPermission.execute("voice.bind") && isConnected) { + if (isPlayer) { + clearAutoBind.execute(); + sendMessage.execute("commands.clearautobind", "green"); + } + // Player only command. + else { + sendMessage.execute("cmd-not-player", "red"); + } + } + // Reload command - reload the configs. + else if (args[0].equalsIgnoreCase("reload") && hasPermission.execute("voice.reload")) { + plugin.reload(); + sendMessage.execute("commands.reload", "green"); + } + else { + sendMessage.execute("cmd-invalid-args", "red"); + } + } + // Invalid command arguments. + else { + sendMessage.execute("cmd-invalid-args", "red"); + } + return true; + } + + public List onTabComplete(String[] args, StringOperation hasPermission) { + List completions = List.of(); + + // Main command arguments. + if (args.length == 1 || args.length == 0) { + List options = List.of("connect", "reconnect", "disconnect", "settings", "bind", "bindfake", "updatefake", "clearautobind", "reload"); + completions = options.stream().filter(val -> (args.length == 0 || val.startsWith(args[0])) && hasPermission.execute(val == "clearautobind" ? "voice.bind" : (val == "updatefake" ? "voice.bindfake" : "voice." + val))).collect(Collectors.toList()); + } + + // Setup command arguments. + if (args.length == 2 && args[0].equalsIgnoreCase("connect") && hasPermission.execute("voice.connect")) { + List options = List.of("host port key"); + completions = options.stream().filter(val -> val.startsWith(args[1])).collect(Collectors.toList()); + } + + // Connect command arguments. + if (args.length == 2 && args[0].equalsIgnoreCase("reconnect") && hasPermission.execute("voice.reconnect")) { + List options = List.of("true", "false"); + completions = options.stream().filter(val -> val.startsWith(args[1])).collect(Collectors.toList()); + } + + return completions; + } +} diff --git a/src/main/java/io/greitan/avion/common/network/Network.java b/src/main/java/io/greitan/avion/common/network/Network.java index 71bf2b1..e1c9e94 100644 --- a/src/main/java/io/greitan/avion/common/network/Network.java +++ b/src/main/java/io/greitan/avion/common/network/Network.java @@ -11,6 +11,7 @@ import io.greitan.avion.common.network.Payloads.PacketType; import io.greitan.avion.common.network.Payloads.MCCommPacket; import io.greitan.avion.common.network.Payloads.LoginPacket; +import io.greitan.avion.common.network.Payloads.LogoutPacket; import io.greitan.avion.common.network.Payloads.AcceptPacket; import io.greitan.avion.common.network.Payloads.DenyPacket; import io.greitan.avion.common.network.Payloads.BindPacket; @@ -28,8 +29,7 @@ public Network(T logger) { this.Logger = logger; } - public MCCommPacket sendPostRequest(String url, MCCommPacket data) // was (String url, Object data) - { + public MCCommPacket sendPostRequest(String url, MCCommPacket data) { try { String jsonData = objectMapper.writeValueAsString(data); Logger.debug("Request: " + jsonData.toString()); @@ -50,11 +50,14 @@ public MCCommPacket sendPostRequest(String url, MCCommPacket data) // was (Strin if (statusCode == 200) { return objectMapper.readValue(body, MCCommPacket.class); } else { - Logger.error("Got non-200 status code: " + statusCode); + Logger.error("Sending HTTP Packet Failed, Reason: HTTP_EXCEPTION, STATUS_CODE: " + statusCode); + // throw new Exception("Sending HTTP Packet Failed, Reason: HTTP_EXCEPTION, STATUS_CODE: " + statusCode); return null; } } catch (Exception e) { - Logger.error("Can't connect to voice chat server! " + e.toString()); + String message = e.getMessage(); + if (message == null) message = e.toString(); + Logger.error("Can't connect to voice chat server! " + message); return null; } } @@ -78,18 +81,31 @@ public String sendLoginRequest(String link, String serverKey) { AcceptPacket packetData = objectMapper.convertValue(response, AcceptPacket.class); return packetData.Token; } - /* - * else if (response.PacketId == PacketType.Deny.ordinal()) - * { - * DenyPacket packetData = objectMapper.convertValue(response, - * DenyPacket.class); - * // Login Denied. Server denied link request! Reason: - * return "DENIED! " + packetData.Reason; - * } - */ + else if (response.PacketId == PacketType.Deny.ordinal() || response instanceof DenyPacket) + { + DenyPacket packetData = objectMapper.convertValue(response, DenyPacket.class); + Logger.error( + "Login Denied. Server denied link request! Reason: " + packetData.Reason); + } + } else { + Logger.error("Could not contact server. Please check if your IPAddress and Port are correct!"); } return null; } + + /** + * Sends the logout request to the server. + * + * @param link HTTP POST link + * @param token The session token + */ + public void sendLogoutRequest(String link, String token) { + // Create request data object. + LogoutPacket logoutPacket = new LogoutPacket(); + logoutPacket.Token = token; + + sendPostRequest(link, logoutPacket); + } /** * Sends the bind request to the server. diff --git a/src/main/java/io/greitan/avion/common/network/Payloads.java b/src/main/java/io/greitan/avion/common/network/Payloads.java index f7a626c..32d87f3 100644 --- a/src/main/java/io/greitan/avion/common/network/Payloads.java +++ b/src/main/java/io/greitan/avion/common/network/Payloads.java @@ -190,6 +190,12 @@ public DisconnectParticipantPacket() { public String PlayerId = ""; } + public static class LocationData { + public double x = 0; + public double y = 0; + public double z = 0; + } + public static class PlayerData { public String PlayerId = ""; public String DimensionId = ""; @@ -212,10 +218,10 @@ public PlayerData clone() { } } - public static class LocationData { - public double x = 0; - public double y = 0; - public double z = 0; + public static class ChannelOverrideData { + public int ProximityDistance = 30; + public boolean ProximityToggle = true; + public boolean VoiceEffects = true; } public static class ChannelData { @@ -225,10 +231,4 @@ public static class ChannelData { public boolean Hidden = false; public ChannelOverrideData OverrideSettings = null; } - - public static class ChannelOverrideData { - public int ProximityDistance = 30; - public boolean ProximityToggle = true; - public boolean VoiceEffects = true; - } } diff --git a/src/main/java/io/greitan/avion/common/utils/DoubleStringOperation.java b/src/main/java/io/greitan/avion/common/utils/DoubleStringOperation.java new file mode 100644 index 0000000..134e811 --- /dev/null +++ b/src/main/java/io/greitan/avion/common/utils/DoubleStringOperation.java @@ -0,0 +1,5 @@ +package io.greitan.avion.common.utils; + +public interface DoubleStringOperation { + void execute(String key, String rawColor); +} diff --git a/src/main/java/io/greitan/avion/common/utils/EmptyOperation.java b/src/main/java/io/greitan/avion/common/utils/EmptyOperation.java new file mode 100644 index 0000000..a935e7a --- /dev/null +++ b/src/main/java/io/greitan/avion/common/utils/EmptyOperation.java @@ -0,0 +1,5 @@ +package io.greitan.avion.common.utils; + +public interface EmptyOperation { + boolean execute(); +} diff --git a/src/main/java/io/greitan/avion/common/utils/IntegerOperation.java b/src/main/java/io/greitan/avion/common/utils/IntegerOperation.java new file mode 100644 index 0000000..3d3211c --- /dev/null +++ b/src/main/java/io/greitan/avion/common/utils/IntegerOperation.java @@ -0,0 +1,5 @@ +package io.greitan.avion.common.utils; + +public interface IntegerOperation { + boolean execute(int key); +} diff --git a/src/main/java/io/greitan/avion/common/utils/StringOperation.java b/src/main/java/io/greitan/avion/common/utils/StringOperation.java new file mode 100644 index 0000000..4ba5086 --- /dev/null +++ b/src/main/java/io/greitan/avion/common/utils/StringOperation.java @@ -0,0 +1,5 @@ +package io.greitan.avion.common.utils; + +public interface StringOperation { + boolean execute(String name); +} diff --git a/src/main/java/io/greitan/avion/paper/GeyserVoice.java b/src/main/java/io/greitan/avion/paper/GeyserVoice.java index addce07..b834622 100644 --- a/src/main/java/io/greitan/avion/paper/GeyserVoice.java +++ b/src/main/java/io/greitan/avion/paper/GeyserVoice.java @@ -1,6 +1,9 @@ package io.greitan.avion.paper; import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -102,7 +105,8 @@ public void reload() { port = getConfig().getInt("config.port"); serverKey = getConfig().getString("config.server-key"); - isConnected = connect(true); + if (getConfig().getBoolean("config.auto-reconnect")) + isConnected = reconnect(true); int positionTaskInterval = getConfig().getInt("config.voice.position-task-interval", 1); if (!taskRunner.isCancelled()) @@ -116,16 +120,42 @@ public void reload() { updateSettings(proximityDistance, proximityToggle, voiceEffects); } + /** + * Connects to a new server. + * + * @param host The host to connect to. + * @param port The port to connect to. + * @param serverKey The server key. + * @return True if connected successfully, otherwise false. + */ + public Boolean connect(String host, int port, String serverKey) { + if (Objects.nonNull(host) && Objects.nonNull(serverKey)) { + getConfig().set("config.host", host); + getConfig().set("config.port", port); + getConfig().set("config.server-key", serverKey); + saveConfig(); + reloadConfig(); + reload(); + + return isConnected; + } else { + Logger.warn(Language.getMessage(lang, "plugin-connect-invalid-data")); + return false; + } + } + /** * Connects to the server. * * @param force Indicates whether to force a connection. * @return True if connected successfully, otherwise false. */ - public Boolean connect(Boolean force) { + public Boolean reconnect(Boolean force) { if (isConnected && !force) return true; - isConnected = false; + if (isConnected) { + disconnect("Reconnecting to another server."); + } if (usesProxy) { Logger.info(Language.getMessage(lang, "plugin-connect-proxy")); @@ -136,11 +166,11 @@ public Boolean connect(Boolean force) { String link = "http://" + host + ":" + port; String Token = network.sendLoginRequest(link, serverKey); if (Objects.nonNull(Token)) { - Logger.info(Language.getMessage(lang, "plugin-connect-connect")); + Logger.info(Language.getMessage(lang, "plugin-connect-connected")); isConnected = true; token = Token; } else { - Logger.warn(Language.getMessage(lang, "plugin-connect-disconnect")); + Logger.warn(Language.getMessage(lang, "plugin-connect-failed")); } return isConnected; } else { @@ -149,6 +179,39 @@ public Boolean connect(Boolean force) { } } + /** + * Disconnects from the server. + * + * @param reason The reason why we disconnected + */ + public void disconnect(String reason) { + if (!isConnected) + return; + + if (Objects.nonNull(host) && Objects.nonNull(serverKey)) { + String link = "http://" + host + ":" + port; + network.sendLogoutRequest(link, token); + isConnected = false; + + String disconnectMessage = Language.getMessage(lang, "plugin-connection-disconnect").replace("$reason", reason); + Logger.info(disconnectMessage); + + boolean sendVoipDisconnectMessage = getConfig().getBoolean("config.voice.send-voip-disconnect-message"); + if (sendVoipDisconnectMessage) { + Bukkit.broadcast(Component.text(disconnectMessage).color(NamedTextColor.YELLOW)); + } + } else { + Logger.warn(Language.getMessage(lang, "plugin-connect-invalid-data")); + } + } + + /** + * Disconnects from the server. + */ + public void disconnect() { + disconnect("N.A."); + } + /** * Binds a player to the voice chat server. * @@ -159,6 +222,11 @@ public Boolean connect(Boolean force) { public Boolean bind(int playerKey, Player player, int tries) { if (!isConnected || Objects.isNull(host) || Objects.isNull(serverKey) || usesProxy) return false; + + if (playerBinds.containsKey(player.getName()) && playerBinds.get(player.getName())) { + return true; + } + String link = "http://" + host + ":" + port; getConfig().set("config.players." + player.getName(), playerKey); @@ -170,13 +238,27 @@ public Boolean bind(int playerKey, Player player, int tries) { if (result != null) { if (result == "SUCCESS") { playerBinds.put(player.getName(), true); - return true; - } else { - if (result == "Invalid Token!" && tries == 0) { - Logger.info("Invalid Token detected, reconnecting..."); - isConnected = connect(true); - return bind(playerKey, player, 1); + + Logger.info(Language.getMessage(lang, "player-binded").replace("$player",player.getName())); + + boolean sendBindedMessage = getConfig().getBoolean("config.voice.send-binded-message"); + if (sendBindedMessage) { + Bukkit.broadcast( + Component.text(player.getName()).decorate(TextDecoration.BOLD) + .append( + Component.text( + Language.getMessage(lang, "player-binded") + .replace("$player", "") + ) + .color(NamedTextColor.DARK_GREEN) + ) + ); } + return true; + } else if (result == "Invalid Token!" && tries == 0) { + Logger.info("Invalid Token detected, reconnecting..."); + isConnected = reconnect(true); + return bind(playerKey, player, 1); } } return false; @@ -186,6 +268,57 @@ public Boolean bind(int playerKey, Player player) { return bind(playerKey, player, 0); } + /** + * Bind a fake player + * @param bindKey + * @param name + * @return + */ + public Boolean bindFake(int playerKey, String name, int tries) { + if (!isConnected || Objects.isNull(host) || Objects.isNull(serverKey)) + return false; + + if (playerBinds.containsKey(name) && playerBinds.get(name)) { + return true; + } + + String link = "http://" + host + ":" + port; + + String result = network.sendBindRequest(link, token, playerKey, String.format("%0", playerKey), name); + playerBinds.put(name, false); + if (result != null) { + if (result == "SUCCESS") { + playerBinds.put(name, true); + + Logger.info(Language.getMessage(lang, "player-binded").replace("$player", name)); + + boolean sendBindedMessage = getConfig().getBoolean("config.voice.send-binded-message"); + if (sendBindedMessage) { + Bukkit.broadcast( + Component.text(name).decorate(TextDecoration.BOLD) + .append( + Component.text( + Language.getMessage(lang, "player-binded") + .replace("$player", "") + ) + .color(NamedTextColor.DARK_GREEN) + ) + ); + } + return true; + } else if (result == "Invalid Token!" && tries == 0) { + Logger.info("Invalid Token detected, reconnecting..."); + isConnected = reconnect(true); + return bindFake(playerKey, name, 1); + } + } + return false; + } + + public Boolean bindFake(int playerKey, String name) { + return bindFake(playerKey, name, 0); + } + /** * Disconnects a player from the voice chat server. * @@ -204,7 +337,7 @@ public Boolean disconnectPlayer(Player player, int tries) { return true; } else if (result == "Invalid Token!" && tries == 0) { Logger.info("Invalid Token detected, reconnecting..."); - isConnected = connect(true); + isConnected = reconnect(true); return disconnectPlayer(player, 1); } } diff --git a/src/main/java/io/greitan/avion/paper/commands/VoiceCommand.java b/src/main/java/io/greitan/avion/paper/commands/VoiceCommand.java index 4ba28e6..eba18ac 100644 --- a/src/main/java/io/greitan/avion/paper/commands/VoiceCommand.java +++ b/src/main/java/io/greitan/avion/paper/commands/VoiceCommand.java @@ -1,174 +1,99 @@ package io.greitan.avion.paper.commands; import java.util.List; -import java.util.Objects; -import java.util.Collections; -import java.lang.NumberFormatException; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; -import org.bukkit.util.StringUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import io.greitan.avion.paper.GeyserVoice; import io.greitan.avion.paper.utils.Language; +import io.greitan.avion.common.commands.BaseVoiceCommand; +import io.greitan.avion.common.utils.IntegerOperation; +import io.greitan.avion.common.utils.StringOperation; +import io.greitan.avion.common.utils.DoubleStringOperation; +import io.greitan.avion.common.utils.EmptyOperation; public class VoiceCommand implements CommandExecutor, TabCompleter { - + + private final BaseVoiceCommand voiceCommand; private final GeyserVoice plugin; private final String lang; - private boolean isConnected = false; // Get the plugin and lang interfaces. public VoiceCommand(GeyserVoice plugin, String lang) { + this.voiceCommand = new BaseVoiceCommand(plugin); this.plugin = plugin; this.lang = lang; } @Override public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { - isConnected = plugin.isConnected(); - - if (sender instanceof Player) { - Player player = (Player) sender; - if (args.length >= 1) { - // Bind command - bind player. - if (args[0].equalsIgnoreCase("bind") && player.hasPermission("voice.bind") && isConnected) { - if (args.length >= 2 && Objects.nonNull(args[1])) { - int bindKey; - try { - bindKey = Integer.parseInt(args[1]); - } catch (NumberFormatException e) { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-invalid-args")) - .color(NamedTextColor.RED)); - return true; - } - /* - * if (bindKey == 0) { - * player.sendMessage("Here is your open key!"); - * return; - * } - */ - Boolean isBound = plugin.bind(bindKey, player); - if (isBound) { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-bind-connect")) - .color(NamedTextColor.AQUA)); - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-bind-disconnect")) - .color(NamedTextColor.RED)); - } - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-invalid-args")) - .color(NamedTextColor.RED)); - } - } - // Setup command - setup the configuration. - else if (args[0].equalsIgnoreCase("setup") && player.hasPermission("voice.setup")) { - String newHost = args[1]; - String newPort = args[2]; - String newKey = args[3]; - - if (Objects.nonNull(newHost) && Objects.nonNull(newPort) && Objects.nonNull(newKey)) { - plugin.getConfig().set("config.host", newHost); - plugin.getConfig().set("config.port", newPort); - plugin.getConfig().set("config.server-key", newKey); - plugin.saveConfig(); - plugin.reloadConfig(); - plugin.reload(); - - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-setup-success")) - .color(NamedTextColor.AQUA)); - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-setup-invalid-data")) - .color(NamedTextColor.RED)); - } + return this.voiceCommand.onCommand( + args, + plugin.isConnected(), + sender instanceof Player, + new StringOperation() { + @Override + public boolean execute(String permission) { + if (sender instanceof Player) + return sender.hasPermission(permission); + else + return true; } - // Connect command - connect to the VoiceCraft server. - else if (args[0].equalsIgnoreCase("connect") && player.hasPermission("voice.connect")) { - if (Objects.nonNull(args[1])) { - Boolean force = Boolean.valueOf(args[1]); - - Boolean connected = plugin.connect(force); - if (connected) { - player.sendMessage(Component.text(Language.getMessage(lang, "plugin-connect-connect")) - .color(NamedTextColor.AQUA)); - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "plugin-connect-disconnect")) - .color(NamedTextColor.RED)); - } - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-invalid-args")) - .color(NamedTextColor.RED)); - } + }, + new DoubleStringOperation() { + @Override + public void execute(String text, String rawColor) { + NamedTextColor color = NamedTextColor.RED; + if (rawColor == "red") color = NamedTextColor.RED; + else if (rawColor == "aqua") color = NamedTextColor.AQUA; + else if (rawColor == "green") color = NamedTextColor.GREEN; + else if (rawColor == "yellow") color = NamedTextColor.YELLOW; + + var message = Component.text(Language.getMessage(lang, text)).color(color); + if (sender instanceof Player) + sender.sendMessage(message); + else + plugin.Logger.log(message); } - // Reload command - reload the configs. - else if (args[0].equalsIgnoreCase("reload") && player.hasPermission("voice.reload")) { - plugin.reload(); - player.sendMessage( - Component.text(Language.getMessage(lang, "cmd-reload")).color(NamedTextColor.GREEN)); - } else if (args[0].equalsIgnoreCase("settings") && player.hasPermission("voice.settings")) { - int proximityDistance = 1; - Boolean proximityToggle = true; - Boolean voiceEffects = true; - - plugin.updateSettings(proximityDistance, proximityToggle, voiceEffects); + }, + new IntegerOperation() { + @Override + public boolean execute(int key) { + if (sender instanceof Player) { + Player player = (Player) sender; + return plugin.bind(key, player); + } + return false; } - // Command select invalid. - else { - player.sendMessage( - Component.text(Language.getMessage(lang, "cmd-invalid-args")).color(NamedTextColor.RED)); + }, + new EmptyOperation() { + @Override + public boolean execute() { + if (sender instanceof Player) { + Player player = (Player) sender; + plugin.getConfig().set("config.players." + player.getName(), null); + return true; + } + return false; } } - } - // Commands runned by console. - else if (args.length >= 1) { - // Reload command - reload the configs. - if (args[0].equalsIgnoreCase("reload")) { - plugin.reload(); - plugin.Logger.log(Component.text(Language.getMessage(lang, "cmd-reload")).color(NamedTextColor.GREEN)); - } - // Command not for console. - else { - sender.sendMessage( - Component.text(Language.getMessage(lang, "cmd-not-player")).color(NamedTextColor.RED)); - } - } - // Invalid command arguments. - else { - sender.sendMessage(Component.text(Language.getMessage(lang, "cmd-invalid-args")).color(NamedTextColor.RED)); - } - return true; + ); } @Override public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { - List completions = List.of(); - - // Main command arguments. - if (args.length == 1) { - List options = List.of("bind", "setup", "connect", "reload"); - StringUtil.copyPartialMatches(args[0], options, completions); - } - - // Setup command arguments. - if (args.length == 2 && args[0].equalsIgnoreCase("setup")) { - List options = List.of("host port key"); - StringUtil.copyPartialMatches(args[1], options, completions); - } - - // Connect command arguments. - if (args.length == 2 && args[0].equalsIgnoreCase("connect")) { - List options = List.of("true", "false"); - StringUtil.copyPartialMatches(args[1], options, completions); - } - - Collections.sort(completions); - return completions; + return voiceCommand.onTabComplete(args, new StringOperation() { + @Override + public boolean execute(String permission) { + return sender.hasPermission(permission); + } + }); } - } diff --git a/src/main/java/io/greitan/avion/paper/listeners/PlayerJoinHandler.java b/src/main/java/io/greitan/avion/paper/listeners/PlayerJoinHandler.java index 78d28db..61580c7 100644 --- a/src/main/java/io/greitan/avion/paper/listeners/PlayerJoinHandler.java +++ b/src/main/java/io/greitan/avion/paper/listeners/PlayerJoinHandler.java @@ -1,15 +1,16 @@ package io.greitan.avion.paper.listeners; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; -import io.greitan.avion.paper.GeyserVoice; -import io.greitan.avion.paper.utils.Language; + import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import io.greitan.avion.paper.GeyserVoice; +import io.greitan.avion.paper.utils.Language; + import java.util.Objects; public class PlayerJoinHandler implements Listener { @@ -34,19 +35,16 @@ public void onPlayerJoin(PlayerJoinEvent event) { } private void handleAutoBind(int playerBindKey, Player player) { - boolean isBound = plugin.bind(playerBindKey, player); + player.sendMessage( + Component.text(Language.getMessage(lang, "plugin-autobind-enabled")).color(NamedTextColor.GREEN) + .append(Component.text(" ")) + .append( + Component.text(Language.getMessage(lang, "plugin-autobind-binding")).color(NamedTextColor.YELLOW) + )); - if (isBound) { - String playerName = player.getName(); - String connectMessage = Language.getMessage(lang, "player-connect").replace("$player", playerName); - - plugin.Logger.info(connectMessage); + boolean isBound = plugin.bind(playerBindKey, player); - boolean sendConnectMessage = plugin.getConfig().getBoolean("config.voice.send-connect-message"); - if (sendConnectMessage) { - Bukkit.broadcast(Component.text(connectMessage).color(NamedTextColor.YELLOW)); - } - } else { + if (!isBound) { player.sendMessage( Component.text(Language.getMessage(lang, "plugin-autobind-failed")).color(NamedTextColor.RED)); } diff --git a/src/main/java/io/greitan/avion/paper/tasks/PositionsTask.java b/src/main/java/io/greitan/avion/paper/tasks/PositionsTask.java index bc7bae8..1423cd0 100644 --- a/src/main/java/io/greitan/avion/paper/tasks/PositionsTask.java +++ b/src/main/java/io/greitan/avion/paper/tasks/PositionsTask.java @@ -206,7 +206,7 @@ private Boolean Reconnect() { plugin.Logger.warn(Language.getMessage(lang, "plugin-connection-reconnecting-attempt").replace("$attempt", ReconnectRetries.toString())); - if (plugin.connect(true)) { + if (plugin.reconnect(true)) { plugin.Logger.warn(Language.getMessage(lang, "plugin-connection-reconnecting-success")); if (plugin.getConfig().getBoolean("config.voice.send-connection-lost-message")) { diff --git a/src/main/java/io/greitan/avion/velocity/GeyserVoice.java b/src/main/java/io/greitan/avion/velocity/GeyserVoice.java index df6bb58..6ad7408 100644 --- a/src/main/java/io/greitan/avion/velocity/GeyserVoice.java +++ b/src/main/java/io/greitan/avion/velocity/GeyserVoice.java @@ -1,6 +1,11 @@ package io.greitan.avion.velocity; import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.ComponentBuilder; import com.google.inject.Inject; import com.velocitypowered.api.command.CommandMeta; @@ -33,6 +38,7 @@ import java.io.OutputStream; import java.io.FileOutputStream; import java.util.concurrent.TimeUnit; + import java.util.Objects; import java.util.Map; import java.util.HashMap; @@ -96,14 +102,14 @@ public void onProxyInitialization(final ProxyInitializeEvent event) { commandManager.register(commandMeta, voiceCommand); taskRunner = proxy.getScheduler() - .buildTask(this, () -> { - if (!positionsTask.run()) { - taskRunner.cancel(); - } - }) - .repeat(positionTaskInterval * 50, TimeUnit.MILLISECONDS) // positionTaskInterval is in ticks, 1 tick = - // 0.050 seconds = 50 ms - .schedule(); + .buildTask(this, () -> { + if (!positionsTask.run()) { + taskRunner.cancel(); + } + }) + .repeat(positionTaskInterval * 50, TimeUnit.MILLISECONDS) // positionTaskInterval is in ticks, 1 tick = + // 0.050 seconds = 50 ms + .schedule(); proxy.getEventManager().register(this, new PlayerJoinHandler(this, lang)); proxy.getEventManager().register(this, new PlayerQuitHandler(this, lang)); @@ -124,20 +130,21 @@ public void reload() { port = getConfig().getInt("config.port"); serverKey = getConfig().getString("config.server-key"); - isConnected = connect(true); + if (getConfig().getBoolean("config.auto-reconnect")) + isConnected = reconnect(true); int positionTaskInterval = getConfig().getOrDefault("config.voice.position-task-interval", 1); if (taskRunner.status() != TaskStatus.CANCELLED) taskRunner.cancel(); taskRunner = proxy.getScheduler() - .buildTask(this, () -> { - if (!positionsTask.run()) { - taskRunner.cancel(); - } - }) - .repeat(positionTaskInterval * 50, TimeUnit.MILLISECONDS) // positionTaskInterval is in ticks, 1 tick = - // 0.050 seconds = 50 ms - .schedule(); + .buildTask(this, () -> { + if (!positionsTask.run()) { + taskRunner.cancel(); + } + }) + .repeat(positionTaskInterval * 50, TimeUnit.MILLISECONDS) // positionTaskInterval is in ticks, 1 tick = + // 0.050 seconds = 50 ms + .schedule(); int proximityDistance = getConfig().getInt("config.voice.proximity-distance"); Boolean proximityToggle = getConfig().getBoolean("config.voice.proximity-toggle"); @@ -146,27 +153,52 @@ public void reload() { updateSettings(proximityDistance, proximityToggle, voiceEffects); } + /** + * Connects to a new server. + * + * @param host The host to connect to. + * @param port The port to connect to. + * @param serverKey The server key. + * @return True if connected successfully, otherwise false. + */ + public Boolean connect(String host, int port, String serverKey) { + if (Objects.nonNull(host) && Objects.nonNull(serverKey)) { + getConfig().set("config.host", host); + getConfig().set("config.port", port); + getConfig().set("config.server-key", serverKey); + saveConfig(); + reloadConfig(); + reload(); + + return isConnected; + } else { + Logger.warn(Language.getMessage(lang, "plugin-connect-invalid-data")); + return false; + } + } + /** * Connects to the server. * * @param force Indicates whether to force a connection. * @return True if connected successfully, otherwise false. */ - public Boolean connect(Boolean force) { + public Boolean reconnect(Boolean force) { if (isConnected && !force) return true; - isConnected = false; + if (isConnected) { + disconnect("Reconnecting to another server."); + } if (Objects.nonNull(host) && Objects.nonNull(serverKey)) { String link = "http://" + host + ":" + port; - String Token = network.sendLoginRequest(link, serverKey); if (Objects.nonNull(Token)) { - Logger.info(Language.getMessage(lang, "plugin-connect-connect")); + Logger.info(Language.getMessage(lang, "plugin-connect-connected")); isConnected = true; token = Token; } else { - Logger.warn(Language.getMessage(lang, "plugin-connect-disconnect")); + Logger.warn(Language.getMessage(lang, "plugin-connect-failed")); } return isConnected; } else { @@ -175,6 +207,39 @@ public Boolean connect(Boolean force) { } } + /** + * Disconnects from the server. + * + * @param reason The reason why we disconnected + */ + public void disconnect(String reason) { + if (!isConnected) + return; + + if (Objects.nonNull(host) && Objects.nonNull(serverKey)) { + String link = "http://" + host + ":" + port; + network.sendLogoutRequest(link, token); + isConnected = false; + + String disconnectMessage = Language.getMessage(lang, "plugin-connection-disconnect").replace("$reason", reason); + Logger.info(disconnectMessage); + + boolean sendVoipDisconnectMessage = getConfig().getBoolean("config.voice.send-voip-disconnect-message"); + if (sendVoipDisconnectMessage) { + getProxy().sendMessage(Component.text(disconnectMessage).color(NamedTextColor.YELLOW)); + } + } else { + Logger.warn(Language.getMessage(lang, "plugin-connect-invalid-data")); + } + } + + /** + * Disconnects from the server. + */ + public void disconnect() { + disconnect("N.A."); + } + /** * Binds a player to the voice chat server. * @@ -185,6 +250,11 @@ public Boolean connect(Boolean force) { public Boolean bind(int playerKey, Player player, int tries) { if (!isConnected || Objects.isNull(host) || Objects.isNull(serverKey)) return false; + + if (playerBinds.containsKey(player.getUsername()) && playerBinds.get(player.getUsername())) { + return true; + } + String link = "http://" + host + ":" + port; getConfig().set("config.players." + player.getUsername(), playerKey); @@ -197,10 +267,26 @@ public Boolean bind(int playerKey, Player player, int tries) { if (result == "SUCCESS") { playerBinds.put(player.getUsername(), true); messageHandler.sendPlayerBindSync(player); + + Logger.info(Language.getMessage(lang, "player-binded").replace("$player",player.getUsername())); + + boolean sendBindedMessage = getConfig().getBoolean("config.voice.send-binded-message"); + if (sendBindedMessage) { + getProxy().sendMessage( + Component.text(player.getUsername()).decorate(TextDecoration.BOLD) + .append( + Component.text( + Language.getMessage(lang, "player-binded") + .replace("$player", "") + ) + .color(NamedTextColor.DARK_GREEN) + ) + ); + } return true; } else if (result == "Invalid Token!" && tries == 0) { Logger.info("Invalid Token detected, reconnecting..."); - isConnected = connect(true); + isConnected = reconnect(true); return bind(playerKey, player, 1); } } @@ -211,6 +297,59 @@ public Boolean bind(int playerKey, Player player, int tries) { public Boolean bind(int playerKey, Player player) { return bind(playerKey, player, 0); } + + /** + * Bind a fake player + * @param bindKey + * @param name + * @return + */ + public Boolean bindFake(int playerKey, String name, int tries) { + if (!isConnected || Objects.isNull(host) || Objects.isNull(serverKey)) + return false; + + if (playerBinds.containsKey(name) && playerBinds.get(name)) { + return true; + } + + String link = "http://" + host + ":" + port; + + String result = network.sendBindRequest(link, token, playerKey, String.format("%0", playerKey), name); + playerBinds.put(name, false); + if (result != null) { + if (result == "SUCCESS") { + playerBinds.put(name, true); + // messageHandler.sendPlayerBindSync(player); + + Logger.info(Language.getMessage(lang, "player-binded").replace("$player", name)); + + boolean sendBindedMessage = getConfig().getBoolean("config.voice.send-binded-message"); + if (sendBindedMessage) { + getProxy().sendMessage( + Component.text(name).decorate(TextDecoration.BOLD) + .append( + Component.text( + Language.getMessage(lang, "player-binded") + .replace("$player", "") + ) + .color(NamedTextColor.DARK_GREEN) + ) + ); + } + return true; + } else if (result == "Invalid Token!" && tries == 0) { + Logger.info("Invalid Token detected, reconnecting..."); + isConnected = reconnect(true); + return bindFake(playerKey, name, 1); + } + } + // messageHandler.sendPlayerBindSync(player); + return false; + } + + public Boolean bindFake(int playerKey, String name) { + return bindFake(playerKey, name, 0); + } /** * Disconnects a player from the voice chat server. @@ -232,7 +371,7 @@ public Boolean disconnectPlayer(Player player, int tries) { return true; } else if (result == "Invalid Token!" && tries == 0) { Logger.info("Invalid Token detected, reconnecting..."); - isConnected = connect(true); + isConnected = reconnect(true); return disconnectPlayer(player, 1); } } diff --git a/src/main/java/io/greitan/avion/velocity/commands/VoiceCommand.java b/src/main/java/io/greitan/avion/velocity/commands/VoiceCommand.java index bea5e93..d207679 100644 --- a/src/main/java/io/greitan/avion/velocity/commands/VoiceCommand.java +++ b/src/main/java/io/greitan/avion/velocity/commands/VoiceCommand.java @@ -1,11 +1,5 @@ package io.greitan.avion.velocity.commands; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.concurrent.CompletableFuture; -import java.lang.NumberFormatException; - import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.SimpleCommand; import com.velocitypowered.api.proxy.Player; @@ -15,15 +9,23 @@ import io.greitan.avion.velocity.GeyserVoice; import io.greitan.avion.velocity.utils.Language; +import io.greitan.avion.common.commands.BaseVoiceCommand; +import io.greitan.avion.common.utils.IntegerOperation; +import io.greitan.avion.common.utils.StringOperation; +import io.greitan.avion.common.utils.DoubleStringOperation; +import io.greitan.avion.common.utils.EmptyOperation; + +import java.util.List; public final class VoiceCommand implements SimpleCommand { + private final BaseVoiceCommand voiceCommand; private final GeyserVoice plugin; private final String lang; - private boolean isConnected = false; // Get the plugin and lang interfaces. public VoiceCommand(GeyserVoice plugin, String lang) { + this.voiceCommand = new BaseVoiceCommand(plugin); this.plugin = plugin; this.lang = lang; } @@ -34,151 +36,72 @@ public void execute(final Invocation invocation) { // Get the arguments after the command alias String[] args = invocation.arguments(); - isConnected = plugin.isConnected(); - - if (sender instanceof Player) { - Player player = (Player) sender; - if (args.length >= 1) { - // Bind command - bind player. - if (args[0].equalsIgnoreCase("bind") && player.hasPermission("voice.bind") && isConnected) { - if (args.length >= 2 && Objects.nonNull(args[1])) { - int bindKey; - try { - bindKey = Integer.parseInt(args[1]); - } catch (NumberFormatException e) { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-invalid-args")) - .color(NamedTextColor.RED)); - return; - } - /* - * if (bindKey == 0) { - * player.sendMessage("Here is your open key!"); - * return; - * } - */ - Boolean isBound = plugin.bind(bindKey, player); - if (isBound) { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-bind-connect")) - .color(NamedTextColor.AQUA)); - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-bind-disconnect")) - .color(NamedTextColor.RED)); - } - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-invalid-args")) - .color(NamedTextColor.RED)); - } + this.voiceCommand.onCommand( + args, + plugin.isConnected(), + sender instanceof Player, + new StringOperation() { + @Override + public boolean execute(String permission) { + if (sender instanceof Player) + return sender.hasPermission(permission); + else + return true; } - // Setup command - setup the configuration. - else if (args[0].equalsIgnoreCase("setup") && player.hasPermission("voice.setup")) { - String newHost = args[1]; - String newPort = args[2]; - String newKey = args[3]; - - if (Objects.nonNull(newHost) && Objects.nonNull(newPort) && Objects.nonNull(newKey)) { - GeyserVoice.getConfig().set("config.host", newHost); - GeyserVoice.getConfig().set("config.port", newPort); - GeyserVoice.getConfig().set("config.server-key", newKey); - plugin.saveConfig(); - plugin.reloadConfig(); - plugin.reload(); - - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-setup-success")) - .color(NamedTextColor.AQUA)); - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-setup-invalid-data")) - .color(NamedTextColor.RED)); - } + }, + new DoubleStringOperation() { + @Override + public void execute(String text, String rawColor) { + NamedTextColor color = NamedTextColor.RED; + if (rawColor == "red") color = NamedTextColor.RED; + else if (rawColor == "aqua") color = NamedTextColor.AQUA; + else if (rawColor == "green") color = NamedTextColor.GREEN; + else if (rawColor == "yellow") color = NamedTextColor.YELLOW; + + var message = Component.text(Language.getMessage(lang, text)).color(color); + if (sender instanceof Player) + sender.sendMessage(message); + else + plugin.Logger.log(message); } - // Connect command - connect to the VoiceCraft server. - else if (args[0].equalsIgnoreCase("connect") && player.hasPermission("voice.connect")) { - if (Objects.nonNull(args[1])) { - Boolean force = Boolean.valueOf(args[1]); - - Boolean connected = plugin.connect(force); - if (connected) { - player.sendMessage(Component.text(Language.getMessage(lang, "plugin-connect-connect")) - .color(NamedTextColor.AQUA)); - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "plugin-connect-disconnect")) - .color(NamedTextColor.RED)); - } - } else { - player.sendMessage(Component.text(Language.getMessage(lang, "cmd-invalid-args")) - .color(NamedTextColor.RED)); - } + }, + new IntegerOperation() { + @Override + public boolean execute(int key) { + if (sender instanceof Player) { + Player player = (Player) sender; + return plugin.bind(key, player); + } + return false; } - // Reload command - reload the configs. - else if (args[0].equalsIgnoreCase("reload") && player.hasPermission("voice.reload")) { - plugin.reload(); - player.sendMessage( - Component.text(Language.getMessage(lang, "cmd-reload")).color(NamedTextColor.GREEN)); - } else if (args[0].equalsIgnoreCase("settings") && player.hasPermission("voice.settings")) { - int proximityDistance = 1; - Boolean proximityToggle = true; - Boolean voiceEffects = true; - - plugin.updateSettings(proximityDistance, proximityToggle, voiceEffects); - } - // Command select invalid. - else { - player.sendMessage( - Component.text(Language.getMessage(lang, "cmd-invalid-args")).color(NamedTextColor.RED)); + }, + new EmptyOperation() { + @Override + public boolean execute() { + if (sender instanceof Player) { + Player player = (Player) sender; + GeyserVoice.getConfig().set("config.players." + player.getUsername(), null); + return true; + } + return false; } } - } - // Commands runned by console. - else if (args.length >= 1) { - // Reload command - reload the configs. - if (args[0].equalsIgnoreCase("reload")) { - plugin.reload(); - plugin.Logger.log(Component.text(Language.getMessage(lang, "cmd-reload")).color(NamedTextColor.GREEN)); - } - // Command not for console. - else { - plugin.getProxy().sendMessage(Component.text("####CheckMessaging####")); - - sender.sendMessage( - Component.text(Language.getMessage(lang, "cmd-not-player")).color(NamedTextColor.RED)); - } - } - // Invalid command arguments. - else { - sender.sendMessage(Component.text(Language.getMessage(lang, "cmd-invalid-args")).color(NamedTextColor.RED)); - } + ); } @Override public boolean hasPermission(final Invocation invocation) { - return true; - // return invocation.source().hasPermission("command.test"); + return invocation.source().hasPermission("voice.cmd"); } @Override - public CompletableFuture> suggestAsync(final Invocation invocation) { + public List suggest(final Invocation invocation) { String[] args = invocation.arguments(); - return CompletableFuture.supplyAsync(() -> { - List completions = List.of(); - - // Main command arguments. - if (args.length == 1) { - List options = List.of("bind", "setup", "connect", "reload"); - completions = options.stream().filter(val -> val.startsWith(args[0])).collect(Collectors.toList()); + return voiceCommand.onTabComplete(args, new StringOperation() { + @Override + public boolean execute(String permission) { + return invocation.source().hasPermission(permission); } - - // Setup command arguments. - if (args.length == 2 && args[0].equalsIgnoreCase("setup")) { - List options = List.of("host port key"); - completions = options.stream().filter(val -> val.startsWith(args[1])).collect(Collectors.toList()); - } - - // Connect command arguments. - if (args.length == 2 && args[0].equalsIgnoreCase("connect")) { - List options = List.of("true", "false"); - completions = options.stream().filter(val -> val.startsWith(args[1])).collect(Collectors.toList()); - } - - return completions; }); } } diff --git a/src/main/java/io/greitan/avion/velocity/listeners/PlayerJoinHandler.java b/src/main/java/io/greitan/avion/velocity/listeners/PlayerJoinHandler.java index 86e5cef..9bb0108 100644 --- a/src/main/java/io/greitan/avion/velocity/listeners/PlayerJoinHandler.java +++ b/src/main/java/io/greitan/avion/velocity/listeners/PlayerJoinHandler.java @@ -40,20 +40,16 @@ public void onPlayerConnect(ServerPostConnectEvent event) { } private void handleAutoBind(int playerBindKey, Player player) { - boolean isBound = plugin.bind(playerBindKey, player); - - if (isBound) { - String playerName = player.getUsername(); - String connectMessage = Language.getMessage(lang, "player-connect").replace("$player", playerName); + player.sendMessage( + Component.text(Language.getMessage(lang, "plugin-autobind-enabled")).color(NamedTextColor.GREEN) + .append(Component.text(" ")) + .append( + Component.text(Language.getMessage(lang, "plugin-autobind-binding")).color(NamedTextColor.YELLOW) + )); - plugin.Logger.info(connectMessage); + boolean isBound = plugin.bind(playerBindKey, player); - boolean sendConnectMessage = GeyserVoice.getConfig().getBoolean("config.voice.send-connect-message"); - if (sendConnectMessage) { - // @TODO send to proxies -> Already works... - plugin.getProxy().sendMessage(Component.text(connectMessage).color(NamedTextColor.YELLOW)); - } - } else { + if (!isBound) { player.sendMessage( Component.text(Language.getMessage(lang, "plugin-autobind-failed")).color(NamedTextColor.RED)); } diff --git a/src/main/java/io/greitan/avion/velocity/tasks/PositionsTask.java b/src/main/java/io/greitan/avion/velocity/tasks/PositionsTask.java index 85268d2..ae7bed1 100644 --- a/src/main/java/io/greitan/avion/velocity/tasks/PositionsTask.java +++ b/src/main/java/io/greitan/avion/velocity/tasks/PositionsTask.java @@ -102,7 +102,7 @@ private Boolean Reconnect() { plugin.Logger.warn(Language.getMessage(lang, "plugin-connection-reconnecting-attempt").replace("$attempt", ReconnectRetries.toString())); - if (plugin.connect(true)) { + if (plugin.reconnect(true)) { plugin.Logger.warn(Language.getMessage(lang, "plugin-connection-reconnecting-success")); if (GeyserVoice.getConfig().getBoolean("config.voice.send-connection-lost-message")) { diff --git a/src/main/resource-templates/bungee.yml b/src/main/resource-templates/bungee.yml index fdb6a33..48ba029 100644 --- a/src/main/resource-templates/bungee.yml +++ b/src/main/resource-templates/bungee.yml @@ -13,19 +13,23 @@ prefix: {{ name }} commands: voice: description: Voice chat main command. - usage: /voice + usage: /voice permission: voice.cmd permissions: voice.cmd: default: true - voice.bind: - default: true voice.connect: default: op - voice.reload: + voice.reconnect: default: op - voice.setup: + voice.disconnect: default: op voice.settings: default: op + voice.bind: + default: true + voice.bindfake: + default: op + voice.reload: + default: op diff --git a/src/main/resource-templates/plugin.yml b/src/main/resource-templates/plugin.yml index 09703f8..32f19d4 100644 --- a/src/main/resource-templates/plugin.yml +++ b/src/main/resource-templates/plugin.yml @@ -17,19 +17,23 @@ soft-depend: commands: voice: description: Voice chat main command. - usage: /voice + usage: /voice permission: voice.cmd permissions: voice.cmd: default: true - voice.bind: - default: true voice.connect: default: op - voice.reload: + voice.reconnect: default: op - voice.setup: + voice.disconnect: default: op voice.settings: default: op + voice.bind: + default: true + voice.bindfake: + default: op + voice.reload: + default: op diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 066c04c..a657ca5 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -19,8 +19,9 @@ config: not-in-voice-symbol: "\u2727" # Symbol for a player not in voice chat (placeholder %voice_status%) in-voice-symbol: "\u2726" # Symbol for a player in voice chat - send-connect-message: true # Send message when a player connects to voice chat + send-binded-message: true # Send message when a player connects to voice chat send-disconnect-message: true # Send message when a player disconnects from voice chat + send-voip-disconnect-message: true # Send message when the server connection is closed send-connection-lost-message: true # Send message when the connection is lost from the voice chat server # The speed and accuracy of player positioning in voice chat depends on this. diff --git a/src/main/resources/locale/en.yml b/src/main/resources/locale/en.yml index 2f05134..37610f4 100644 --- a/src/main/resources/locale/en.yml +++ b/src/main/resources/locale/en.yml @@ -1,16 +1,39 @@ # en messages: - cmd-reload: "Plugin reloaded!" # Message indicating successful plugin reload. + commands: + connect: + invalid-args: "Invalid command usage. Usage: /voice connect " - cmd-bind-connect: "Bind success!" # Successful binding to the voice chat server. - cmd-bind-disconnect: "Bind failed! Check your key and try /voice bind " # Error message during binding to the voice chat server. - cmd-bind-invalid-data: "Invalid bind data!" # Message indicating invalid bind data. - cmd-bind-not-available: "You already connected to the voice chat." # Message indicating that a connection to the voice chat already exists. + disconnect: + disconnecting: "Disconnecting from Server..." + already-disconnected: "Already disconnected from server." + invalid-args: "Invalid command usage. Usage: /voice disconnect" - cmd-setup-success: "Setup success! Reloading..." # Successful setup of connection data. - cmd-setup-invalid-data: "Invalid command arguments. Usage: /voice setup " # Error message for invalid command arguments during setup. + settings: + nametag: "VoiceCraft Server Settings" + lore: "Open VoiceCraft Settings" + message: "You have been given an item in your inventory. Right Click/Interact with the item to open the settings UI" - cmd-invalid-args: "Invalid command usage. Usage: /voice " # Error message for invalid command usage. + bind: + binding: "Binding..." + binded: "Binding Successful!" + failed: "Binding Failed! Check your key and try again!" + broadcast: "$player has connected to VoiceCraft!" + binding-fake: "Binding fake player..." + invalid-args: "Invalid command usage. Usage: /voice bind " + fake-invalid-args: "Invalid command usage. Usage: /voice bindfake " + + updatefake: + updating: "Updating fake player..." + updated: "Update Successful!" + failed: "Update Failed!" + invalid-args: "Invalid command usage. Usage: /voice bindfake " + + clearautobind: "Successfully cleared autobind!" + + reload: "Plugin reloaded!" + + cmd-invalid-args: "Invalid command usage. Usage: /voice " # Error message for invalid command usage. cmd-not-player: "Only players can use this command!" # Error message for command use restricted to players only. cmd-not-exists: "This command is not exist." # Message indicating that the command does not exist. @@ -21,9 +44,10 @@ messages: plugin-config-loaded: "Config loaded." # Message indicating successful loading of the configuration. plugin-command-executor: "Commands executors enabled." # Message indicating successful enabling of command executors. - plugin-connect-connect: "Connected to voice chat server." # Successful connection to the voice chat server. + plugin-connect-connecting: "Connecting/Linking Server..." # Successful connection to the voice chat server. + plugin-connect-connected: "Login Accepted. Server successfully linked!" # Successful connection to the voice chat server. + plugin-connect-failed: "Login Failed! Server not linked! Run /voice to reconnect." # Error message during connection to the voice chat server. plugin-connect-proxy: "Proxy based server setup. Not connecting to voice chat server." # Velocity/Bungeecord based voice chat server connection. - plugin-connect-disconnect: "Connection to voice chat server had error. Run /voice to reconnect." # Error message during connection to the voice chat server. plugin-connect-invalid-data: "Connection failed. Invalid config." # Error message indicating failed connection due to invalid configuration. plugin-connection-lost: "Lost connection from voice chat server." # Message when connection is lost. @@ -32,6 +56,9 @@ messages: plugin-connection-reconnecting-success: "Successfully reconnected to voice chat server." # Message when reconnected to the server plugin-connection-reconnecting-failed-retry: "Connection failed, Retrying..." # Message when reconnecting failed and retrying it plugin-connection-reconnecting-failed: "Failed to reconnect to voice chat server." # Message when reconnecting failed after 5 tries + plugin-connection-disconnecting: "Disconnecting from Server..." # Message when disconnecting + plugin-connection-already-disconnected: "Already disconnected from server." # Message when already disconnected + plugin-connection-disconnect: "Disconnected from VOIP Server, Reason: $reason" # Message when disconnect plugin-autobind-success: "AutoBind success!" # Successful AutoBind execution. plugin-autobind-failed: "AutoBind failed! Are you not in the VoiceCraft app?" # Error message during failed AutoBind execution. @@ -39,4 +66,4 @@ messages: player-disconnect-success: "Player $player left from the voice chat." # Message indicating player leaving the voice chat. player-disconnect-failed: "Player $player received an error when leaving the voice chat." # Error message during player leaving the voice chat. - player-connect: "Player $player joined the voice chat." # Message indicating player joining the voice chat. + player-binded: "$player has connected to VoiceCraft." # Message indicating player joining the voice chat. diff --git a/src/main/resources/locale/nl.yml b/src/main/resources/locale/nl.yml index 3e8c040..384c24e 100644 --- a/src/main/resources/locale/nl.yml +++ b/src/main/resources/locale/nl.yml @@ -1,16 +1,38 @@ # nl messages: - cmd-reload: "Plugin herladen!" # Message indicating successful plugin reload. + commands: + connect: + invalid-args: "Ongeldig commando gebruik. Gebruik: /voice connect " - cmd-bind-connect: "Bind succes!" # Successful binding to the voice chat server. - cmd-bind-disconnect: "Bind mislukt! Check je key en probeer /voice bind " # Error message during binding to the voice chat server. - cmd-bind-invalid-data: "Ongeldige bind data!" # Message indicating invalid bind data. - cmd-bind-not-available: "Je bent al verbonden met de voice chat." # Message indicating that a connection to the voice chat already exists. + disconnect: + disconnecting: "Verbinding met Server verbreken..." + already-disconnected: "De verbinding met de server is al verbroken." + invalid-args: "Ongeldig commando gebruik. Gebruik: /voice disconnect" - cmd-setup-success: "Setup succes! Herladen..." # Successful setup of connection data. - cmd-setup-invalid-data: "Ongeldige commando argumenten. Gebruik: /voice setup " # Error message for invalid command arguments during setup. + settings: + nametag: "VoiceCraft Server Instellingen" + lore: "Open VoiceCraft Instellingen" + message: "Je hebt een item in je inventaris gekregen. Klik met de rechtermuisknop/communiceer met het item om de gebruikersinterface voor instellingen te openen" - cmd-invalid-args: "Ongeldig commando gebruik. Gebruik: /voice " # Error message for invalid command usage. + bind: + binding: "Koppelen..." + binded: "Koppelen Succesvol!" + failed: "Koppelen Mislukt! Check je key en probeer opnieuw!" + binding-fake: "Koppelen fake speler..." + invalid-args: "Ongeldig commando gebruik. Gebruik: /voice bind " + fake-invalid-args: "Ongeldig commando gebruik. Gebruik: /voice bindfake " + + updatefake: + updating: "Updaten van fake speler..." + updated: "Update Succesvol!" + failed: "Update Mislukt!" + invalid-args: "Ongeldig commando gebruik. Gebruik: /voice bindfake " + + clearautobind: "Legen van autobind gelukt!" + + reload: "Plugin herladen!" + + cmd-invalid-args: "Ongeldig commando gebruik. Gebruik: /voice " # Error message for invalid command usage. cmd-not-player: "Alleen spelers kunnen dit commando gebruiken!" # Error message for command use restricted to players only. cmd-not-exists: "Dit commando bestaat niet." # Message indicating that the command does not exist. @@ -21,9 +43,10 @@ messages: plugin-config-loaded: "Configuratie geladen." # Message indicating successful loading of the configuration. plugin-command-executor: "Uitvoerders voor commando's ingeschakeld." # Message indicating successful enabling of command executors. - plugin-connect-connect: "Verbonden met voicechatserver." # Successful connection to the voice chat server. + plugin-connect-connecting: "Verbinden/Linken van Server..." # Successful connection to the voice chat server. + plugin-connect-connected: "Login Geaccepteerd. Server succesvol gelinkt." # Successful connection to the voice chat server. + plugin-connect-failed: "Login Mislukt! Server niet gelinkt! Voer /voice uit om opnieuw verbinding te makne." # Error message during connection to the voice chat server. plugin-connect-proxy: "Proxy gebaseerde server setup. Niet verbinden met voicechatserver." # Velocity based voice chat server connection. - plugin-connect-disconnect: "Er is een fout opgetreden bij de verbinding met de voicechatserver. Voer /voice uit om opnieuw verbinding te maken." # Error message during connection to the voice chat server. plugin-connect-invalid-data: "Verbinding mislukt. Ongeldige configuratie." # Error message indicating failed connection due to invalid configuration. plugin-connection-lost: "Verbinding met voicechatserver verloren." # Message when connection is lost. @@ -32,11 +55,16 @@ messages: plugin-connection-reconnecting-success: "Met succes herverbonden met voicechatserver." # Message when reconnected to the server plugin-connection-reconnecting-failed-retry: "Connectie mislukt, Opnieuw proberen..." # Message when reconnecting failed and retrying it plugin-connection-reconnecting-failed: "Opnieuw verbinden met voicechatserver mislukt." # Message when reconnecting failed after 5 tries + plugin-connection-disconnecting: "Verbinding met Server verbreken..." # Message when disconnecting + plugin-connection-already-disconnected: "Verbinding was al verbroken met server." # Message when already disconnected + plugin-connection-disconnect: "Verbinding met VOIP Server verbroken, Reden: $reason" # Message when disconnect + plugin-autobind-enabled: "Autobinding Enabled." + plugin-autobind-binding: "Binding to key: $key!" plugin-autobind-success: "AutoBind succes!" # Successful AutoBind execution. plugin-autobind-failed: "AutoBind mislukt! Zit je niet in de VoiceCraft app?" # Error message during failed AutoBind execution. player-disconnect-success: "Speler $player heeft de voicechat verlaten." # Message indicating player leaving the voice chat. player-disconnect-failed: "Speler $player ontving een foutmelding bij het verlaten van de voicechat." # Error message during player leaving the voice chat. - player-connect: "Speler $player neemt deel aan de voicechat." # Message indicating player joining the voice chat. + player-binded: "$player is verbonden met VoiceCraft." # Message indicating player joining the voice chat. diff --git a/src/main/resources/locale/ru.yml b/src/main/resources/locale/ru.yml index c16f799..ef4d3fc 100644 --- a/src/main/resources/locale/ru.yml +++ b/src/main/resources/locale/ru.yml @@ -22,7 +22,7 @@ messages: plugin-command-executor: "Исполнители команд включены." # Сообщение об активации исполнителей команд. plugin-connect-connect: "Сервер голосового успешно чата подключен." # Успешное подключение к серверу голосового чата. - plugin-connect-disconnect: "Не удалось подключиться к серверу голосового чата. Для переподключения используйте /voice " # Ошибка при подключении к серверу голосового чата. + plugin-connect-failed: "Не удалось подключиться к серверу голосового чата. Для переподключения используйте /voice " # Ошибка при подключении к серверу голосового чата. plugin-connect-invalid-data: "Подключение не удалось. Неверная конфигурация." # Ошибка при неверной конфигурации подключения. plugin-autobind-success: "АвтоБинд успешен!" # Успешное выполнение автоматического подключения.