Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ In-Game Command | Description
--------------- | -----------
[**afk**](commands.md#afk) | Get the currently afk players in your team.
[**alive**](commands.md#alive) | Get the player with the longest time alive.
[**calc**](commands.md#calc) | Calculate a mathematical expression.
[**cargo**](commands.md#cargo) | Get information about CargoShip (Location, time till enters egress stage, time since last on map).
[**chinook**](commands.md#chinook) | Get information about Chinook 47 (Location, time since last on map).
[**connection/connections**](commands.md#connectionconnections) | Get recent connection events.
Expand Down Expand Up @@ -401,6 +402,12 @@ In-Game Command | Description

![In-Game Command alive Image](images/ingame_commands/alive_ingame.png)

## **calc**

> **Calculate a mathematical expression.**
<br>Command: `!calc 1+1`
<br>Command: `!calc 17*33`


## **cargo**

Expand Down
37 changes: 37 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/handlers/discordCommandHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ module.exports = {
commandLowerCase.startsWith(`${prefix}${client.intlGet(guildId, 'commandSyntaxAlive')}`)) {
response = rustplus.getCommandAlive(command);
}
else if ((commandLowerCase.startsWith(`${prefix}${client.intlGet('en', 'commandSyntaxCalc')} `) ||
commandLowerCase === `${prefix}${client.intlGet('en', 'commandSyntaxCalc')}`) ||
(commandLowerCase.startsWith(`${prefix}${client.intlGet(guildId, 'commandSyntaxCalc')} `) ||
commandLowerCase === `${prefix}${client.intlGet(guildId, 'commandSyntaxCalc')}`)) {
response = rustplus.getCommandCalc(client, command);
}
else if (commandLowerCase === `${prefix}${client.intlGet('en', 'commandSyntaxCargo')}` ||
commandLowerCase === `${prefix}${client.intlGet(guildId, 'commandSyntaxCargo')}`) {
response = rustplus.getCommandCargo();
Expand Down
6 changes: 6 additions & 0 deletions src/handlers/inGameCommandHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ module.exports = {
commandLowerCase.startsWith(`${prefix}${client.intlGet(guildId, 'commandSyntaxAlive')}`)) {
rustplus.sendInGameMessage(rustplus.getCommandAlive(command));
}
else if ((commandLowerCase.startsWith(`${prefix}${client.intlGet('en', 'commandSyntaxCalc')} `) ||
commandLowerCase === `${prefix}${client.intlGet('en', 'commandSyntaxCalc')}`) ||
(commandLowerCase.startsWith(`${prefix}${client.intlGet(guildId, 'commandSyntaxCalc')} `) ||
commandLowerCase === `${prefix}${client.intlGet(guildId, 'commandSyntaxCalc')}`)) {
rustplus.sendInGameMessage(rustplus.getCommandCalc(client, command));
}
else if (commandLowerCase === `${prefix}${client.intlGet('en', 'commandSyntaxCargo')}` ||
commandLowerCase === `${prefix}${client.intlGet(guildId, 'commandSyntaxCargo')}`) {
rustplus.sendInGameMessage(rustplus.getCommandCargo());
Expand Down
3 changes: 2 additions & 1 deletion src/languages/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Wipe byl detekován!",
"yield": "Úrodnost",
"youAreAlreadyLeader": "Už jsi vůdce.",
"youAreNotPairedWithServer": "Příkaz na vůdce nefunguje, protože nejsi spárován se serverem."
"youAreNotPairedWithServer": "Příkaz na vůdce nefunguje, protože nejsi spárován se serverem.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Wipe erkannt!",
"yield": "Ertrag",
"youAreAlreadyLeader": "Du bist bereits Anführer.",
"youAreNotPairedWithServer": "Anführer-Befehl funktioniert nicht, weil du nicht mit dem Server gekoppelt bist."
"youAreNotPairedWithServer": "Anführer-Befehl funktioniert nicht, weil du nicht mit dem Server gekoppelt bist.",
"commandSyntaxCalc": "calc"
}
5 changes: 3 additions & 2 deletions src/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@
"travelingVendorHaltedSetting": "When the Traveling Vendor stops moving, send a notification.",
"travelingVendorLeftSetting": "When the Traveling Vendor left the map, send a notification.",
"travelingVendorLocatedAt": "The Traveling Vendor is located at {location}.",
"travelingVendorLeftMap" : "The Traveling Vendor just left the map at {location}.",
"travelingVendorLeftMap": "The Traveling Vendor just left the map at {location}.",
"travelingVendorNotCurrentlyOnMap": "The Traveling Vendor is not currently on the map.",
"travelingVendorResumedAt": "The Traveling Vendor resumed moving at {location}.",
"travelingVendorSpawnedAt": "The Traveling Vendor spawned at {location}.",
Expand Down Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Wipe detected!",
"yield": "Yield",
"youAreAlreadyLeader": "You are already leader.",
"youAreNotPairedWithServer": "Leader command does not work because you're not paired with the server."
"youAreNotPairedWithServer": "Leader command does not work because you're not paired with the server.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "¡Wipe detectado!",
"yield": "Yield",
"youAreAlreadyLeader": "Ya eres líder.",
"youAreNotPairedWithServer": "El comando líder no funciona porque no está emparejado con el servidor."
"youAreNotPairedWithServer": "El comando líder no funciona porque no está emparejado con el servidor.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Wipe detecté!",
"yield": "Rendement",
"youAreAlreadyLeader": "Vous êtes déjà le chef du groupe.",
"youAreNotPairedWithServer": "La commande Leader ne fonctionne pas car n'est pas associé au serveur."
"youAreNotPairedWithServer": "La commande Leader ne fonctionne pas car n'est pas associé au serveur.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Rilevato wipe!",
"yield": "Yield",
"youAreAlreadyLeader": "Sei già il leader.",
"youAreNotPairedWithServer": "Il comando del leader non funziona perché non sei associato al server."
"youAreNotPairedWithServer": "Il comando del leader non funziona perché non sei associato al server.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "서버 초기화가 감지되었습니다!",
"yield": "Yield",
"youAreAlreadyLeader": "당신은 이미 팀 리더 입니다.",
"youAreNotPairedWithServer": "서버와 페어링되지 않았기 때문에 리더 명령어가 작동하지 않습니다."
"youAreNotPairedWithServer": "서버와 페어링되지 않았기 때문에 리더 명령어가 작동하지 않습니다.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Wipe detected!",
"yield": "Plon",
"youAreAlreadyLeader": "You are already leader.",
"youAreNotPairedWithServer": "Leader command does not work because you're not paired with the server."
"youAreNotPairedWithServer": "Leader command does not work because you're not paired with the server.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Wipe detetado!",
"yield": "Rendimento",
"youAreAlreadyLeader": "Você já é o líder.",
"youAreNotPairedWithServer": "O comando Líder não funciona porque você não está emparelhado com o servidor."
"youAreNotPairedWithServer": "O comando Líder não funciona porque você não está emparelhado com o servidor.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Обнаружен Wipe!",
"yield": "Урожай",
"youAreAlreadyLeader": "Вы уже лидер.",
"youAreNotPairedWithServer": "Команда лидера не работает, потому что вы не подключены к серверу."
"youAreNotPairedWithServer": "Команда лидера не работает, потому что вы не подключены к серверу.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Rensning upptäcktes!",
"yield": "Yield",
"youAreAlreadyLeader": "Du är redan lagledare.",
"youAreNotPairedWithServer": "Leader-kommandot fungerar inte eftersom du inte är parad med servern."
"youAreNotPairedWithServer": "Leader-kommandot fungerar inte eftersom du inte är parad med servern.",
"commandSyntaxCalc": "calc"
}
3 changes: 2 additions & 1 deletion src/languages/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,6 @@
"wipeDetected": "Wipe tespit edildi!",
"yield": "Teslim Ol",
"youAreAlreadyLeader": "Zaten lidersin.",
"youAreNotPairedWithServer": "Sunucuyla eşleşmediğiniz için lider komutu çalışmıyor."
"youAreNotPairedWithServer": "Sunucuyla eşleşmediğiniz için lider komutu çalışmıyor.",
"commandSyntaxCalc": "calc"
}
28 changes: 28 additions & 0 deletions src/structures/RustPlus.js
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,34 @@ class RustPlus extends RustPlusLib {
});
}

getCommandCalc(client, command) {
const prefix = this.generalSettings.prefix;
const commandCalc = `${prefix}${client.intlGet(this.guildId, 'commandSyntaxCalc')}`;
const commandCalcEn = `${prefix}${client.intlGet('en', 'commandSyntaxCalc')}`;

let expr = '';
if (command.toLowerCase().startsWith(`${commandCalc} `)) {
expr = command.substring(commandCalc.length).trim();
}
else if (command.toLowerCase().startsWith(`${commandCalcEn} `)) {
expr = command.substring(commandCalcEn.length).trim();
}

if (expr === '') return client.intlGet(this.guildId, 'missingArguments');

try {
const safeExpr = expr.replace(/[^\d.\+\-\*\/\(\)\s]/g, '');
if (safeExpr.length === 0) return client.intlGet(this.guildId, 'errorExecutingCommand');

const res = new Function(`return (${safeExpr});`)();
if (res === undefined || Number.isNaN(res)) return client.intlGet(this.guildId, 'errorExecutingCommand');

return `${client.intlGet(this.guildId, 'calculated')}: ${expr} = ${res}`;
} catch(e) {
return client.intlGet(this.guildId, 'errorExecutingCommand');
}
}

getCommandCargo(isInfoChannel = false) {
const strings = [];
let unhandled = this.mapMarkers.cargoShips.map(e => e.id);
Expand Down
123 changes: 123 additions & 0 deletions ubuntu_install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/bin/bash
# ubuntu_install.sh
# Automatically clones repository and starts the bot using pm2 interactively

set -e

REPO_URL="https://github.com/abboodnoga176-max/rustplusplus.git"
INSTALL_DIR="$HOME/rustplusplus"

echo "=== Rustplusplus Ubuntu Installer ==="

echo "Checking for required dependencies..."
sudo apt-get update
sudo apt-get install -y git curl build-essential

if ! command -v node >/dev/null 2>&1; then
echo "Node.js not found. Installing Node.js..."
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
fi

if ! command -v pm2 >/dev/null 2>&1; then
echo "PM2 not found. Installing PM2 globally..."
sudo npm install -g pm2
fi

if [ -d "$INSTALL_DIR" ]; then
echo "Directory $INSTALL_DIR already exists."
else
echo "Cloning rustplusplus..."
git clone "$REPO_URL" "$INSTALL_DIR"
fi

cd "$INSTALL_DIR"

echo "Installing NPM dependencies..."
npm install

ENV_FILE=".env"
if [ ! -f "$ENV_FILE" ]; then
echo ""
echo "--- Discord Credentials Setup ---"
read -p "Enter your RPP_DISCORD_CLIENT_ID: " DISCORD_CLIENT_ID
read -p "Enter your RPP_DISCORD_TOKEN: " DISCORD_TOKEN

cat <<ENV > "$ENV_FILE"
RPP_DISCORD_CLIENT_ID=$DISCORD_CLIENT_ID
RPP_DISCORD_TOKEN=$DISCORD_TOKEN
ENV
echo "Credentials saved to $ENV_FILE"
else
echo "Credentials already exist in $ENV_FILE"
fi

UPDATE_SCRIPT="$INSTALL_DIR/ubuntu_update.sh"
cat << 'UPSCRIPT' > "$UPDATE_SCRIPT"
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$DIR"

# Fetch latest changes
git fetch origin

LOCAL=$(git rev-parse HEAD)
REMOTE=$(git rev-parse @{u})

if [ "$LOCAL" != "$REMOTE" ]; then
echo "Updates found. Sending restart notification..."

if [ -f "notify_restart.js" ]; then
node notify_restart.js
sleep 5
fi

git reset --hard origin/master
npm install

pm2 restart rustplusplus
echo "Update complete."
fi
UPSCRIPT

chmod +x "$UPDATE_SCRIPT"

NOTIFY_SCRIPT="$INSTALL_DIR/notify_restart.js"
cat << 'NJSCRIPT' > "$NOTIFY_SCRIPT"
require('dotenv').config();
const { Client, GatewayIntentBits, ChannelType } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] });

client.on('ready', async () => {
try {
const guilds = client.guilds.cache;
for (const [id, guild] of guilds) {
const channels = guild.channels.cache.filter(c => c.type === ChannelType.GuildText);
const infoChannel = channels.find(c => c.name === 'information' && c.parent && c.parent.name === 'rustplusplus');
if (infoChannel) {
await infoChannel.send('⚠️ **Notice:** The bot is restarting to apply a new update. It will be back shortly!').catch(() => {});
}
}
} catch (e) {
console.error("Error sending restart notifications:", e);
}
client.destroy();
});
client.login(process.env.RPP_DISCORD_TOKEN).catch(()=>console.log("Could not login to notify"));
NJSCRIPT

CRON_JOB="*/5 * * * * $UPDATE_SCRIPT >> $INSTALL_DIR/logs/auto_update.log 2>&1"
(crontab -l 2>/dev/null | grep -Fv "ubuntu_update.sh"; echo "$CRON_JOB") | crontab -
echo "Cron job added to check for updates every 5 minutes."

mkdir -p "$INSTALL_DIR/logs"

echo "Starting bot with PM2..."
npm install dotenv --no-save
pm2 start npm --name "rustplusplus" -- run start
pm2 save
pm2 startup | grep "sudo" | bash || true

echo "=== Installation Complete ==="
echo "Bot is now running in the background via PM2."
echo "Use 'pm2 logs rustplusplus' to view logs."