diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index e97e4d93d..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: 'bug' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Environment (please complete the following information):** - - Hosting OS: - - Node Version (node -v): - - NPM Version (npm -v): - - Bot Version (git log -1): \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index da3909363..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: 'enhancement' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8a80baed1..8eefaff31 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,19 +1,19 @@ -on: - push: - pull_request: - -jobs: - lint: - name: Lint - Node ${{ matrix.node }} - runs-on: ubuntu-latest - strategy: - matrix: - node: [ 22 ] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node }} - cache: 'npm' - - run: npm install - - run: npm test +on: + push: + pull_request: + +jobs: + lint: + name: Lint - Node ${{ matrix.node }} + runs-on: ubuntu-latest + strategy: + matrix: + node: [ 14, 16, 18 ] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: 'npm' + - run: npm install + - run: npm test diff --git a/.gitignore b/.gitignore index 73b976c24..ef2f42e55 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ instances credentials maps logs -temp +temp \ No newline at end of file diff --git a/config/index.js b/config/index.js index 63bcaf836..7a1655531 100644 --- a/config/index.js +++ b/config/index.js @@ -31,4 +31,4 @@ module.exports = { token: process.env.RPP_DISCORD_TOKEN || '', needAdminPrivileges: process.env.RPP_NEED_ADMIN_PRIVILEGES || true, /* If true, only admins can delete (server, switch..), manage credentials and reset a channel */ } -}; +}; \ No newline at end of file diff --git a/docs/commands.md b/docs/commands.md index 9dfd6ab22..ce0ec1708 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -360,6 +360,7 @@ In-Game Command | Description [**marker**](commands.md#marker) | Set custom markers anywhere on the map. [**market**](commands.md#market-ingame) | Search for items in vending machines or subscribe/unsubscribe to items. [**mute**](commands.md#mute) | Mute the bot from the In-Game Team Chat. +[**move**](commands.md#move) | Move user to a different channel. [**note/notes**](commands.md#notenotes) | Create notes about meaningful things. [**offline**](commands.md#offline) | Get the currently offline players in your team. [**online**](commands.md#online) | Get the currently online players in your team. @@ -535,6 +536,20 @@ Subcommand | Description | Required ![In-Game Command mute Image](images/ingame_commands/mute_ingame.png) +## **move** + +> **Move users between voice channels.** Use this to move yourself or other users to a specified voice channel. + +
Command format: `!move [user1] [user2] [...] ` + +* `target_channel`: Name or ID of the destination voice channel (**required**) +* `user1`, `user2`, ... : Mention or ID of the users to move (**optional**). If not specified, it moves **you**. + +### **Examples** + +* `!move General` – Moves **you** to the **General** voice channel +* `!move Alle Gaming` – Moves **Alle** to the **Gaming** channel +* `!move 123456789012345678` – Moves **you** to the voice channel with that **ID** ## **note/notes** diff --git a/docs/installation.md b/docs/installation.md index ba309692b..7ee2d25c6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,20 +1,20 @@ -# Installation Documentation - -## Required Software - -Program | Version | Download | Note -------- | ------- | -------- | ---- -`NodeJS` | >= 22.12.0 | [**here**](https://nodejs.org/en/download/) | Since discordjs v14 is used, the version needs to be at least 22.12.0. -`Git` | Any | [**here**](https://git-scm.com/downloads) |   - -## Optional Software -To enable step-trace for cargoship and patrol helicopter, [**GraphicsMagick**](http://www.graphicsmagick.org/download.html) needs to be downloaded. - - -## Clone the repository - -Open a terminal (`Git Bash` / `CMD` / `Terminal` / `PowerShell` or similar) and run the following commands: - - $ git clone https://github.com/alexemanuelol/rustplusplus.git - $ cd rustplusplus - $ npm install +# Installation Documentation + +## Required Software + +Program | Version | Download | Note +------- | ------- | -------- | ---- +`NodeJS` | >= 16.9 | [**here**](https://nodejs.org/en/download/) | Since discordjs v14 is used, the version needs to be at least 16.9. +`Git` | Any | [**here**](https://git-scm.com/downloads) |   + +## Optional Software +To enable step-trace for cargoship and patrol helicopter, [**GraphicsMagick**](http://www.graphicsmagick.org/download.html) needs to be downloaded. + + +## Clone the repository + +Open a terminal (`Git Bash` / `CMD` / `Terminal` / `PowerShell` or similar) and run the following commands: + + $ git clone https://github.com/alexemanuelol/rustplusplus.git + $ cd rustplusplus + $ npm install diff --git a/package.json b/package.json index 2657f40c2..444fbdfec 100644 --- a/package.json +++ b/package.json @@ -1,45 +1,45 @@ -{ - "name": "rustplusplus", - "version": "1.22.0", - "description": "A NodeJS Discord Bot that uses the rustplus.js library to utilize the power of the Rust+ Companion App with additional Quality-of-Life features.", - "main": "index.ts", - "scripts": { - "start": "ts-node .", - "preinstall": "npx npm-force-resolutions", - "test": "tsc --noEmit -p ." - }, - "repository": { - "type": "git", - "url": "https://github.com/alexemanuelol/rustplusplus.git" - }, - "author": "Alexemanuelol", - "license": "SEE LICENSE IN LICENSE", - "bugs": { - "url": "https://github.com/alexemanuelol/rustplusplus/issues" - }, - "homepage": "https://github.com/alexemanuelol/rustplusplus#readme", - "dependencies": { - "@discordjs/rest": "^2.5.1", - "@discordjs/voice": "^0.18.0", - "@formatjs/intl": "^2.6.9", - "@liamcottle/push-receiver": "^0.0.4", - "@liamcottle/rustplus.js": "git+https://github.com/alexemanuelol/rustplus.js.git#089cfd3db1b04709911948bce669273139c6a124", - "axios": "^1.3.4", - "colors": "^1.4.0", - "discord-api-types": "^0.38.14", - "discord.js": "^14.21.0", - "ffmpeg-static": "^5.1.0", - "gm": "^1.25.0", - "jimp": "^0.22.7", - "libsodium-wrappers": "^0.7.11", - "lodash": "^4.17.21", - "translate": "^1.4.1", - "ts-node": "^10.9.2", - "typescript": "^5.8.3", - "winston": "^3.8.2" - }, - "resolutions": { - "jpeg-js": "0.4.4", - "protobufjs": "7.2.4" - } +{ + "name": "rustplusplus", + "version": "1.22.0", + "description": "A NodeJS Discord Bot that uses the rustplus.js library to utilize the power of the Rust+ Companion App with additional Quality-of-Life features.", + "main": "index.ts", + "scripts": { + "start": "ts-node .", + "preinstall": "npx npm-force-resolutions", + "test": "tsc --noEmit -p ." + }, + "repository": { + "type": "git", + "url": "https://github.com/alexemanuelol/rustplusplus.git" + }, + "author": "Alexemanuelol", + "license": "SEE LICENSE IN LICENSE", + "bugs": { + "url": "https://github.com/alexemanuelol/rustplusplus/issues" + }, + "homepage": "https://github.com/alexemanuelol/rustplusplus#readme", + "dependencies": { + "@discordjs/rest": "^1.6.0", + "@discordjs/voice": "^0.16.0", + "@formatjs/intl": "^2.6.9", + "@liamcottle/push-receiver": "^0.0.4", + "@liamcottle/rustplus.js": "git+https://github.com/alexemanuelol/rustplus.js.git#089cfd3db1b04709911948bce669273139c6a124", + "axios": "^1.3.4", + "colors": "^1.4.0", + "discord-api-types": "^0.37.37", + "discord.js": "^14.8.0", + "ffmpeg-static": "^5.1.0", + "gm": "^1.25.0", + "jimp": "^0.22.7", + "libsodium-wrappers": "^0.7.11", + "lodash": "^4.17.21", + "translate": "^1.4.1", + "ts-node": "^10.9.1", + "typescript": "^4.8.2", + "winston": "^3.8.2" + }, + "resolutions": { + "jpeg-js": "0.4.4", + "protobufjs": "7.2.4" + } } \ No newline at end of file diff --git a/src/discordTools/discordEmbeds.js b/src/discordTools/discordEmbeds.js index ece33295b..c47e46359 100644 --- a/src/discordTools/discordEmbeds.js +++ b/src/discordTools/discordEmbeds.js @@ -26,11 +26,6 @@ const DiscordTools = require('./discordTools.js'); const InstanceUtils = require('../util/instanceUtils.js'); const Timer = require('../util/timer'); -function isValidUrl(url) { - if (url.startsWith('https') || url.startsWith('http')) return true; - return false; -} - module.exports = { getEmbed: function (options = {}) { const embed = new Discord.EmbedBuilder(); @@ -602,7 +597,7 @@ module.exports = { footer: { text: body.name }, title: data.title, description: data.message, - thumbnail: (body.img !== '' && isValidUrl(body.img)) ? body.img : 'attachment://rocket.png' + thumbnail: body.img !== '' ? body.img : 'attachment://rocket.png' }); }, diff --git a/src/handlers/inGameCommandHandler.js b/src/handlers/inGameCommandHandler.js index 8d606ef74..521bc6c21 100644 --- a/src/handlers/inGameCommandHandler.js +++ b/src/handlers/inGameCommandHandler.js @@ -99,6 +99,10 @@ module.exports = { commandLowerCase.startsWith(`${prefix}${client.intlGet(guildId, 'commandSyntaxLeader')}`)) { rustplus.sendInGameMessage(await rustplus.getCommandLeader(command, callerSteamId)); } + else if (commandLowerCase.startsWith(`${prefix}${client.intlGet('en', 'commandSyntaxMove')} `) || + commandLowerCase.startsWith(`${prefix}${client.intlGet(guildId, 'commandSyntaxMove')} `)) { + rustplus.sendInGameMessage(await rustplus.handleMoveCommand(command, callerSteamId, callerName)); + } else if ((commandLowerCase.startsWith(`${prefix}${client.intlGet('en', 'commandSyntaxMarker')} `) || commandLowerCase === `${prefix}${client.intlGet('en', 'commandSyntaxMarkers')}`) || (commandLowerCase.startsWith(`${prefix}${client.intlGet(guildId, 'commandSyntaxMarker')} `) || diff --git a/src/languages/cs.json b/src/languages/cs.json index e09ac66f7..c0eba9caa 100644 --- a/src/languages/cs.json +++ b/src/languages/cs.json @@ -93,6 +93,8 @@ "channelNameSwitches": "přepínače", "channelNameTeamchat": "týmový chat", "channelNameTrackers": "trackery", + "channelNotFound": "Nepodařilo se najít kanál: {channel}", + "errorFindingChannel": "Chyba při hledání kanálu: {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "Když na mapu vstoupí Chinook 47, pošleti notifikaci.", "chinook47EntersMap": "Chinook 47 vstupuje na mapu z {location} aby vyhodil uzamčenou bednu.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "jazyk", "commandSyntaxLarge": "velký", "commandSyntaxLeader": "vůdce", + "commandSyntaxMove": "přesunout", "commandSyntaxList": "list", "commandSyntaxMarker": "marker", "commandSyntaxMarkers": "markery", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Kanál nelze odstranit: {channelId}", "couldNotDeleteMessage": "Could not delete message: {message}", "couldNotFindAnyPlayers": "Could not find any players.", + "playersNotFound": "Nepodařilo se najít žádné odpovídající hráče.", + "multipleChannelsFound": "Nalezeno více kanálů: {channels}. Zadejte prosím přesnější název.", + "movedToChannel": "Přesunuto {count} hráč(ů) na kanál {channel}: {players}", + "userNotInVoice": "{user} není v hlasovém kanálu.", + "userAlreadyInChannel": "{user} je již v cílovém hlasovém kanálu.", + "failedToMoveUser": "Nepodařilo se přesunout uživatele {user}.", + "commandSyntaxMoveHelp": "Použití: .move [uživatel1 uživatel2 ...] nebo .move pro přesun sebe", + "noLinkedUserFound": "Nenalezen žádný propojený Discord účet. Propojte si účet nebo určete uživatele k přesunutí.", "couldNotFindCategory": "Could not find category: {category}", "couldNotFindChannel": "Could not find channel: {channel}", "couldNotFindCraftDetails": "Podrobnosti o craftu pro {name} nelze najít.", diff --git a/src/languages/de.json b/src/languages/de.json index 3f6e42a9c..e3bb22142 100644 --- a/src/languages/de.json +++ b/src/languages/de.json @@ -93,6 +93,8 @@ "channelNameSwitches": "schalter", "channelNameTeamchat": "teamchat", "channelNameTrackers": "tracker", + "channelNotFound": "Konnte den Kanal nicht finden: {channel}", + "errorFindingChannel": "Fehler beim Finden des Kanals: {error}", "chinook47": "Transporthubschr.", "chinook47DetectedSetting": "Wenn der Transporthubschrauber auf der Karte erscheint, sende eine Benachrichtigung.", "chinook47EntersMap": "Transporthubschrauber erscheint auf der Karte [{location}], um eine gesperrte Kiste abzuwerfen.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "sprache", "commandSyntaxLarge": "groß", "commandSyntaxLeader": "anführer", + "commandSyntaxMove": "verschieben", "commandSyntaxList": "liste", "commandSyntaxMarker": "markierung", "commandSyntaxMarkers": "markierungen", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Konnte Kanal nicht löschen: {channelId}", "couldNotDeleteMessage": "Konnte Nachricht nicht löschen: {message}", "couldNotFindAnyPlayers": "Konnte keine Spieler finden.", + "playersNotFound": "Keine passenden Spieler gefunden.", + "multipleChannelsFound": "Mehrere Kanäle gefunden: {channels}. Bitte gib einen genaueren Namen an.", + "movedToChannel": "{count} Spieler wurden in den Kanal {channel} verschoben: {players}", + "userNotInVoice": "{user} befindet sich nicht in einem Sprachkanal.", + "userAlreadyInChannel": "{user} befindet sich bereits im Ziel-Sprachkanal.", + "failedToMoveUser": "Verschieben von {user} fehlgeschlagen.", + "commandSyntaxMoveHelp": "Verwendung: .move [user1 user2 ...] oder .move , um dich selbst zu verschieben.", + "noLinkedUserFound": "Kein verknüpfter Discord-Account gefunden. Bitte verknüpfe deinen Account oder gib Benutzer an, die verschoben werden sollen.", "couldNotFindCategory": "Konnte Kategorie nicht finden: {category}", "couldNotFindChannel": "Konnte Kanal nicht finden: {channel}", "couldNotFindCraftDetails": "Konnte keine Details zur Herstellung von {name} finden.", diff --git a/src/languages/en.json b/src/languages/en.json index bb5fb961d..8540588e7 100644 --- a/src/languages/en.json +++ b/src/languages/en.json @@ -93,6 +93,8 @@ "channelNameSwitches": "switches", "channelNameTeamchat": "teamchat", "channelNameTrackers": "trackers", + "channelNotFound": "Could not find channel: {channel}", + "errorFindingChannel": "Error finding channel: {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "When a Chinook 47 enters the map, send a notification.", "chinook47EntersMap": "Chinook 47 enters the map from {location} to drop off Locked Crate.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "language", "commandSyntaxLarge": "large", "commandSyntaxLeader": "leader", + "commandSyntaxMove": "move", "commandSyntaxList": "list", "commandSyntaxMarker": "marker", "commandSyntaxMarkers": "markers", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Could not delete channel: {channelId}", "couldNotDeleteMessage": "Could not delete message: {message}", "couldNotFindAnyPlayers": "Could not find any players.", + "playersNotFound": "Could not find any matching players.", + "multipleChannelsFound": "Multiple channels found: {channels}. Please provide a more precise name.", + "movedToChannel": "Moved {count} player(s) to {channel}: {players}", + "userNotInVoice": "{user} is not in a voice channel.", + "userAlreadyInChannel": "{user} is already in the target voice channel.", + "failedToMoveUser": "Failed to move {user}.", + "commandSyntaxMoveHelp": "Usage: .move [user1 user2 ...] or .move to move yourself", + "noLinkedUserFound": "No linked Discord account found. Please link your account or specify users to move.", "couldNotFindCategory": "Could not find category: {category}", "couldNotFindChannel": "Could not find channel: {channel}", "couldNotFindCraftDetails": "Could not find craft details for {name}.", diff --git a/src/languages/es.json b/src/languages/es.json index 662e86e30..e2b09f164 100644 --- a/src/languages/es.json +++ b/src/languages/es.json @@ -93,6 +93,8 @@ "channelNameSwitches": "interruptores", "channelNameTeamchat": "chat-de-equipo", "channelNameTrackers": "rastreadores", + "channelNotFound": "No se pudo encontrar el canal: {channel}", + "errorFindingChannel": "Error al buscar el canal: {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "Cuando el Chinook 47 entre en el mapa, envía una notificación.", "chinook47EntersMap": "El Chinook entra en el mapa desde {location} para soltar la Caja Bloqueada.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "idioma", "commandSyntaxLarge": "grande", "commandSyntaxLeader": "líder", + "commandSyntaxMove": "mover", "commandSyntaxList": "lista", "commandSyntaxMarker": "marcador", "commandSyntaxMarkers": "marcadores", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "No se pudo borrar el canal: {channelId}", "couldNotDeleteMessage": "No se pudo eliminar el mensaje: {message}", "couldNotFindAnyPlayers": "No se pudo encontrar a ningún jugador.", + "playersNotFound": "No se encontraron jugadores que coincidan.", + "multipleChannelsFound": "Se encontraron varios canales: {channels}. Por favor, proporciona un nombre más preciso.", + "movedToChannel": "Se movieron {count} jugador(es) al canal {channel}: {players}", + "userNotInVoice": "{user} no está en un canal de voz.", + "userAlreadyInChannel": "{user} ya está en el canal de voz de destino.", + "failedToMoveUser": "No se pudo mover a {user}.", + "commandSyntaxMoveHelp": "Uso: .move [usuario1 usuario2 ...] o .move para moverte a ti mismo", + "noLinkedUserFound": "No se encontró una cuenta de Discord vinculada. Por favor vincula tu cuenta o especifica los usuarios a mover.", "couldNotFindCategory": "No se pudo encontrar la categoría: {category}", "couldNotFindChannel": "No se pudo encontrar el canal: {channel}", "couldNotFindCraftDetails": "Could not find craft details for {name}.", diff --git a/src/languages/fr.json b/src/languages/fr.json index ccc19587c..60408c218 100644 --- a/src/languages/fr.json +++ b/src/languages/fr.json @@ -93,6 +93,8 @@ "channelNameSwitches": "switches", "channelNameTeamchat": "teamchat", "channelNameTrackers": "trackeurs", + "channelNotFound": "Impossible de trouver le canal : {channel}", + "errorFindingChannel": "Erreur lors de la recherche du canal : {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "Lorsque le Chinook entre dans la map, envoyer une notification.", "chinook47EntersMap": "Le Chinook entre dans la map en {location} pour déposer une caisse.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "language", "commandSyntaxLarge": "large", "commandSyntaxLeader": "leader", + "commandSyntaxMove": "déplacer", "commandSyntaxList": "liste", "commandSyntaxMarker": "marqueur", "commandSyntaxMarkers": "marqueurs", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Impossible de supprimer le channel: {channelId}", "couldNotDeleteMessage": "Impossible de supprimer le message : {message}", "couldNotFindAnyPlayers": "Impossible de trouver des joueurs.", + "playersNotFound": "Aucun joueur correspondant trouvé.", + "multipleChannelsFound": "Plusieurs canaux trouvés : {channels}. Veuillez fournir un nom plus précis.", + "movedToChannel": "{count} joueur(s) déplacé(s) vers {channel} : {players}", + "userNotInVoice": "{user} n'est pas dans un canal vocal.", + "userAlreadyInChannel": "{user} est déjà dans le canal vocal cible.", + "failedToMoveUser": "Échec du déplacement de {user}.", + "commandSyntaxMoveHelp": "Utilisation : .move [utilisateur1 utilisateur2 ...] ou .move pour vous déplacer", + "noLinkedUserFound": "Aucun compte Discord lié trouvé. Veuillez lier votre compte ou spécifier les utilisateurs à déplacer.", "couldNotFindCategory": "Impossible de trouver la catégorie: {category}", "couldNotFindChannel": "Impossible de trouver le salon : {channel}", "couldNotFindCraftDetails": "Impossible de trouver les détails de l'artisanat pour {name}.", diff --git a/src/languages/it.json b/src/languages/it.json index 8c7c6c331..ad53f69b9 100644 --- a/src/languages/it.json +++ b/src/languages/it.json @@ -93,6 +93,8 @@ "channelNameSwitches": "interruttori", "channelNameTeamchat": "chat-team", "channelNameTrackers": "tracker", + "channelNotFound": "Impossibile trovare il canale: {channel}", + "errorFindingChannel": "Errore durante la ricerca del canale: {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "Quando un Chinook 47 entra nella mappa, invia una notifica.", "chinook47EntersMap": "Il Chinook 47 entra nella mappa da {location} per scaricare la cassa bloccata.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "lingua", "commandSyntaxLarge": "grande", "commandSyntaxLeader": "capo", + "commandSyntaxMove": "sposta", "commandSyntaxList": "elenco", "commandSyntaxMarker": "marcatore", "commandSyntaxMarkers": "marcatori", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Could not delete channel: {channelId}", "couldNotDeleteMessage": "Impossibile eliminare il messaggio: {message}", "couldNotFindAnyPlayers": "Impossibile trovare alcun giocatore.", + "playersNotFound": "Nessun giocatore corrispondente trovato.", + "multipleChannelsFound": "Trovati più canali: {channels}. Per favore fornisci un nome più preciso.", + "movedToChannel": "{count} giocatore(i) spostato(i) su {channel}: {players}", + "userNotInVoice": "{user} non è in un canale vocale.", + "userAlreadyInChannel": "{user} è già nel canale vocale di destinazione.", + "failedToMoveUser": "Impossibile spostare {user}.", + "commandSyntaxMoveHelp": "Uso: .move [utente1 utente2 ...] oppure .move per spostarti da solo", + "noLinkedUserFound": "Nessun account Discord collegato trovato. Per favore collega il tuo account o specifica gli utenti da spostare.", "couldNotFindCategory": "Impossibile trovare la categoria: {category}", "couldNotFindChannel": "Impossibile trovare il canale: {channel}", "couldNotFindCraftDetails": "Could not find craft details for {name}.", diff --git a/src/languages/ko.json b/src/languages/ko.json index 8fcb75144..e4e9ff17a 100644 --- a/src/languages/ko.json +++ b/src/languages/ko.json @@ -93,6 +93,8 @@ "channelNameSwitches": "스위치", "channelNameTeamchat": "팀 채팅", "channelNameTrackers": "추적기", + "channelNotFound": "채널을 찾을 수 없습니다: {channel}", + "errorFindingChannel": "채널을 찾는 중 오류가 발생했습니다: {error}", "chinook47": "치누크 47", "chinook47DetectedSetting": "치누크 47이 지도에서 탐지되면 알림을 보내줍니다.", "chinook47EntersMap": "치누크 47이 {location}에서 발견되었습니다.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "language", "commandSyntaxLarge": "large", "commandSyntaxLeader": "leader", + "commandSyntaxMove": "move", "commandSyntaxList": "list", "commandSyntaxMarker": "marker", "commandSyntaxMarkers": "markers", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Could not delete channel: {channelId}", "couldNotDeleteMessage": "{message} 메시지를 삭제할 수 없습니다.", "couldNotFindAnyPlayers": "플레이어를 찾을 수 없습니다.", + "playersNotFound": "일치하는 플레이어를 찾을 수 없습니다.", + "multipleChannelsFound": "여러 개의 채널이 발견되었습니다: {channels}. 더 정확한 이름을 입력해주세요.", + "movedToChannel": "{count}명의 플레이어를 {channel} 채널로 이동했습니다: {players}", + "userNotInVoice": "{user}님은 음성 채널에 있지 않습니다.", + "userAlreadyInChannel": "{user}님은 이미 대상 음성 채널에 있습니다.", + "failedToMoveUser": "{user}님을 이동하는 데 실패했습니다.", + "commandSyntaxMoveHelp": "사용법: .move [user1 user2 ...] <채널> 또는 .move <채널>을 사용해 자신을 이동하세요.", + "noLinkedUserFound": "연결된 Discord 계정을 찾을 수 없습니다. 계정을 연결하거나 이동할 사용자를 지정하세요.", "couldNotFindCategory": "{category} 카테고리를 찾을 수 없습니다.", "couldNotFindChannel": "{channel} 채널을 찾을 수 없습니다.", "couldNotFindCraftDetails": "Could not find craft details for {name}.", diff --git a/src/languages/pl.json b/src/languages/pl.json index d23121c4c..b6c0a27d2 100644 --- a/src/languages/pl.json +++ b/src/languages/pl.json @@ -93,6 +93,8 @@ "channelNameSwitches": "przełączniki", "channelNameTeamchat": "czat drużynowy", "channelNameTrackers": "trackers", + "channelNotFound": "Nie znaleziono kanału: {channel}", + "errorFindingChannel": "Błąd podczas wyszukiwania kanału: {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "Kiedy Chinok 47 wejdzie na mapę, wyślij powiadomienie.", "chinook47EntersMap": "Chinook 47 wchodzi na mapę z {location} aby zrzucić zablokowaną skrzynkę.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "język", "commandSyntaxLarge": "large", "commandSyntaxLeader": "leader", + "commandSyntaxMove": "move", "commandSyntaxList": "list", "commandSyntaxMarker": "marker", "commandSyntaxMarkers": "markers", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Could not delete channel: {channelId}", "couldNotDeleteMessage": "Could not delete message: {message}", "couldNotFindAnyPlayers": "Could not find any players.", + "playersNotFound": "Nie znaleziono pasujących graczy.", + "multipleChannelsFound": "Znaleziono wiele kanałów: {channels}. Proszę podać dokładniejszą nazwę.", + "movedToChannel": "Przeniesiono {count} gracza(-ów) do {channel}: {players}", + "userNotInVoice": "{user} nie jest na kanale głosowym.", + "userAlreadyInChannel": "{user} jest już na docelowym kanale głosowym.", + "failedToMoveUser": "Nie udało się przenieść {user}.", + "commandSyntaxMoveHelp": "Użycie: .move [użytkownik1 użytkownik2 ...] lub .move , aby przenieść siebie", + "noLinkedUserFound": "Nie znaleziono powiązanego konta Discord. Proszę połączyć konto lub określić użytkowników do przeniesienia.", "couldNotFindCategory": "Could not find category: {category}", "couldNotFindChannel": "Could not find channel: {channel}", "couldNotFindCraftDetails": "Could not find craft details for {name}.", diff --git a/src/languages/pt.json b/src/languages/pt.json index 3598ffffa..0bf7c02b7 100644 --- a/src/languages/pt.json +++ b/src/languages/pt.json @@ -93,6 +93,8 @@ "channelNameSwitches": "interruptores", "channelNameTeamchat": "ChatDeEquipa", "channelNameTrackers": "rastreadores", + "channelNotFound": "Não foi possível encontrar o canal: {channel}", + "errorFindingChannel": "Erro ao encontrar o canal: {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "Quando um Chinook 47 entra no mapa, envia uma notificação.", "chinook47EntersMap": "O Chinook 47 entra no mapa em {location} para largar uma Caixa Bloqueada.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "idioma", "commandSyntaxLarge": "grande", "commandSyntaxLeader": "líder", + "commandSyntaxMove": "mover", "commandSyntaxList": "lista", "commandSyntaxMarker": "marcador", "commandSyntaxMarkers": "marcadores", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Não foi possível apagar o canal: {channelId}", "couldNotDeleteMessage": "Não foi possível apagar a mensagem: {message}", "couldNotFindAnyPlayers": "Não foi possível encontrar nenhum jogador.", + "playersNotFound": "Não foi possível encontrar jogadores correspondentes.", + "multipleChannelsFound": "Vários canais encontrados: {channels}. Por favor, forneça um nome mais preciso.", + "movedToChannel": "Movido(s) {count} jogador(es) para {channel}: {players}", + "userNotInVoice": "{user} não está em um canal de voz.", + "userAlreadyInChannel": "{user} já está no canal de voz de destino.", + "failedToMoveUser": "Falha ao mover {user}.", + "commandSyntaxMoveHelp": "Uso: .move [usuário1 usuário2 ...] ou .move para mover a si mesmo", + "noLinkedUserFound": "Nenhuma conta Discord vinculada encontrada. Por favor, vincule sua conta ou especifique os usuários a serem movidos.", "couldNotFindCategory": "Não foi possível encontrar a categoria: {category}", "couldNotFindChannel": "Não foi possível encontrar o canal: {channel}", "couldNotFindCraftDetails": "Não foi possível encontrar detalhes de criação para {name}.", diff --git a/src/languages/ru.json b/src/languages/ru.json index f1d099369..777d7efa4 100644 --- a/src/languages/ru.json +++ b/src/languages/ru.json @@ -93,6 +93,8 @@ "channelNameSwitches": "переключатели", "channelNameTeamchat": "командный чат", "channelNameTrackers": "трекеры", + "channelNotFound": "Не удалось найти канал: {channel}", + "errorFindingChannel": "Ошибка при поиске канала: {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "Уведомление при обнаружении Chinook 47.", "chinook47EntersMap": "Chinook 47 появился на карте ({location}), чтобы сбросить запертый ящик.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "language", "commandSyntaxLarge": "large", "commandSyntaxLeader": "leader", + "commandSyntaxMove": "move", "commandSyntaxList": "list", "commandSyntaxMarker": "marker", "commandSyntaxMarkers": "markers", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Не удалось удалить канал: {channelId}", "couldNotDeleteMessage": "Не удалось удалить сообщение: {message}", "couldNotFindAnyPlayers": "Не удалось найти игроков.", + "playersNotFound": "Не удалось найти подходящих игроков.", + "multipleChannelsFound": "Найдено несколько каналов: {channels}. Пожалуйста, укажите более точное название.", + "movedToChannel": "Перемещено {count} игрок(а/ов) в {channel}: {players}", + "userNotInVoice": "{user} не находится в голосовом канале.", + "userAlreadyInChannel": "{user} уже находится в целевом голосовом канале.", + "failedToMoveUser": "Не удалось переместить {user}.", + "commandSyntaxMoveHelp": "Использование: .move [игрок1 игрок2 ...] <канал> или .move <канал> для перемещения себя", + "noLinkedUserFound": "Не найдена привязанная учетная запись Discord. Пожалуйста, привяжите свою учетную запись или укажите пользователей для перемещения.", "couldNotFindCategory": "Не удалось найти категорию: {category}", "couldNotFindChannel": "Не удалось найти канал: {channel}", "couldNotFindCraftDetails": "Не удалось найти сведения о создании для {name}.", diff --git a/src/languages/sv.json b/src/languages/sv.json index 8d71ed5bb..1a92db166 100644 --- a/src/languages/sv.json +++ b/src/languages/sv.json @@ -93,6 +93,8 @@ "channelNameSwitches": "strömbrytare", "channelNameTeamchat": "lagchatt", "channelNameTrackers": "spårare", + "channelNotFound": "Kunde inte hitta kanalen: {channel}", + "errorFindingChannel": "Fel vid sökning av kanal: {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "När en Chinook 47 kommer in på kartan, skicka en notifikation.", "chinook47EntersMap": "Chinook 47 kommer in på kartan från {location} för att lämna en låst låda.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "language", "commandSyntaxLarge": "large", "commandSyntaxLeader": "leader", + "commandSyntaxMove": "move", "commandSyntaxList": "list", "commandSyntaxMarker": "marker", "commandSyntaxMarkers": "markers", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Could not delete channel: {channelId}", "couldNotDeleteMessage": "Kunde inte radera meddelandet: {message}.", "couldNotFindAnyPlayers": "Kunde inte hitta några spelare.", + "playersNotFound": "Hittade inga matchande spelare.", + "multipleChannelsFound": "Flera kanaler hittades: {channels}. Vänligen ange ett mer exakt namn.", + "movedToChannel": "Flyttade {count} spelare till {channel}: {players}", + "userNotInVoice": "{user} är inte i en röstkanal.", + "userAlreadyInChannel": "{user} är redan i mål-röstkanalen.", + "failedToMoveUser": "Misslyckades med att flytta {user}.", + "commandSyntaxMoveHelp": "Användning: .move [användare1 användare2 ...] eller .move för att flytta dig själv", + "noLinkedUserFound": "Inget länkat Discord-konto hittades. Vänligen länka ditt konto eller specificera användare att flytta.", "couldNotFindCategory": "Kunde inte hitta kategorin: {category}.", "couldNotFindChannel": "Kunde inte hitta kanalen: {channel}.", "couldNotFindCraftDetails": "Could not find craft details for {name}.", diff --git a/src/languages/tr.json b/src/languages/tr.json index c8b7e925d..082b934ef 100644 --- a/src/languages/tr.json +++ b/src/languages/tr.json @@ -93,6 +93,8 @@ "channelNameSwitches": "anahtarlar", "channelNameTeamchat": "ekip sohbeti", "channelNameTrackers": "izleyiciler", + "channelNotFound": "{channel} kanalı bulunamadı", + "errorFindingChannel": "Kanal bulunurken hata oluştu: {error}", "chinook47": "Chinook 47", "chinook47DetectedSetting": "Chinook 47 haritaya girdiğinde bildirim gönder.", "chinook47EntersMap": "Chinook 47 {location} konumundan kilitli sandık bırakmak için haritaya giriş yaptı.", @@ -126,6 +128,7 @@ "commandSyntaxLanguage": "language", "commandSyntaxLarge": "large", "commandSyntaxLeader": "leader", + "commandSyntaxMove": "move", "commandSyntaxList": "list", "commandSyntaxMarker": "marker", "commandSyntaxMarkers": "markers", @@ -285,6 +288,14 @@ "couldNotDeleteChannel": "Could not delete channel: {channelId}", "couldNotDeleteMessage": "Mesaj silinmedi: {message}", "couldNotFindAnyPlayers": "Herhangi bir oyuncu bulunamadı.", + "playersNotFound": "Eşleşen oyuncu bulunamadı.", + "multipleChannelsFound": "Birden fazla kanal bulundu: {channels}. Lütfen daha kesin bir isim verin.", + "movedToChannel": "{count} oyuncu {channel} kanalına taşındı: {players}", + "userNotInVoice": "{user} bir ses kanalında değil.", + "userAlreadyInChannel": "{user} zaten hedef ses kanalında.", + "failedToMoveUser": "{user} taşınamadı.", + "commandSyntaxMoveHelp": "Kullanım: .move [kullanıcı1 kullanıcı2 ...] veya .move kendinizi taşımak için", + "noLinkedUserFound": "Bağlı bir Discord hesabı bulunamadı. Lütfen hesabınızı bağlayın veya taşınacak kullanıcıları belirtin.", "couldNotFindCategory": "Kategori bulunamadı: {category}", "couldNotFindChannel": "Kanal bulunamadı: {channel}", "couldNotFindCraftDetails": "Could not find craft details for {name}.", diff --git a/src/structures/RustPlus.js b/src/structures/RustPlus.js index 39820fa6a..a4ef963ea 100644 --- a/src/structures/RustPlus.js +++ b/src/structures/RustPlus.js @@ -1479,6 +1479,226 @@ class RustPlus extends RustPlusLib { return strings; } + async handleMoveCommand(command, callerSteamId, callerName) { + const args = command.split(' ').slice(1); + if (args.length < 1) { + return Client.client.intlGet(this.guildId, 'commandSyntaxMoveHelp'); + } + + const guild = Client.client.guilds.cache.get(this.guildId); + if (!guild) { + return Client.client.intlGet(this.guildId, 'couldNotFindGuild', { guildId: this.guildId }); + } + + const me = await guild.members.fetch(Client.client.user.id); + if (!me.permissions.has('MOVE_MEMBERS')) { + return Client.client.intlGet(this.guildId, 'missingMoveMembersPermission'); + } + + let targetChannelInput, playerNames; + + if (args.length === 1) { + targetChannelInput = args[0]; + + const fs = require('fs'); + const path = require('path'); + const credentialsPath = path.join(__dirname, '..', '..', 'credentials', `${this.guildId}.json`); + + try { + if (fs.existsSync(credentialsPath)) { + const credentialsData = JSON.parse(fs.readFileSync(credentialsPath, 'utf8')); + console.log('Credentials data:', JSON.stringify(credentialsData, null, 2)); + + if (credentialsData[callerSteamId]?.discord_user_id) { + const discordUserId = credentialsData[callerSteamId].discord_user_id; + console.log(`Found Discord ID ${discordUserId} for SteamID ${callerSteamId}`); + playerNames = [discordUserId]; + } else { + console.log(`No Discord ID linked for SteamID ${callerSteamId} in credentials`); + console.log('Available Steam IDs in credentials:', Object.keys(credentialsData).filter(k => k !== 'hoster')); + return Client.client.intlGet(this.guildId, 'noLinkedUserFound'); + } + } else { + console.log(`Credentials file not found: ${credentialsPath}`); + return Client.client.intlGet(this.guildId, 'noLinkedUserFound'); + } + } catch (error) { + console.error('Error reading user data:', error); + return Client.client.intlGet(this.guildId, 'noLinkedUserFound'); + } + } else { + targetChannelInput = args[args.length - 1]; + playerNames = args.slice(0, -1); + } + + let targetChannel = guild.channels.cache.get(targetChannelInput); + + if (!targetChannel) { + try { + const voiceChannels = guild.channels.cache.filter( + c => c.type === 'GUILD_VOICE' || c.type === 2 + ); + + targetChannel = voiceChannels.find( + c => c.name.toLowerCase() === targetChannelInput.toLowerCase() + ); + + if (!targetChannel) { + const matchingChannels = voiceChannels.filter( + c => c.name.toLowerCase().includes(targetChannelInput.toLowerCase()) + ); + + if (matchingChannels.size === 1) { + targetChannel = matchingChannels.first(); + } else if (matchingChannels.size > 1) { + return Client.client.intlGet(this.guildId, 'multipleChannelsFound', { + channels: matchingChannels.map(c => c.name).join(', ') + }); + } + } + + if (!targetChannel) { + const instance = Client.client.getInstance(this.guildId); + const aliases = instance.aliases || {}; + const alias = Object.entries(aliases).find( + ([, v]) => v.toLowerCase() === targetChannelInput.toLowerCase() + ); + + if (alias) { + targetChannel = voiceChannels.get(alias[0]); + } + } + + if (!targetChannel) { + return Client.client.intlGet(this.guildId, 'channelNotFound', { channel: targetChannelInput }); + } + } catch (error) { + console.error('Error finding voice channel:', error); + return Client.client.intlGet(this.guildId, 'errorFindingChannel', { error: error.message }); + } + } + + const results = { + moved: [], + failed: [], + notFound: [] + }; + + for (const name of playerNames) { + const searchName = name.toLowerCase(); + let member = null; + + member = guild.members.cache.get(name); + console.log(`Looking for member with ID: ${name}`); + + if (member) { + console.log(`Found member by ID: ${member.user.tag} (${member.id})`); + } else { + console.log(`No member found with ID: ${name}`); + + const voiceMembers = guild.members.cache.filter(m => m.voice?.channelId); + console.log(`Searching in ${voiceMembers.size} voice members...`); + + member = voiceMembers.find(m => + m.user.id === name || + m.displayName?.toLowerCase() === searchName || + m.nickname?.toLowerCase() === searchName || + m.user.username.toLowerCase() === searchName + ); + + if (!member) { + member = voiceMembers.find(m => + m.displayName?.toLowerCase().includes(searchName) || + m.nickname?.toLowerCase().includes(searchName) || + m.user.username.toLowerCase().includes(searchName) + ); + } + + if (!member) { + console.log('Searching in all members...'); + member = guild.members.cache.find(m => { + const displayName = m.displayName?.toLowerCase(); + const nickname = m.nickname?.toLowerCase(); + const username = m.user.username.toLowerCase(); + + return m.user.id === name || + displayName === searchName || + nickname === searchName || + username === searchName || + displayName?.includes(searchName) || + nickname?.includes(searchName) || + username.includes(searchName); + }); + } + + if (member) { + console.log(`Found member by name: ${member.user.tag} (${member.id})`); + } else { + console.log('No member found with any search method'); + } + } + + if (!member) { + results.notFound.push(name); + continue; + } + + if (!member.voice?.channelId) { + results.failed.push({ name: member.displayName, reason: 'not_in_voice' }); + continue; + } + + if (member.voice.channelId === targetChannel.id) { + results.failed.push({ + name: member.displayName, + reason: 'already_in_channel' + }); + continue; + } + + try { + await member.voice.setChannel(targetChannel); + results.moved.push(member.displayName); + } catch (error) { + console.error(`Failed to move ${member.displayName}:`, error); + results.failed.push({ + name: member.displayName, + reason: error.message.includes('permissions') ? 'missing_permissions' : 'other_error' + }); + } + } + + const messages = []; + + if (results.moved.length > 0) { + messages.push(Client.client.intlGet(this.guildId, 'movedToChannel', { + count: results.moved.length, + players: results.moved.join(', '), + channel: targetChannel.name + })); + } + + if (results.failed.length > 0) { + const failedMessages = results.failed.map(f => + Client.client.intlGet(this.guildId, + f.reason === 'not_in_voice' ? 'userNotInVoice' : + f.reason === 'already_in_channel' ? 'userAlreadyInChannel' : 'failedToMoveUser', + { user: f.name } + ) + ); + messages.push(failedMessages.join('\n')); + } + + if (results.notFound.length > 0) { + messages.push(Client.client.intlGet(this.guildId, 'playersNotFound', { + count: results.notFound.length, + players: results.notFound.join(', ') + })); + } + + return messages.join('\n'); + } + async getCommandLeader(command, callerSteamId) { const prefix = this.generalSettings.prefix; const commandLeader = `${prefix}${Client.client.intlGet(this.guildId, 'commandSyntaxLeader')}`; diff --git a/src/util/keywords.js b/src/util/keywords.js index c1c350feb..b4be663dd 100644 --- a/src/util/keywords.js +++ b/src/util/keywords.js @@ -55,6 +55,7 @@ module.exports = { client.intlGet(guildId, 'commandSyntaxSteamid'), client.intlGet(guildId, 'commandSyntaxTeam'), client.intlGet(guildId, 'commandSyntaxTime'), + client.intlGet(guildId, 'commandSyntaxMove'), client.intlGet(guildId, 'commandSyntaxTimer'), client.intlGet(guildId, 'commandSyntaxTimers'), client.intlGet(guildId, 'commandSyntaxTranslateTo'), @@ -98,6 +99,7 @@ module.exports = { client.intlGet('en', 'commandSyntaxSteamid'), client.intlGet('en', 'commandSyntaxTeam'), client.intlGet('en', 'commandSyntaxTime'), + client.intlGet('en', 'commandSyntaxMove'), client.intlGet('en', 'commandSyntaxTimer'), client.intlGet('en', 'commandSyntaxTimers'), client.intlGet('en', 'commandSyntaxTranslateTo'),