.github | ||
core | ||
factory | ||
plugins | ||
squad-server | ||
.eslintignore | ||
.eslintrc | ||
.gitignore | ||
.huskyrc | ||
.lintstagedrc | ||
.prettierrc | ||
config.json | ||
index.js | ||
LICENSE | ||
package.json | ||
README.md |
About
SquadJS is a scripting framework, designed for Squad servers, that aims to handle all communication and data collection to and from the servers. Using SquadJS as the base to any of your scripting projects allows you to easily write complex plugins without having to worry about the hassle of RCON or log parsing. However, for your convenience SquadJS comes shipped with multiple plugins already built for you allowing you to experience the power of SquadJS right away.
Using SquadJS
SquadJS relies on being able to access the Squad server log directory in order to parse logs live to collect information. Thus, SquadJS must be hosted on the same server box as your Squad server.
Prerequisites
- Git
- Node.js (Current) - Download
- Yarn (Version 1.22.0+) - Download
- Some plugins may have additional requirements.
Installation
- Clone the repository:
git clone https://github.com/Thomas-Smyth/SquadJS
- Install the dependencies:
yarn install
- Configure the
config.json
file. See below for more details. - Start SquadJS:
node index.js
.
Configuring SquadJS
SquadJS can be configured via a JSON configuration file which, by default, is located in the SquadJS and is named config.json.
The config file needs to be valid JSON syntax. If an error is thrown saying the config cannot be parsed then try putting the config into a JSON syntax checker (there's plenty to choose from that can be found via Google).
Server
The following section of the configuration contains information about your Squad server.
"server": {
"id": 1,
"host": "xxx.xxx.xxx.xxx",
"queryPort": 27165,
"rconPort": 21114,
"rconPassword": "password",
"logReaderMode": "tail",
"logDir": "C:/path/to/squad/log/folder",
"ftpPort": 21,
"ftpUser": "FTP Username",
"ftpPassword": "FTP Password",
"rconVerbose": false
},
id
- An integer ID to uniquely identify the server.host
- The IP of the server.queryPort
- The query port of the server.rconPort
- The RCON port of the server.rconPassword
- The RCON password of the server.logReaderMode
-tail
will read from a local log file.ftp
will read from a remote log file.ftpPort
- The FTP port of the server. Only required forftp
logReaderMode
.ftpUser
- The FTP user of the server. Only required forftp
logReaderMode
.ftpPassword
- The FTP password of the server. Only required forftp
logReaderMode
.rconVerbose
- Enable verbose logging for RCON.
Connectors
Connectors allow SquadJS to communicate with external resources.
"connectors": {
"discord": "Discord Login Token",
},
Connectors should be named, for example the above is named discord
, and should have the associated config against it. Configs can be specified by name in plugin options. Should a connector not be needed by any plugin then the default values can be left or you can remove it from your config file.
See below for more details on connectors and their associated config.
Discord
Connects to Discord via discord.js
.
"discord": "Discord Login Token",
Requires a Discord bot login token.
Squad Layer Filter
Connects to a filtered list of Squad layers and filters them either by an "initial filter" or an "active filter" that depends on current server information, e.g. player count.
"layerFilter": {
"type": "buildFromFilter",
"filter": {
"whitelistedLayers": null,
"blacklistedLayers": null,
"whitelistedMaps": null,
"blacklistedMaps": null,
"whitelistedGamemodes": null,
"blacklistedGamemodes": [
"Training"
],
"flagCountMin": null,
"flagCountMax": null,
"hasCommander": null,
"hasTanks": null,
"hasHelicopters": null
},
"activeLayerFilter": {
"historyResetTime": 18000000,
"layerHistoryTolerance": 8,
"mapHistoryTolerance": 4,
"gamemodeHistoryTolerance": {
"Invasion": 4
},
"gamemodeRepetitiveTolerance": {
"Invasion": 4
},
"playerCountComplianceEnabled": true,
"factionComplianceEnabled": true,
"factionHistoryTolerance": {
"RUS": 4
},
"factionRepetitiveTolerance": {
"RUS": 4
}
}
},
type
- The type of filter builder to use.filter
will depend on this type.buildFromFilter
- Builds the Squad layers list from a list of filters. An examplefilter
with default values for this type is show above.whitelistedLayers
- List of layers to consider.blacklistLayers
- List of layers to not consider.whitelistedMaps
- List of maps to consider.blacklistedMaps
- List of maps to not consider.whitelistedGamemodes
- List of gamemodes to consider.blacklistedGamemodes
- List of gamemodes to not consider.flagCountMin
- Minimum number of flags the layer may have.flagCountMax
- Maximum number of flags the layer may have.hasCommander
- Layer must/most not have a commander.null
for either.hasTanks
- Layer must/most not have a tanks.null
for either.hasHelicopters
- Layer must/most not have a helicopters.null
for either.
buildFromFile
- Builds the Squad layers list from a Squad layer config file.filter
should be the filename of the config file.buildFromList
- Builds the Squad layers list from a list of layers.filter
should be a list of layers, e.g."filter": ["Sumari AAS v1", "Fool's Road AAS v1"]
.
filter
- Described above.activeLayerFilter
- Filters layers live as server information updates, e.g. if the player count exceeds a certain amount a layer may no longer be in the filter.historyResetTime
- After this number of miliseconds the layer history is no longer considered.layerHistoryTolerance
- A layer can only be played again after this number of layers.mapHistoryTolerance
- A map can only be played again after this number of layers.gamemodeHistoryTolerance
- A gamemode can only be played again after this number of layers. Gamemodes can be specified individually inside the object. If they are not listed then the filter is not applied.gamemodeRepetitiveTolerance
- A gamemode can only be played this number of times in a row. Gamemodes can be specified individually inside the object. If they are not listed then the filter is not applied.playerCountComplianceEnabled
- Filter layers by player count.factionComplianceEnabled
- Filter layers so that a team cannot play the same faction twice in a row.factionHistoryTolerance
- A faction can only be played again after this number of layers. Factions can be specified individually inside the object. If they are not listed then the filter is not applied.factionRepetitiveTolerance
- A faction can only be played this number of times in a row. Factions can be specified individually inside the object. If they are not listed then the filter is not applied.
MySQL
Connects to a MySQL database.
"mysql": {
"connectionLimit": 10,
"host": "host",
"port": 3306,
"user": "squadjs",
"password": "password",
"database": "squadjs"
}
The config is a set of pool connection options as listed in the Node.js mysql documentation.
Plugins
The plugins
section in your config file lists all plugins built into SquadJS, e.g.:
"plugins": [
{
"plugin": "auto-tk-warn",
"disabled": false,
"message": "Please apologise for ALL TKs in ALL chat!"
}
]
The disabled
field can be toggled between true
/ false
to enabled/disable the plugin.
Plugin options are also specified. A full list of plugin options can be seen below.
Plugins
The following is a list of plugins built into SquadJS, you can click their title for more information:
auto-tk-warn
auto-tk-warn
The auto-tk-warn
plugin will automatically warn players in game to apologise for teamkills when they teamkill another player.
Options
message
Description
The message to warn players with.
Default
Please apologise for ALL TKs in ALL chat!
Example
Test
chat-commands
chat-commands
The chat-command
plugin can be configured to make chat commands that broadcast or warn the caller with present messages.
Options
commands
Description
An array of objects containing the following properties:
command
- The command that initiates the message.type
- Eitherwarn
orbroadcast
.response
- The message to respond with.ignoreChats
- A list of chats to ignore the commands in. Use this to limit it to admins.
Default
[
{
"command": "!squadjs",
"type": "warn",
"response": "This server is powered by SquadJS.",
"ignoreChats": []
}
]
discord-admin-broadcast
discord-admin-broadcast
The discord-admin-broadcast
plugin will send a copy of admin broadcasts made in game to a Discord channel.
Options
discordClient (Required)
Description
The name of the Discord Connector to use.
Default
discord
channelID (Required)
Description
The ID of the channel to log admin broadcasts to.
Default
Example
667741905228136459
color
Description
The color of the embed.
Default
16761867
discord-admin-cam-logs
discord-admin-cam-logs
The discord-admin-cam-logs
plugin will log in game admin camera usage to a Discord channel.
Options
discordClient (Required)
Description
The name of the Discord Connector to use.
Default
discord
channelID (Required)
Description
The ID of the channel to log admin cam usage to.
Default
Example
667741905228136459
color
Description
The color of the embed.
Default
16761867
discord-chat
discord-chat
The discord-chat
plugin will log in-game chat to a Discord channel.
Options
discordClient (Required)
Description
The name of the Discord Connector to use.
Default
discord
channelID (Required)
Description
The ID of the channel to log admin broadcasts to.
Default
Example
667741905228136459
ignoreChats
Description
A list of chat names to ignore.
Default
[
"ChatSquad"
]
chatColors
Description
The color of the embed for each chat.
Default
{}
Example
{
"ChatAll": 16761867
}
color
Description
The color of the embed.
Default
16761867
discord-admin-request
discord-admin-request
The discord-admin-request
plugin will ping admins in a Discord channel when a player requests an admin via the !admin
command in in-game chat.
Options
discordClient (Required)
Description
The name of the Discord Connector to use.
Default
discord
channelID (Required)
Description
The ID of the channel to log admin broadcasts to.
Default
Example
667741905228136459
ignoreChats
Description
A list of chat names to ignore.
Default
[]
Example
[
"ChatSquad"
]
ignorePhrases
Description
A list of phrases to ignore.
Default
[]
Example
[
"switch"
]
adminPrefix
Description
The command that calls an admin.
Default
!admin
pingGroups
Description
A list of Discord role IDs to ping.
Default
[]
Example
[
"500455137626554379"
]
pingDelay
Description
Cooldown for pings in milliseconds.
Default
60000
color
Description
The color of the embed.
Default
16761867
discord-debug
discord-debug
The discord-debug
plugin can be used to help debug SquadJS by dumping SquadJS events to a Discord channel.
Options
discordClient (Required)
Description
The name of the Discord Connector to use.
Default
discord
channelID (Required)
Description
The ID of the channel to log admin broadcasts to.
Default
Example
667741905228136459
events (Required)
Description
A list of events to dump.
Default
[]
Example
[
"PLAYER_DIED"
]
discord-rcon
discord-rcon
The discord-rcon
plugin allows a specified Discord channel to be used as a RCON console to run RCON commands.
Options
discordClient (Required)
Description
The name of the Discord Connector to use.
Default
discord
channelID (Required)
Description
The ID of the channel you wish to turn into a RCON console.
Default
Example
667741905228136459
prependAdminNameInBroadcast
Description
Prepend the admin's name when he makes an announcement.
Default
false
discord-round-winner
discord-round-winner
The `discord-round-winner` plugin will send the round winner to a Discord channel.
Options
discordClient (Required)
Description
The name of the Discord Connector to use.
Default
discord
channelID (Required)
Description
The ID of the channel to log admin broadcasts to.
Default
Example
667741905228136459
color
Description
The color of the embed.
Default
16761867
discord-server-status
discord-server-status
The discord-server-status
plugin displays a server status embed to Discord when someone uses the !server
command in a Discord channel.
Options
discordClient (Required)
Description
The name of the Discord Connector to use.
Default
discord
color
Description
The color code of the Discord embed.
Default
16761867
colorGradient
Description
Apply gradient color to Discord embed depending on the player count.
Default
true
connectLink
Description
Display a Steam server connection link.
Default
true
command
Description
The command that displays the embed.
Default
!server
disableStatus
Description
Disable the bot status.
Default
false
discord-teamkill
discord-teamkill
The discord-teamkill
plugin logs teamkills and related information to a Discord channel for admin to review.
Options
discordClient (Required)
Description
The name of the Discord Connector to use.
Default
discord
channelID (Required)
Description
The ID of the channel to log admin broadcasts to.
Default
Example
667741905228136459
teamkillColor
Description
The color of the embed for teamkills.
Default
16761867
suicideColor
Description
The color of the embed for suicides.
Default
16761867
ignoreSuicides
Description
Ignore suicides.
Default
false
disableSCBL
Description
Disable Squad Community Ban List information.
Default
false
intervalled-broadcasts
intervalled-broadcasts
The `intervalled-broadcasts` plugin allows you to set broadcasts, which will be broadcasted at preset intervals
Options
broadcasts
Description
The broadcasted messages.
Default
[
"Server powered by SquadJS."
]
interval
Description
How frequently to broadcast in seconds.
Default
300000
mapvote-123
mapvote-123
The mapvote-123
plugin provides map voting functionality. This variant of map voting allows admins to specify a small number of maps which are numbered and announced in admin broadcasts. Players can then vote for the map their choice by typing the corresponding map number into chat.
Player Commands:
!mapvote help
- Show other commands players can use.!mapvote results
- Show the results of the current map vote.- Vote for a layer using the layer number.
Admin Commands (Admin Chat Only):
!mapvote start <layer name 1>, <layer name 2>, ...
- Start a new map vote with the specified maps.!mapvote restart
- Restarts the map vote with the same layers.!mapvote end
- End the map vote and announce the winner.!mapvote destroy
- End the map vote without announcing the winner.
Options
minVoteCount
Description
The minimum number of votes required for the vote to succeed.
Default
null
Example
3
mapvote-did-you-mean
mapvote-did-you-mean
The mapvote-did-you-mean
plugin provides map voting functionality. This variant of map voting uses a "Did you mean?" algorithm to allow players to easily select one of a large pool of layers by typing it's name into the in-game chat.
Player Commands:
!mapvote help
- Show other commands players can use.!mapvote results
- Show the results of the current map vote.!mapvote
- Vote for the specified layer. Misspelling will be corrected where possible.
Admin Commands (Admin Chat Only):
!mapvote start
- Start a new map vote!mapvote restart
- Restarts the map vote.!mapvote end
- End the map vote and announce the winner.!mapvote destroy
- End the map vote without announcing the winner.
Options
layerFilter
Description
The layers players can choose from.
Default
layerFilter
alwaysOn
Description
If true then the map voting system will always be live.
Default
true
minPlayerCount
Description
The minimum number of players required for the vote to succeed.
Default
null
Example
10
minVoteCount
Description
The minimum number of votes required for the vote to succeed.
Default
null
Example
5
mysql-log
mysql-log
The mysql-log
plugin will log various server statistics and events to a MySQL database. This is great for server performance monitoring and/or player stat tracking.
Installation:
- Obtain/Install MySQL. MySQL v8.x.x has been tested with this plugin and is recommended.
- Enable legacy authentication in your database using this guide.
- Execute the schema to setup the database.
- Add a server to the database with
INSERT INTO Server (name) VALUES ("Your Server Name");
. - Find the ID of the server you just inserted with
SELECT * FROM Server;
. - Replace the server ID in your config with the ID from the inserted record in the database.
If you encounter any issues you can enable "debug": true
in your MySQL connector to get more error logs in the console.
Grafana:
- Grafana is a cool way of viewing server statistics stored in the database.
- Install Grafana.
- Add your MySQL database as a datasource named
SquadJS - MySQL
. - Import the SquadJS Dashboard to get a preconfigured MySQL only Grafana dashboard.
- Install any missing Grafana plugins.
Options
mysqlPool (Required)
Description
The name of the MySQL Pool Connector to use.
Default
mysql
overrideServerID
Description
A overridden server ID.
Default
null
seeding-message
seeding-message
The seeding-message
plugin broadcasts seeding rule messages to players at regular intervals or after a new player has connected to the server. It can also be configured to display live messages when the server goes live.
Options
mode
Description
Display seeding messages at a set interval or after players join. Either interval
or onjoin
.
Default
interval
interval
Description
How frequently to display the seeding messages in seconds.
Default
150000
delay
Description
How long to wait after a player joins to display the announcement in seconds.
Default
45000
seedingThreshold
Description
Number of players before the server is considered live.
Default
50
seedingMessage
Description
The seeding message to display.
Default
Seeding Rules Active! Fight only over the middle flags! No FOB Hunting!
liveEnabled
Description
Display a "Live" message when a certain player count is met.
Default
true
liveThreshold
Description
When above the seeding threshold, but within this number "Live" messages are displayed.
Default
2
liveMessage
Description
The "Live" message to display.
Default
Live
skipmap
skipmap
The skipmap
plugin will allow players to vote via +
/-
if they wish to skip the current map
Options
command
Description
The name of the command to be used in chat.
Default
!skipmap
voteDuration
Description
How long the vote should go on for.
Default
300000
startTimer
Description
Time before voting is allowed.
Default
900000
endTimer
Description
Time before voting is no longer allowed.
Default
1800000
pastVoteTimer
Description
Time that needs to have passed since the last vote.
Default
600000
minimumVotes
Description
The minimum percentage of people required to vote for the vote to go through.
Default
20
reminderInterval
Description
The time between individual reminders.
Default
120000
team-randomizer
team-randomizer
The team-randomizer
plugin can be used to randomize teams. It's great for destroying clan stacks or for social events. It can be run by typing !randomize
into in-game admin chat.
Options
command
Description
The command used to randomize the teams.
Default
!randomize
Creating Your Own Plugins
To create your own plugin you need a basic knowledge of JavaScript.
Typical plugins are functions that take the server as an argument in order to allow the plugin to access information about the server or manipulate it in some way:
function aPluginToLogServerID(server){
console.log(server.id);
}
Stored in the server object are a range of different properties that store information about the server.
id
- ID of the server.serverName
- Name of the server.maxPlayers
- Maximum number of players on the server.publicSlots
- Maximum number of public slots.reserveSlots
- Maximum number of reserved slots.publicQueue
- Length of the public queue.reserveQueue
- Length of the reserved queue.matchTimeout
- Time until match ends?gameVersion
- Game version.layerHistory
- Array history of layers used with most recent at the start. Each entry is an object with layer info in.currentLayer
- The current layer.nextLayer
- The next layer.players
- Array of players. Each entry is a PlayerObject with various bits of info in.
One approach to making a plugin would be to run an action periodically, in the style of the original SquadJS:
function aPluginToLogPlayerCountEvery60Seconds(server){
setInterval(() => {
console.log(server.players.length);
}, 60 * 1000);
}
A more common approach in this version of SquadJS is to react to an event happening:
function aPluginToLogTeamkills(server){
server.on(TEAMKILL, info => {
console.log(info);
});
}
A complete list of events that you can listen for and the information included within each is found here.
Various actions can be completed in a plugin. Most of these will involve outside system, e.g. Discord.js to run a Discord bot, so they are not documented here. However, you may run RCON commands using server.rcon.execute("Command");
.
If you're struggling to create a plugin, the existing plugins
are a good place to go for examples or feel free to ask for help in the Squad RCON Discord.
Statement on Accuracy
Some of the information SquadJS collects from Squad servers was never intended or designed to be collected. As a result, it is impossible for any framework to collect the same information with 100% accuracy. SquadJS aims to get as close as possible to that figure, however, it acknowledges that this is not possible in some specific scenarios.
Below is a list of scenarios we know may cause some information to be inaccurate:
- Use of Realtime Server and Player Information - We update server and player information periodically every 30 seconds (by default) or when we know that it requires an update. As a result, some information about the server or players may be up to 30 seconds out of date.
- SquadJS Restarts - If SquadJS is started during an active Squad game some information will be lost or not collected correctly:
- The current state of players will be lost. For example, if a player was wounded prior to the bot starting and then is revived/gives up after the bot is started information regarding who originally wounded them will not be known.
- The accurate collection of some server log events will not occur. SquadJS collects players' "suffix" name, i.e. their Steam name without the clan tag added via the game settings, when they join the server and uses this to identify them in certain logs that do not include their full name. As a result, for players connecting prior to SquadJS starting some log events associated with their actions will show the player as
null
. We aim to implement a solution to attempt to recover players' suffix names when this occurs, but the accuracy of correctly identifying players will be decreased.
- Duplicated Player Names - If two or more players have the same name or suffix name (see above) then SquadJS will be unable to identify them in the logs. When this occurs event logs will show the player as
null
. Be on the watch for groups of players who try to abuse this in order to TK or complete other malicious actions without being detected by SquadJS plugins.
Credits
SquadJS would not be possible without the support of so many individuals and organisations. My thanks goes out to:
- subtlerod for proposing the initial log parsing idea, helping to design the log parsing process and for providing multiple servers to test with.
- Fourleaf, Mex and various other members of ToG / ToG-L for helping to stage logs and participate in small scale tests.
- The Coalition community, including those that participate in Wednesday Fight Night, for participating in larger scale tests and for providing feedback on plugins.
- My GitHub sponsors!
- Everyone in the Squad RCON Discord and others who have submitted bug reports, suggestions and feedback.
- iDronee for providing Linux Squad server logs to ensure log parsing regexes support the OS.
License
Boost Software License - Version 1.0 - August 17th, 2003
Copyright (c) 2020 Thomas Smyth
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.