RustPlusBot plugins allow you to develop your own commands to add functionality to the bot. The plugin itself exposes many events for a programmer to attach to and execute code.
The plugins are written in JavaScript and run in a NodeJS environment after they are published. During development, you host the plugin on your client machine and in your web-browser. Your plugin interfaces with the bot via a WebSocket connection and communicates using the RustPlusBot api.
Note
Plugins are loaded when the bot is starting and lasts for its entire life-cycle. Restarting the bot also restarts all plugins.
You can load any of the official plugins and use them as a template for getting started in the Plugin Studio. The Plugin Studio can be accessed via a link in the Plugin settings tab on the RustPlusBot settings page for your Discord server.
You can find the list of plugin examples in the plugin examples section.
For data that persists beyond the bot's instance, use this.storage. This object loads with the bot and saves when it stops or restarts.
// store the myData variable
if (!this.storage.myData) this.storage.myData = 'Hello World!';
console.log(this.storage.myData);
onConnected()Fires when the bot connects to a server or when the plugin loadsonDisconnected()Fires when the bot disconnects from a serveronEntityChanged(obj)Fires when a paired Smart Device is changed- obj.entityId:
intThe entity ID of the Smart device - obj.payload:
objectThe payload data of the event (seePayloadbelow)
- obj.entityId:
onMessageReceive(obj)Fires when a team chat message is received- obj.message:
stringThe incoming team chat message - obj.name:
stringThe steam name of the sender - obj.steamId:
stringThe steam ID of the sender
- obj.message:
onMessageSend(obj)Fires when a team chat message is sent- obj.message:
stringThe outgoing team chat message
- obj.message:
onNotification(obj)Fires when there is a bot notification (including server events)- obj.notification:
objectThe notification data of the event (see allNotificationbelow)
- obj.notification:
onTeamChanged(obj)Fires when the team leader changes, or a team member is added or removed from the team
Note
To handle bot configuration changes or other update events, take a look at registeredHandlers.
The app object exists in the plugin's scope this, and exposes the following properties and methods:
bmDataobjectAn object containing the BattleMetrics data of the server (seeBattleMetrics Databelow)camerasarrayAn array containing all camera indentifiers saved from the Camera StationcfgobjectAn object containing the configuration settings for the bot (seeConfigbelow)devicesMapA Map object containing the bot's paired devices (key: device name (lowercase only), value: Array of devices, seeDevicebelow)devices_autoMapA Map object containing the bot's automatic paired devices function (key: device name, value: An object containing the automatic function config (seeDeviceAutobelow))devices_iconsMapA Map object containing the bot's paired device icons (key: device name, value: The icon name of the device)devices_mapMapA Map object containing the bot's paired device names (key: device ID, value: Array of lowercased device names)event_typesMapA Map object containing server event names (key: event ID, value: event name)eventTimersobjectAn object containing the respawn timers for server events in seconds (seeEvent Timersbelow)guild_tokenstringThe unique token representing the Discord serverguild_namestringThe name of the Discord serveritemIdsMapA Map object containing the item names for all item IDs (key: item ID, value: item name)itemShortnamesMapA Map object containing the item shortnames for all item IDs (key: item ID, value: item shortname)monumentsMapA Map object containing all monument tokens and locations (key: monument token, value: Array of monument locations, seePointbelow)tokenMapMapA Map object containing the monument names for all monument tokens (key: monument token, value: monument name)player_idstringThe steam ID of the bot's connected playerplayer_namestringThe steam name of the bot's connected playerserver_ipstringThe IP address of the bot's connected serverserver_namestringThe name of the bot's connected serverserver_portstringThe port of the bot's connected server (Rust+ app port)server_tagsstringInternal tags used to describe this server
// get the bot's language setting
console.log(this.app.cfg.lang);
getBattleMetrics(playerName, success, error)Retrieve the BattleMetrics info for a server player using their player name- playerName:
stringThe name of the player - success(data):
functionThe function to execute after receiving the BattleMetrics data (optional) - error(err):
functionThe function to execute when an error occurs (optional) - returns:
booltrue
// getBattleMetrics example var app = this.app; app.getBattleMetrics('Rust Player 2099', (data) => { if (data && data.name) { if (data.online) app.sendTeamMessage('Player ' + cmdFormat(data.id) + ' \'' + cmdFormat(data.name) + '\' is ONLINE and has been connected for ' + getTimeDisplay(getTimeDifference(new Date(data.lastseen)), true)); else app.sendTeamMessage('Player ' + cmdFormat(data.id) + ' \'' + cmdFormat(data.name) + '\' is OFFLINE and was last seen ' + getFriendlyDate(data.lastseen)); app.sendTeamMessage('Player ' + cmdFormat(data.id) + ' was first seen ' + getFriendlyDate(data.firstseen) + ' and their time played is ' + getTimeDisplay(data.timeplayed, true)); } else if (data && data.indexOf('unavailable') > 0) { app.sendTeamMessage(data); } else app.sendTeamMessage('Server player not found'); }, (error) => { app.sendTeamMessage('Error obtaining the BattleMetrics data: ' + error); });- playerName:
getBattleMetricsId(playerId, success, error)Retrieve the BattleMetrics info for a server player using their BattleMetrics ID- playerId:
intThe BattleMetrics ID of the player - success(data):
functionThe function to execute after receiving the BattleMetricsId data (optional) - error(err):
functionThe function to execute when an error occurs (optional) - returns:
booltrue
// getBattleMetricsId example var app = this.app; app.getBattleMetricsId(123456789, (data) => { if (data && data.name) { app.sendTeamMessage('Player ' + cmdFormat(data.id) + ' \'' + cmdFormat(data.name) + '\' is ' + ((data.online) ? 'ONLINE' : 'OFFLINE')); if (data.lastseen) app.sendTeamMessage('Player ' + cmdFormat(data.id) + ' has been connected for ' + getTimeDisplay(getTimeDifference(new Date(data.lastseen)), true)); } else app.sendTeamMessage('Server player not found'); }, (error) => { app.sendTeamMessage('Error obtaining the BattleMetricsId data: ' + error); });- playerId:
getCameraPlayers(id, callback)Get all player names visible on the specified camera- id:
stringThe identifier of the camera - callback(players, playersDistances):
functionThe function to execute after getting the players list and players distances list (playersis anarrayof player names andplayersDistancesis anarrayof player distances in meters) - returns:
booltrueif successful
// getCameraPlayers example var app = this.app; app.getCameraPlayers('CAMERA_ID', (players, playersDistances) => { if (players && players.length > 0) { for (var i = 0; i < players.length; i++) players[i] += ' [' + playersDistances[i] + 'm]'; app.sendTeamMessage('Detected these players: ' + players.join(', ')); } else { app.sendTeamMessage('No players detected on camera'); } });- id:
getCameraPlayersFiltered(id, callback)Get only non-team member player names visible on the specified camera- id:
stringThe identifier of the camera - callback(players, playersDistances):
functionThe function to execute after getting the players list and players distances list (playersis anarrayof player names andplayersDistancesis anarrayof player distances in meters) - returns:
booltrueif successful
// getCameraPlayersFiltered example var app = this.app; app.getCameraPlayersFiltered('CAMERA_ID', (players, playersDistances) => { if (players && players.length > 0) { for (var i = 0; i < players.length; i++) players[i] += ' [' + playersDistances[i] + 'm]'; app.sendTeamMessage('Detected these enemy players: ' + players.join(', ')); } else { app.sendTeamMessage('No enemy players detected on camera'); } });- id:
getConnected()Get the date of the server connection- returns:
stringa Date string
// getConnected example var connected = await this.app.getConnected(); console.log(new Date(connected));- returns:
getCrateTimer()Get the configured crate unlock timer- returns:
intvalue
// getCrateTimer example var timer = await this.app.getCrateTimer(); this.app.sendTeamMessage('Crate unlock timer is set to: ' + getTimeDisplay(timer));- returns:
getDetailedInfo(callback)Get detailed information about the server- callback(data):
functionThe function to execute after getting the detailed info (dataisDetailedInfo) - returns:
booltrueif successful
// getDetailedInfo example var app = this.app; app.getDetailedInfo((data) => { if (data && data.players) { app.sendTeamMessage('Current server population is ' + data.players); app.sendTeamMessage('Current server time is ' + data.time); } });- callback(data):
getEntityInfo(id, callback)Get data from a Smart device- id:
intThe identifier of the Smart device - callback(message):
functionThe function to execute after getting the entity info (message.responsecontainsEntityInfo) - returns:
booltrueif successful
// getEntityInfo example var app = this.app; app.getEntityInfo(123456, (message) => { if (message.response && message.response.entityInfo && message.response.entityInfo.payload) { app.sendTeamMessage('This device is: ' + ((message.response.entityInfo.payload.value) ? 'On' : 'Off')); } else { app.sendTeamMessage('This device is inactive'); } });- id:
getEvents(type)Get the most recent server events (ordered by newest to oldest)- type:
stringThe event type (optional)heliPatrol HelicoptercargoCargo ShipcrateLocked Cratech47CH-47 Chinookoil_rig_smallOil Rig (Small)large_oil_rigOil Rig (Large)vendorTravelling Vendor
- returns:
arrayEventarray
// getEvents example var e = await this.app.getEvents(); console.log(e);- type:
getInfo(callback)Get information about the server- callback(message):
functionThe function to execute after getting the info (message.responsecontainsInfo) - returns:
booltrueif successful
// getInfo example var app = this.app; app.getInfo((message) => { if (message.response && message.response.info) { app.sendTeamMessage('Current server population is ' + message.response.info.players + ' / ' + message.response.info.maxPlayers + ((message.response.info.queuedPlayers > 0) ? ' (' + message.response.info.queuedPlayers + ' in queue)' : '')); } });- callback(message):
getMapInfo(callback)Get information about the server's map- callback(message):
functionThe function to execute after getting the map info (messageisMapInfo) - returns:
booltrueif successful
// getMapInfo example var app = this.app; app.getMapInfo((message) => { if (message && message.image) { app.sendTeamMessage('Link to server map: ' + message.image); } });- callback(message):
getMapMarkers(callback)Get information about all map markers- callback(message):
functionThe function to execute after getting the map markers (message.responsecontainsMapMarkers) - returns:
booltrueif successful
// getMapMarkers example var app = this.app; app.getMapMarkers((message) => { if (message.response && message.response.mapMarkers && message.response.mapMarkers.markers) { var cnt = 0; for (var i = 0; i < message.response.mapMarkers.markers.length; i++) { if (message.response.mapMarkers.markers[i].type == 3) { // 'VendingMachine' if (message.response.mapMarkers.markers[i].sellOrders.length > 0) cnt++; } } app.sendTeamMessage('There are this many active vending machines: ' + cnt); } });- callback(message):
getMonumentName(x, y, noSmall)Get the name of the monument at the specified coordinates- x:
intThe x-coordinate of where the monument is located - y:
intThe y-coordinate of where the monument is located - noSmall:
boolSet totrueto exclude small monuments (optional) - returns:
stringThe name of the monument
// getMonumentName example var app = this.app, x = 1000, y = 1000; app.sendTeamMessage('The monument located at ' + (await app.util.getMapCoords(x, y)) + ' is: ' + (await app.getMonumentName(x, y)));- x:
getPrefix(type)Get the command prefix for the bot- type:
stringThe command type (optional)allAll CommandsdeviceDevice Commands
- returns:
stringThe selected prefix if it's required
// getPrefix example var prefix = await this.app.getPrefix('all');- type:
getRecyclerItems(items, success, error, opts)Retrieve the recycled items for the input items- items:
objectAn object containing the item names and item values - success(data):
functionThe function to execute after receiving recycle data (optional) - error(err):
functionThe function to execute when an error occurs (optional) - opts:
objectThe opts object containing theemojiboolproperty (optional) - returns:
booltrue
// getRecyclerItems example var app = this.app; app.getRecyclerItems({'Sheet Metal Door': 1}, (data) => { var keys = Object.keys(data), recycle = []; for (var i = 0; i < keys.length; i++) { recycle.push(keys[i] + ' x ' + data[keys[i]]); } if (recycle.length > 0) app.sendTeamMessage('Recyclables: ' + recycle.join(', ')); }, (error) => { app.sendTeamMessage('Error obtaining the recyle items: ' + error); }, { emoji: false });- items:
getSteamrep(steamId, success, error)Retrieve the Steamrep data for a Steam member- steamId:
stringThe steam ID of the Steam member - success(data):
functionThe function to execute after receiving Steamrep data (optional) - error(err):
functionThe function to execute when an error occurs (optional) - returns:
booltrue
⚠️ Unfortunately this plugin method no longer works since Steamrep has shutdown at the end of 2024- steamId:
getTeamChat(callback)Get recent team chat messages- callback(message):
functionThe function to execute after getting the team chat messages (message.responsecontainsTeamChat) - returns:
booltrueif successful
// getTeamChat example const messages_max = 5; var app = this.app; app.getTeamChat((message) => { if (message.response && message.response.teamChat) { var cnt = message.response.teamChat.messages.length, max = (cnt > messages_max) ? messages_max : cnt; app.sendTeamMessage('Showing the last ' + cnt + ' team chat messages:'); for (var i = 0; i < cnt; i++) { app.sendTeamMessage('(' + getFriendlyDate(new Date(message.response.teamChat.messages[cnt - i - 1].time * 1000)) + ') ' + message.response.teamChat.messages[cnt - i - 1].message); } } });- callback(message):
getTeamData(callback)Get detailed information about the team (leader, members)- callback(data):
functionThe function to execute after getting the team data (dataisTeamData) - returns:
booltrueif successful
// getTeamData example var app = this.app; app.getTeamData((data) => { if (data && data.members) { var info = ''; for (var i = 0; i < data.members.length; i++) { if (data.members[i].steamId == data.leader.steamId) { info = data.members[i].status + '; ' + data.members[i].info; break; } } app.sendTeamMessage('Team leader \'' + data.leader.name + '\' is ' + info); } });- callback(data):
getTeamInfo(callback)Get information about the team (leader, members)- callback(message):
functionThe function to execute after getting the team info (message.responsecontainsTeamInfo) - returns:
booltrueif successful
// getTeamInfo example var app = this.app; app.getTeamInfo((message) => { if (message.response && message.response.teamInfo) { var cnt = 0; for (var i = 0; i < message.response.teamInfo.members.length; i++) { if (message.response.teamInfo.members[i].isAlive) cnt++; } app.sendTeamMessage('There are this many alive team members: ' + cnt); } });- callback(message):
getTeamMemberDeaths(steamId)Gets the last 5 snapshots for a specific team member taken when they died- steamId:
stringThe player's steamId - returns:
arrayMembersarray of team member death snapshots
// getTeamMemberDeaths example var app = this.app, deaths = await app.getTeamMemberDeaths(obj.steamId), idx = 1; if (deaths && deaths.length > 0) { for (var i = 0; i < deaths.length; i++) { app.sendTeamMessage('Team member \'' + cmdFormat(deaths[i].name) + '\' death #' + idx + ' was ' + ((deaths[i].deathTime > 0) ? getFriendlyDate(deaths[i].deathTime * 1000).replace('less than one', '< 1').replace('about an', '1') : 'unknown') + ' and is located ' + cmdFormat('@ ' + (await app.util.getMapCoords(deaths[i].x, deaths[i].y)))); idx++; } } else app.sendTeamMessage('No death info found for team member: ' + cmdFormat(obj.name));- steamId:
getTime(callback)Get information about the server time- callback(message):
functionThe function to execute after getting the time (message.responsecontainsTime) - returns:
booltrueif successful
// getTime example var app = this.app; app.getTime(async (message) => { if (message.response && message.response.time) { app.sendTeamMessage('Current Rust time is ' + (await app.getTimeInfo(message.response.time))); } });- callback(message):
getTimeInfo(time)Get the server time + day/night display text- time:
objectThe time object from the getTime method - returns:
stringthe server time + day/night display text
// getTimeInfo example var app = this.app; app.getTime(async (message) => { if (message.response && message.response.time) { app.sendTeamMessage('Current Rust time is ' + (await app.getTimeInfo(message.response.time))); } });- time:
postDiscordMessage(msg)Post a message to the bot's Main Discord channel or a custom channel- msg:
stringThe message to post - msg:
objectThe message object containing themessagestringandchannelstring, optionalttsboolNote:channelis the channel ID
// postDiscordMessage example 1 this.app.postDiscordMessage('This is a message from a bot\'s plugin');
// postDiscordMessage example 2 this.app.postDiscordMessage({ message: 'This is a message from a bot\'s plugin to a custom channel', channel: '966820843924466774', tts: false });- msg:
postDiscordNotification(title, description, url, img, list)Post a notification to the bot's Notification Discord channel- title:
stringThe title of the notification - description:
stringThe description of the notification - url:
stringThe url of the notification (optional) - img:
stringThe image url of the notification (optional) - list:
arrayThe item list data of the notification (optional; seeNotificationListbelow)
// postDiscordNotification example var app = this.app; app.postDiscordNotification('Plugin Alert Title', 'Plugin Alert Message');- title:
postDiscordWebhook(url, msg)Post a message to a Discord webhook- url:
stringThe url of the Discord webhook - msg:
stringThe message to post to the Discord webhook
// postDiscordWebhook example var app = this.app; app.postDiscordWebhook('webhook url', 'Webhook Message');- url:
runCommand(cmd, steamId, steamName)Run a team chat command as a specific player- cmd:
stringThe command to run - steamId:
stringThe player's steamId (optional) - steamName:
stringThe player's steam name (optional) - returns:
booltrueif successful
// runCommand example var app = this.app, prefix = await app.getPrefix('all'); app.runCommand(prefix + 'pop');- cmd:
sendDiscordVoiceMessage(msg, noChime)Send a voice message to the RustPlusBot voice client- msg:
stringThe voice message to send - noChime:
boolSet totrueto disable the voice client chime (optional)
// sendDiscordVoiceMessage example var app = this.app; app.sendDiscordVoiceMessage('Hello, this is a test voice message!');- msg:
sendTeamMessage(msg, callback, noTranslate, sendVoice, noChime)Send a team chat message- msg:
stringThe message to send - callback():
functionThe function to execute after sending (optional) - noTranslate:
boolSet totrueto disable message translation (optional) - sendVoice:
boolSet totrueto send the message to the voice client (optional) - noChime:
boolSet totrueto disable the voice client chime (optional) - returns:
booltrueif successful
// sendTeamMessage example var app = this.app; app.sendTeamMessage('This is a team message');- msg:
setEntityValue(id, value, callback)Set the value of a Smart Switch- id:
intThe identifier of the Smart Switch - value:
boolThe value (true or false) - callback():
functionThe function to execute after setting the value (optional) - returns:
booltrueif successful
// setEntityValue example var app = this.app; app.setEntityValue(123456, true, () => { app.sendTeamMessage('The smart switch is activated'); });- id:
translateMessage(msg, lang, success, error)Translate a message from English (default) to another language- msg:
stringThe message to translate - lang:
stringThe language code to use for translation (see: Language Codes) - lang:
objectThe lang object containing thefromstringandtostringlanguage codes - success(res):
functionThe function to execute after translating (optional) - error(err):
functionThe function to execute when an error occurs (optional) - returns:
booltrue
// translateMessage example 1 this.app.translateMessage('Hello, how are you?', 'es', (res) => { app.sendTeamMessage(res); }, (error) => { app.sendTeamMessage('Error: ' + error); });
// translateMessage example 2 this.app.translateMessage('Hola, como estas?', { from: 'es', to: 'en' }, (res) => { app.sendTeamMessage(res); }, (error) => { app.sendTeamMessage('Error: ' + error); });- msg:
webGet(url, params, headers, success, error)Retrieve data from a url- url:
stringThe url to access - params:
objectThe parameters of the url (optional) - headers:
objectThe headers to send with the web request (optional) - success(data):
functionThe function to execute after receiving data (optional) - error(err):
functionThe function to execute when an error occurs (optional) - returns:
booltrue
// webGet example var app = this.app; app.webGet('https://rust.facepunch.com/rss/news', null, null, (data) => { var link = '', pos = data.indexOf('>https://'); if (pos > 0) link = data.substr(pos + 1, data.indexOf('<', pos) - pos - 1); if (link != '') app.sendTeamMessage('The newest Rust update link: ' + link); else app.sendTeamMessage('The newest Rust update link was not found'); }, (error) => { app.sendTeamMessage('Error obtaining Rust update link: ' + error); });- url:
webPost(url, data, headers, success, error)Post data to a url- url:
stringThe url to access - data:
stringThe data to post (optional) - headers:
objectThe headers to send with the web request (optional) - success(data):
functionThe function to execute after receiving data (optional) - error(err):
functionThe function to execute when an error occurs (optional) - returns:
booltrue
// webPost example var app = this.app; app.webPost('https://httpbin.org/post', 'test data', null, (data) => { app.sendTeamMessage('Post result: ' + data); }, (error) => { app.sendTeamMessage('Error posting: ' + error); });- url:
interactiveMap.addMarker(markerIdReturnsstring, steamIdstring, namestring, msgstring, xint, yint)trueif the custom map marker is addedRefer to the mapmarkers plugin example to see the correct usage for addMarker
interactiveMap.setMarkerColor(markerIdReturnsstring, colorstring)trueif the custom map marker's color is updatedAvailable colors are:
blue,red,green,purple,grayinteractiveMap.setMarkerExpiration(markerIdReturnsstring, expiresint)trueif the custom map marker's expiration is updatedexpiresis a unix timestamp (set to0for no expiration)interactiveMap.removeMarker(markerIdReturnsstring)trueif the custom map marker matching markerId is removedinteractiveMap.clearMarkers(steamIdReturnsstring)trueif all custom map markers are removed for steamIdinteractiveMap.getHeatmapData()Returns an object containing the heatmap data (seeHeatmapDatabelow)util.collides(xReturnsint, yint, rotationint, x1int, y1int, x2int, y2int)trueif angled point x,y collides with rectangle x1,y1,x2,y2util.direction(x1Get the direction from the first point facing the secondint, y1int, x2int, y2int)util.distance(x1Get the distance between two points in metersint, y1int, x2int, y2int)util.getMapCoords(xGet the map coordinates for a pointint, yint)util.inRect(xReturnsint, yint, x1int, y1int, x2int, y2int)trueif the point is inside the rectangle
// get the map coordinates of a specific location
var location = {x: 1000, y: 2000};
console.log('map coordinates: ' + (await this.app.util.getMapCoords(location.x, location.y)));
Note
The following methods exist in the plugin's scope this (instead of in app).
registeredHandlers.add(typeAdd a handler for a specific update event type:string, handlerfunction)cameraFires when the camera list has changedconfigFires when the configuration settings have changeddeviceFires when the paired devices has changed or loadedwipeFires when the server has wiped
registeredHandlers.remove(typeRemove a handler for a specific update event type (seestring, handlerfunction)registeredHandlers.addabove)
// listen for a configuration change event
if (!this.configFunc) {
var self = this;
self.configFunc = function() {
console.log(self.app.cfg);
};
}
this.registeredHandlers.add('config', this.configFunc);
-
BattleMetrics Data
{ "Name": "Server Name", "Rank": "#1", "Player count": "1/100", "Address": "Server Address", "Status": "online", "Country": "US", "Uptime": 26522, "Average FPS": "60", "Last Wipe": "2024-02-01T18:53:55.766Z", "Next Wipe": "2024-02-15T20:00:00.000Z", "PVE": "False", "Website": "http://www.playrust.com/", "Entity Count": "265097", "Official Server": "True", "Private": "False", "Map": "Procedural Map", "Type": "official", "Tags": [], "createdAt": "2018-09-06T00:16:14.003Z", "updatedAt": "2024-02-08T18:25:13.509Z", "id": 546784, "time": 1640108040219 } -
Config
{ "lang": "en", "gender": "male", "cmdPrefix": "!", "requirePrefix": "all", "teamChatIncoming": "all", "teamChatOutgoing": true, "teamChatResponses": false, "teamChatSilenced": false, "teamChatDelay": 0, "teamChatTTS": false, "teamChatMentions": true, "shortTime": false, "nextTime": false, "altTime": false, "dirAngle": true, "eventsDiscord": false, "broadcastEvents": true, "vendingDiscord": false, "broadcastVending": true, "broadcastVendingName": true, "broadcastAmount": 1, "respawnAmount": 1, "battlemetricsID": 0, "battlemetricsDiscord": true, "deathDiscord": true, "loginDiscord": true, "aliasesFullMatch": false, "accessOnlyCommands": false, "deviceTTS": false, "autoCleanDevices": false, "autoDeviceCommand": true, "showDevicePlayer": false, "alwaysPostAlarms": true, "alwaysPostDecay": true, "decayOffset": 0, "streamerMode": false, "promoteStrict": false, "voiceDevice": true, "voiceEvent": true, "voiceVending": true, "voiceTracking": true, "voicePlugin": true, "eventsDisplay": "heli,brad,cargo,oil,crate,ch47,ch47b,vendor", "subEventsDisplay": "heli_lootable,brad_lootable,cargo_docked,oil_lootable,oil_cams" } -
DetailedInfo
{ "players": "51/200", "playersQueue": 0, "playersChange": 0, "time": "16:23", "timeValue": 16.38, "wipe": 1147412, "nextDay": 1453, "nextNight": 775, "nextWipe": 22 }// wipe usage: getTimeDisplay(wipe * 1000) + ' ago' // nextDay usage: getTimeDisplay(nextDay) // nextNight usage: getTimeDisplay(nextNight) // nextWipe usage: nextWipe + 'd' -
Device
{ name: "MyDevice", id: 123456, flag: false, // true if op is inverted type: "Smart Switch", time: 0 // timestamp of last state change } -
DeviceAuto
{ state: true, // true for ON time: 60 // auto time in seconds } -
EntityInfo
{ "type": "1", "payload": {} // see Payload below }// entity types: // 1 = Smart Switch // 2 = Smart Alarm // 3 = Storage Monitor -
Event
{ id: 123456789, type: "heli", name: "Patrol Helicopter @ A1", start: new Date(), stop: null // null if active } -
Event Timers
{ "cargo": { "spawn": 7200, "spread": 7200 }, "crate": { "spawn": 7200, "spread": 3600 }, "heli": { "spawn": 7200, "spread": 3600 }, "oilrig": { "spawn": 2700, "spread": 2700 }, "vendor": { "spawn": 7200, "spread": 7200 } } -
Heatmap Data
{ "deaths": [], "brad": [{ "x": 2667.51416015625, "y": 2336.646240234375, "count": 1 }], "heli": [{ "x": 688.2880859375, "y": 922.4451904296875, "count": 1 }], "crate": [{ "x": 2047.0020751953125, "y": 2884.339111328125, "count": 6 }], "cargo": [{ "x": -1775, "y": 2098.646240234375, "count": 8 },{ "x": -1684.09814453125, "y": 2145.852783203125, "count": 2 },{ "x": -1608.643798828125, "y": 2141.641357421875, "count": 2 }] } -
Info
{ "name": "Rust Server Name", "headerImage": "", "url": "", "map": "Procedure Map", "mapSize": 4250, "wipeTime": 0, "players": 100, "maxPlayers": 200, "queuedPlayers": 0, "seed": 0, "salt": 0 } -
MapInfo
{ "width": 3125, "height": 3125, "oceanMargin": 500, "offset": 0, "background": "#12404D", "image": "", "cached": true, "info": { "name": "Rust Server Name", "headerImage": "", "url": "", "map": "Procedure Map", "mapSize": 4250, "wipeTime": 0, "players": 100, "maxPlayers": 200, "queuedPlayers": 0, "seed": 0, "salt": 0 } } -
MapMarkers
{ markers: [{ "id": 123456, "type": 3, "x": 1500.958740234375, "y": 2551.239990234375, "location": "G20", "steamId": 0, "rotation": 0, "radius": 0, "name": "", "outOfStock": false, sellOrders: [{ // sellOrders when type is 3 "itemId": 123456, "quantity": 1, "currencyId": 654321, "costPerItem": 1, "amountInStock": 10, "itemIsBlueprint": false, "currencyIsBlueprint": false, "itemCondition": 42.75, "itemConditionMax": 100 }] }] }// marker types: // 1 = Player // 2 = Explosion // 3 = VendingMachine // 4 = CH47 // 5 = CargoShip // 6 = Crate // 8 = PatrolHelicopter // 9 = TravellingVendorFind the item name with the itemId using
itemIds -
MapNotes
[{ "type": 1, "x": 1500.958740234375, "y": 2551.239990234375 }] -
Members
[{ "steamId": "123456789", "name": "RustPlayer1", "x": 1497.4344482421875, "y": 2522.85546875, "isOnline": true, "spawnTime": 1638768666, "isAlive": true, "deathTime": 1638768647, "onlineTime": 1638768660, "afk": { "value": false, "time": 0 } }, { "steamId": "123456799", "name": "RustPlayer2", "x": 1487.4344482421875, "y": 2512.85546875, "isOnline": true, "spawnTime": 1638768866, "isAlive": true, "deathTime": 1638768847, "onlineTime": 1638768660, "afk": { "value": false, "time": 0 } }] -
Notification: Alarm
{ "notification": { "type": "alarm", "alarm": { "title": "Smart Alarm Title", "message": "Smart Alarm Message" }, "server_name": "Rust Server Name" } } -
Notification: Decaying TC
{ "notification": { "type": "monitor", "monitor": { "title": "MyDevice", "message": "This monitored TC is decaying!", "device_name": "MyDevice", "device_id": "123456", "device_flag": false, "device_type": "Storage Monitor" }, "server_name": "Rust Server Name" } } -
Notification: Entity Pairing
{ "notification": { "type": "entity", "server_name": "Rust Server Name", "entityName": "Smart Switch", "entityId": "123456", "entityType": "1" } }// entity types: // 1 = Smart Switch // 2 = Smart Alarm // 3 = Storage Monitor -
Notification: Event
{ "notification": { "type": "event", "event": { "type": "heli", "title": "Patrol Helicopter", "message": "The Patrol Helicopter has exploded @ A1", "x": 100.543565665, "y": 200.345765755 }, "server_name": "Rust Server Name" } } -
Notification: Inactive Device
{ "notification": { "type": "inactive", "inactive": { "title": "MyDevice", "message": "This device is inactive.", "device_name": "MyDevice", "device_id": "123456", "device_flag": false, "device_type": "Smart Switch" }, "server_name": "Rust Server Name" } } -
Notification: News
{ "notification": { "type": "news", "news": { "title": "Rust Update News", "url": "https://rust.facepunch.com/", "message": "A new Rust update blog is available!" }, "server_name": "Rust Server Name" } } -
Notification: Player Death
{ "notification": { "type": "death", "server_name": "Rust Server Name", "targetName": "RustPlayer", "targetId": "123456789" } } -
Notification: Player Tracking
{ "notification": { "type": "tracking", "tracking": { "bm_id": "1234", "player_id": "123456789", "name": "Tracked player \"Rust Player\" has joined the server", "status": "joined" }, "server_name": "Rust Server Name" } } -
Notification: Team Login
{ "notification": { "type": "login", "server_name": "Rust Server Name", "targetName": "RustPlayer", "targetId": "123456789" } } -
NotificationList
[{ name: "Sub Item", value: "Sub Value", inline: false }] -
Payload: Smart Switch, Smart Alarm
"payload": { "value": false, "capacity": 0, "hasProtection": false, "protectionExpiry": 0 } -
Payload: Storage Monitor
"payload": { "value": false, "items": [{ "itemId": 317398316, "quantity": 95, "itemIsBlueprint": false }, { "itemId": -151838493, "quantity": 998, "itemIsBlueprint": false }], "capacity": 24, "hasProtection": true, "protectionExpiry": 1638790206 }Find the item name with the itemId using
itemIds -
Point
{ x: 100, y: 200 } -
Time
{ "dayLengthMinutes": 60, "timeScale": 1, "sunrise": 7, "sunset": 20, "time": 12 } -
TeamChat
{ "messages": [{ "steamId": "123456789", "name": "RustPlayer1", "message": "A Locked Crate has been dropped @ M13 (Airfield)", "color": "#5af", "time": 1649959932 }] } -
TeamData
{ "leader": { "name": "RustPlayer1", "steamId": "123456789" }, "members": [{ "name": "RustPlayer1", "steamId": "123456789", "status": "ONLINE", "info": "alive for 2 hours", "infoAlt": "online for 2 hours", "infoText": "alive for", "infoValue": 1649959932, "infoTextAlt": "online for", "infoValueAlt": 1649959932, "location": "G20", "x": 1932.2833251953125, "y": 2376.96240234375 }] } -
TeamInfo
{ "leaderSteamId": 123456789, "members": [], // see Members "leaderMapNotes": [], // see MapNotes "mapNotes": [] // see MapNotes } -
Time
{ "dayLengthMinutes": 60, "timeScale": 1, "sunrise": 7, "sunset": 20, "time": 12 }
abbreviateNumber(value)Abbreviate a number for a compact display- value:
intThe number to abbreviate - returns:
stringan abbreviated number
// abbreviateNumber example var app = this.app, stat_wood = 132000, stat_stones = 63000, stat_sulfur = 23000, stat_mf = 56000, stat_hqm = 1200, msg = ':wood: ' + abbreviateNumber(stat_wood) + ' | :stones: ' + abbreviateNumber(stat_wood) + ' | :sulfur: ' + abbreviateNumber(stat_sulfur) + ' | :metal.fragments: ' + abbreviateNumber(stat_mf) + ' | :hq.metal.ore: ' + abbreviateNumber(stat_hqm); app.sendTeamMessage(msg);- value:
cmdFormat(str)Convert a string into a non-translatable string- str:
stringThe string to convert - returns:
stringa non-translatable string
// cmdFormat example var app = this.app, msg = 'Here is the url: ' + cmdFormat('https://www.google.com'); app.sendTeamMessage(msg);- str:
cmdFormatUndo(str)Undo the non-translatable string conversion- str:
stringThe string to undo the non-translatable string conversion - returns:
stringa string
// cmdFormatUndo example var app = this.app, msg = 'Here is the url: ' + cmdFormat('https://www.google.com'); console.log(cmdFormatUndo(msg));- str:
encodeForm(data)Convert an object to form data for a webPost- data:
objectThe object to convert - returns:
stringa string of encoded names and values
// encodeForm example var app = this.app; app.webPost('https://www.iplocation.net/ip-lookup', encodeForm({ query: app.server_ip }), null, (data) => { var regex = new RegExp('<tr><td>' + app.server_ip + '</td><td>([^<]+)<', 'g'), match = regex.exec(data); if (match) app.sendTeamMessage('GeoIP location of the server: ' + match[1]); else app.sendTeamMessage('Unable to get the GeoIP location of the server'); }, (error) => { app.sendTeamMessage('Error posting: ' + error); });- data:
combineItems(items, itemIds)Combine the items from a Storage Monitor payload and resolve the item names- items:
objectThe items from the payload - itemIds:
MapThe item ID list to lookup item names - returns:
MapA Map object containing the combined items and item quantities
// combineItems example var app = this.app, device = app.devices.get('BaseTC')[0]; app.getEntityInfo(device.id, (message) => { if (message.response && message.response.entityInfo && message.response.entityInfo.payload && message.response.entityInfo.payload.capacity > 0 && message.response.entityInfo.payload.items) { var items = combineItems(message.response.entityInfo.payload.items, app.itemIds), sorted = [], list = []; items.forEach((value, key) => { sorted.push({ name: key, quantity: value }); }); sorted.sort(function (a, b) { if (a.name < b.name) return -1; if (a.name > b.name) return 1; }); sorted.forEach((item) => { list.push(item.name + ' x ' + item.quantity.toLocaleString()); }); if (list.length > 0) { multiLineFormat('Device \'' + cmdFormat(device.name) + '\' contents: ', list, function(line) { app.sendTeamMessage(line); }); } } });- items:
findClosestString(str, arr, threshold = 2)Find the closest match for a string in an array using a threshold- str:
stringThe input string - arr:
arrayThe array of possible string matches - threshold:
intThe threshold used for string matching (optional) - returns:
stringThe closest matched string found in the input array
// findClosestString example var app = this.app, item = 'windturbine', closest = findClosestString(item, Array.from(app.itemIds.values())); if (closest && closest.toLowerCase() != item.toLowerCase()) { app.sendTeamMessage('Are you looking for this item? ' + closest); } else { app.sendTeamMessage('This item name is a direct match: ' + item); }- str:
getFriendlyDate(date)Get a friendly representation of the date- date:
dateThe date object - returns:
stringa string containing the friendly representation of the date
// getFriendlyDate example var app = this.app; app.getTeamInfo((message) => { if (message.response && message.response.teamInfo) { var status = '', status_time = 0; for (var i = 0; i < message.response.teamInfo.members.length; i++) { if (message.response.teamInfo.members[i].steamId == message.response.teamInfo.leaderSteamId) { status = (message.response.teamInfo.members[i].isAlive) ? 'alive' : 'dead'; status_time = (message.response.teamInfo.members[i].isAlive) ? message.response.teamInfo.members[i].spawnTime : message.response.teamInfo.members[i].deathTime; break; } } app.sendTeamMessage('The team leader has been ' + status + ' since ' + getFriendlyDate(status_time * 1000)); } });- date:
getTime(timestr, max_val)Convert a time string to seconds- timestr:
stringThe time string (format: 1d1h1m1s) - max_val:
intThe maximum allowed time value to return (optional) - returns:
intthe total seconds of the timestr
// getTime example var app = this.app; app.sendTeamMessage('The time in seconds for 1d1h1m1s is ' + getTime('1d1h1m1s'));- timestr:
getTimeDifference(date)Get the time difference for a date- date:
dateThe date object - returns:
intthe date difference in seconds
// getTimeDifference example var app = this.app, connected = await app.getConnected(); app.sendTeamMessage('The time in seconds since the bot connected is ' + Math.round(getTimeDifference(new Date(connected))));- date:
getTimeDisplay(time)Get the time display for time- time:
intThe time in seconds - returns:
stringa string representing the time
// getTimeDisplay example var app = this.app, connected = await app.getConnected(); app.sendTeamMessage('The bot has been connected for ' + getTimeDisplay(Math.round(getTimeDifference(new Date(connected)))));- time:
multiLineFormat(msg, list, callback, all, separator)Format the message + list to fit the Rust message size using multiple lines- msg:
stringThe message to prepend - list:
arrayThe list of items to output - callback(line, msg, data, idx):
functionThe function to execute for each formatted line (optional) - all:
boolSet to true if all lines should include the msg (optional) - separator:
stringThe list separator; default: ", " (optional) - returns:
arrayan Array containing the formatted lines
// multiLineFormat example var app = this.app, device = app.devices.get('BaseTC')[0]; app.getEntityInfo(device.id, (message) => { if (message.response && message.response.entityInfo && message.response.entityInfo.payload && message.response.entityInfo.payload.capacity > 0 && message.response.entityInfo.payload.items) { var items = combineItems(message.response.entityInfo.payload.items, app.itemIds), sorted = [], list = []; items.forEach((value, key) => { sorted.push({ name: key, quantity: value }); }); sorted.sort(function (a, b) { if (a.name < b.name) return -1; if (a.name > b.name) return 1; }); sorted.forEach((item) => { list.push(item.name + ' x ' + item.quantity.toLocaleString()); }); if (list.length > 0) { multiLineFormat('Device \'' + cmdFormat(device.name) + '\' contents: ', list, function(line, msg, data, idx) { if (idx == 0) app.sendTeamMessage(msg + data); else app.sendTeamMessage(data); }); } } });- msg:
You can publish your plugin when you are done making any major changes to it by clicking the Publish tab in the Plugin Studio. You have the option of making it a public plugin for others to use with their bot. There will be a review of your plugin after submitting which could take several days. If your plugin is accepted for publishing, you will then be able to select it in the Plugin settings for your bot and install it. Duplicates of official plugins will not be accepted.
- alarmchannel
- This plugin example demonstrates how to use the activation of a Smart Alarm to post a Discord message in a specific channel and ping a role.
- announcements
- This plugin example demonstrates how to automatically send pre-defined team chat announcements.
- autopop
- This plugin example demonstrates how to automatically run the
!popcommand every 5 minutes.
- This plugin example demonstrates how to automatically run the
- autotime
- This plugin example demonstrates how to automatically send until daytime / until nighttime team chat announcements.
- eventstimestamp
- This plugin example demonstrates how to add timestamps to server event messages sent to team chat.
- hotelfloors
- This plugin example demonstrates how to automatically activate multiple similarly named Smart Switches with a single command. This is the same plugin seen in the MikeTheVike YouTube video here: https://www.youtube.com/watch?v=ijdQ31TP0hk
- macro
- This plugin example demonstrates how to use a single team chat command to execute multiple chat commands.
- mapmarker
- This plugin example demonstrates how to pin a custom map marker to the Interactive Map.
- messagerouting
- This plugin example demonstrates how to route team chat messages to custom Discord channels. You can specify wildcard matches for the messages and have them posted to their own Discord channels.
- mirrormessages
- This plugin example demonstrates how to mirror all team chat messages by posting them to another Discord server via a webhook.
- teamvoice
- This plugin example demonstrates how to send voice messages to the RustPlusBot voice client. You can invite the voice client to your active voice channel using Discord command:
rp!voice_join.
- This plugin example demonstrates how to send voice messages to the RustPlusBot voice client. You can invite the voice client to your active voice channel using Discord command:
- timedfireworks
- This plugin example demonstrates how to activate multiple Smart Switches with different delays, allowing you to create a timed firework show. The Smart Switches should be directly wired to Igniters near the fireworks.
- turretrotation
- This plugin implements auto turret flip flop for your bot. It works by rotating auto turret segments, or sections, with a total of 9 segments supported. Each turret segment is controlled by a single smart switch. Each turret in the segment has their Has Target output combined to a single smart alarm. When a turret segment is active, and if its related smart alarm is activated from the combined Has Target output, then the turret segment timer is reset keeping the segment active for longer.
- vendingitems
- This plugin example demonstrates how to output all vending machine items in CSV or JSON format.
- vendinglog
- This plugin example demonstrates how to log all vending machine item changes on the server to the Notifications Discord Channel (or the Plugin Notification channel if set in the bot's config).
- Website: https://bot.rustplus.io/
- Help & Documentation: https://bot.rustplus.io/help/
- Plugin Examples: https://github.com/javajuice1337/RustPlusBot/blob/main/plugin%20examples
