Discord bot for Warface Tournaments
RoleKeeper is a bot specificly designed to handle Warface Discord tournament servers. Its main features are:
- Auto-assignment of team captain and group roles based on an CSV file (exported from esports site);
- Creation of chat channels used for guided pick & ban sequence (bo1, bo2, bo3);
- Broadcast of events from and to match chat channels (match room created, streamed match, pick&ban results).
It was successfuly used in the June Fast Cup (JFC 2017) with over 100 teams, first Warface Tournament ever ran on Discord. It has been used and polished ever since.
Here is a quick demonstration (from 2017) of what Rolekeeper does:
The bot has a chat-command interface. A command starts with a !
(bang sign)
followed by the command name, a space and then the command arguments.
A Team captain is a member imported using the !add_captain
or !start_cup
commands.
!ban map
, bans mapmap
from the map list available in the pick & ban sequence.map
is case-insensitively matched at 80% with available maps. A shortcut-
is available (e.g.-pyramid
to ban mapPyramid
);!pick map
, same as!ban
excepts it is used to pick a map (best-of-3 only). A shortcut+
is available (e.g.+d17
to pick mapD17
);!side side
, chooses the side, either attack or defense. A shortcut=
is available (e.g.=wf
to take Warface side). There is also!defend
and!attack
as shortcuts.
Note: The above commands are only available in a match chat channel created by the bot itself.
A judge referee is a member with the role roles/referee
!say #channel message...
, makes the bot saymessage...
inchannel
. Note thatchannel
has to be a valid chat-channel mention. If nomessage...
is given, one can attach a file;!bo1 @teamA @teamB [>cat] [cup] [new/reuse]
(Both first arguments have to be existing Discord role mentions, team names or Discord captain mention);- Creates a chat room named
match_teamA_vs_teamB
(with transliteration); - If
>cat
is given, creates the channel in thecat
channel category wherecat
has to be given inservers/.../categories/
; - Broadcast the fact the channel was created in rooms
servers/.../rooms/match_created
; - Gives permissions to
teamA
andteamB
roles to write in the chat room; - Starts a best-of-1 map pick & ban sequence (6xban, 7th is a pick, side);
- Team captains are invited to type
!ban map
,!pick map
or!side side
one after the other; - Prints the summary of elected maps and sides;
- Broadcast the results in rooms
servers/.../rooms/match_starting
. Note: When a match already exists for the 2 teams, the bot will ask to either addreuse
ornew
in the command. Otherwise, these arguments should never be given to avoid mistakes.
- Creates a chat room named
!bo2 @teamA @teamB ...
, same as!bo1
excepts it creates a best-of-2 chat channel (ban, ban, pick, pick, side);!bo3 @teamA @teamB ...
, same as!bo1
excepts it creates a best-of-3 chat channel (ban, ban, pick, pick, ban, ban, 7th is a pick, side);!add_captain @captain teamA nickname group|- [cup]
, add captain to the captain database (for cupcup
), assign the captain, team and group roles and rename the captain to the one defined in the CSV file. Argumentgroup
is mandatory, but if no group is required, use-
(dash);!update_captain @captain nickname [cup]
, updates a captain discord ID using his nickname as a lookup in the database;!remove_captain @captain [cup]
, remove a captain from the captain database (for cupcup
), reset its nickname, remove the assigned roles.!add_group group [cup]
, add group to the group database. Heregroup
should correspond to{}
inroles/group
(e.g.Group {}
). The Discord role for that group has to exist;!remove_group group [cup]
, remove a group from the group database.!ban
,!pick
and!side
commands (see Team captains) are available to referees so that they can test or bridge team captains choice if they are not in Discord server;!undo
, to go back 1 step in the pick & ban sequence;!close
, to close a pick & ban sequence (can be reopenned with!undo
).
Note: The cup
argument is optional if there is only 1 cup running. Else it
is mandatory.
A streamer is a member with the role roles/streamer
!stream match_id [@streamer]
, will broadcast the information thatmatch_id
will be streamed by the one executing the command. Rolekeeper providesmatch_id
to channelsservers/.../rooms/match_created
which streamers should have access to. The bot will also give visibility (read only) to the streamer on the match room ifservers/.../streamer_can_see_match
istrue
. If the optional@streamer
argument is given (valid Discord mention) then it will be used in place of the command author.
An admin is a member with Discord permission manage roles
, someone that has
access to the config.json
file and bot launch.
!check_cup cup [// CSV]
, takes the attached CSV and builds a report of missing members or invalid Discord IDs. If the command was already used and we just want to run the check with the same database, the attached file is optional;!start_cup cup [maps_key] [// CSV]
, same as!check_cup
but actually imports the captains and teams, and start assigning the roles. Same as!check_cup
, if there was already a CSV given to check, the attached CSV file is optional. Once!start_cup
is used, the scratchpad is emptied. Ifmaps_key
is given, use this one as the map pool key instead of the default one for the server;!stop_cup cup
, wipes out teams, captains and matches, then unregisters the cup from the database;!start_hunt cup [#channel]
, to use a channel as an automatic!update_captain
one: Each captain can write their team name or registered nickname and the bot will automatically use it to update the captain discord;!check_captain @captain
, to check if a captain is recognized as a captain by the bot;!update_cup cup // CSV
, to bulk update groups/discords;!update_team oldname newname
, to change a team's name;!stop_hunt cup
, to stop from seeing the channel as a captain hunt;!broadcast on/off
, to enable broadcast notifications globally;!reconfig
, to reload the configuration file without restarting the bot;!members
, will generate a CSV of all members in the Discord server;!captains [cup]
, will generate a CSV of all captains in a format that is compatible with!start_cup
;!stats [cup]
, will generate a CSV of pick&bans statistics;!wipe_matches all/rooms/finished [cup]
, will either remove all match chat channels created from DB and Discord (all
), all but only from Discord (rooms
) or only from Discord the ones that are finished (finished
) ;!wipe_messages #channel
, will remove all non-pinned messages inchannel
. Note thatchannel
has to be a valid chat-channel mention.
Rolekeeper requires Python >=3.5. Entrypoint is main.py
, which takes an
optional 1st argument, the configuration file. By default, no argument given
means Rolekeeper will look for the file config.json
.
Example:
~/rolekeeper/$ ./main.py config_mr.py
or:
~/rolekeeper/$ ./main.py
Using default configuration file path: `config.json`
...
This project requires Python >=3.5 as it uses extensively the Python
Discord API. It is recommended to run
it in a Python virtualenv
and install dependencies with pip
.
- Clone the project
$ git clone https://github.com/Levak/RoleKeeper.git
$ cd RoleKeeper
- Create a virtual env
$ python -m venv env
$ source ./env/bin/activate
(venv) $ pip install -r requirements.txt
-
Go to Discord application registration page and create an app with a bot.
In there, enable "SERVER MEMBERS INTENT" in the "Priviledged Gateway Intents".
-
Edit
config.json
and:- Fill
app_bot_token
with the APP BOT USER token; - Change or add a discord server with its member list;
- Fill
config.json
...
"app_bot_token" = "--redacted--",
...
"servers" : {
"My Discord server": {
"db": "myserver",
...
}
},
...
- Invite the bot to the Discord server (replace
BOT_CLIENT_ID
with the one from the bot app page)
https://discordapp.com/oauth2/authorize?client_id=BOT_CLIENT_ID&scope=bot&permissions=403172432
This link should give the following permissions:
- Manage roles;
- Manage nicknames;
- Manage channels;
- Manage messages;
- Read message history;
- Read/Send messages (+attach, +react, +embed).
Note: Make sure the bot role is just below the admin role (above the roles it manages)
- Create the mandatory roles in the Discord server (names can be changed
in
config.json
):
Note: Make sure these roles are below RoleKeeper
role in Discord role
list so that it can manage them.
- Run RoleKeeper
(venv) $ python ./main.py
-
Create a
members.csv
file (see Member list section) -
Check the members for a cup (in Discord):
Levak: !check_cup mycup
<members.csv>
- Start the cup (in Discord):
Levak: !start_cup mycup
- Create pick&ban rooms (in Discord):
Levak: !bo1 @noob team @pro team
Levak: !bo2 @op team @ez team
Levak: !bo3 @wp team @gg team
- Fetch the pick&ban statistics and stop the cup (in Discord):
Levak: !stats mycup
Levak: !stop_cup mycup
Once everything is setup, the only things to repeat are steps 8 to 12.
The bot is configurable at startup with the file config.json
. This file
defines all the variable parameters supported by RoleKeeper, such as role
names, member list path per guilds, broadcast lists, etc.
Here is an example of configuration file:
config.json
{
"app_bot_token": "--redacted--",
"roles": {
"referee": { "name": "Referees" },
"streamer": { "name": "Streamers" },
"captain": { "name": "{} Captains", "color": "0xf1c40f" },
"group": { "name": "Group {}" },
"team": { "name": "{} team", "color": "orange" }
},
"maps": {
"ptb": [ "Yard", "D-17", "Factory", "District", "Destination", "Palace", "Pyramid" ],
"test": [ "Lorem", "Ipsum", "Dolor", "Sit", "Amet", "Consectetur", "Adipiscing" ]
},
"guilds": {
"June Fast Cup": {
"db": "jfc",
"default_maps": "ptb",
"rooms": {
"match_created": [ "jfc_streamers" ],
"match_starting": [ "bot_referees", "jfc_streamers" ]
},
"streamer_can_see_match": true,
"categories": {
"A": "Referee A",
"B": "Referee B"
}
},
"JFCtest": {
"db": "jfctest",
"default_maps": "test",
"rooms": {
"match_created": [ "streamers" ],
"match_starting": [ "referees", "streamers" ]
}
}
}
}
String. Name of the role. The role may support formating string, in such
cases, use {}
to indicate the location where the formatting will happen
(e.g. {} team
will become Foobar team
for team Foobar
).
String. Color of the role in Discord. The format may be hexadecimal
(e.g. 0xFFFFFF
) or the name of the color (e.g. orange
).
String. Token for the bot. Go to Discord application page, click on your application, then create a bot for the application and expand the APP BOT TOKEN.
String. ID of the emote to use for loading operations. Can be ommited and no loading emoji will be used. In order to add a custom loading emoji, add an animated emoji to a server the bot has access to (e.g. this one ), right click on it, "Open image in a new tab" and copy the digit part of the URL.
Role. Role used for Judge referees.
Role. Role used for Streamers/Casters.
Role. Role used for Team captains. Formatted with the cup name.
Role. Role used for the Team Groups. Formatted with the group ID.
Role. Role used for the Team names. Formatted with the team name.
Dict of List of String. All the available maps for the pick & ban
sequences indexed by "key". May contain any number of maps per key. "key" is
used to reference a map pool in !start_cup
and in
guilds/.../default_maps
.
String. Name of the persistent storage DB on the disk (unique per server).
String. Key referencing the map pool defined in maps/...
.
List of String. Channels that will receive match creation notifications,
when either !bo1
or !bo3
is used.
List of String. Channels that will receive match start notifications, when ever the pick & ban sequence has ended.
Boolean. If true
, then when creating a match, a streamer that uses the
!stream
command will be able to see (read-only) the said rooms. Useful
when the streamer needs to see the pick&ban sequence, or know when/if the
match is about to start.
Dict of String. Discord channel category shortcuts. e.g.
"categories": {
"A": "Referee A",
"B": "Referee B"
}
And then use it like this:
!bo1 @xxx @yyy >A
!bo1 @zzz @www >B
RoleKeeper heavily relies on members.csv
files that contain all team
captains Discord ID, team name, group and IGN. Based on such file, the bot is
able to rename, create the team role, and assign it to the team captain
whenever he joins the Discord server.
A member.csv
file can be remotely uploaded via Discord to the bot using the
!check_cup
or !start_cup
command (attach the file to the Discord message).
A members.csv
file has to be in the following format (comma separated
values, #
for comments):
members.csv
#discord,team_name,nickname,group
ezpz#4242,Noobs,AllProsAboveMe,A
gg#2424,Pros,xX-AtTheTop-Xx,B
noob42#777,PGM,SixSweat,C
Note: The first line of the members.csv file has to contain column names
that match the ones in the above example. That is, discord
, team_name
,
nickname
and group
. There can be other columns with other names, these
will be ignored.
The above member list makes RoleKeeper wait for any server join from
ezpz#4242
, gg#2424
and noob42#777
on the Discord server the command was
ran on.
For instance, once ezpz#4242
joins the server, he will be:
- Renamed to
AllProsAboveMe
; - Assigned roles
TestCup Captains
,Group A
andNoobs team
.
CAUTION: NEVER MANUALLY ASSIGN TEAM ROLES TO CAPTAINS. The bot uses
its own database to know who is and who isn't allowed to use captain
commands. A team captain can only be added using the !add_captain
and
!start_cup
(bulk) commands. Do not try to give the Discord roles manually to
them. You may think the captain is now allowed to see the room, but he will be
unable to pick or ban maps.
-
It is recommanded to create a chat channel
#bot_commands
that both bot and referees can see and talk in order to enter all bot commands. It will ease command tracking and prevent spam in lobby channels. -
Groups are useful to separate teams among referees. A referee handles one and only one group, until the brackets merge. At this point, some referees lose the responsability of their group. It is recommanded to create chat channels like
#group_a
where members with roleGroup A
are able to read/send messages. When the groups merge, referees can manually assign the new group role to the affected team captains.
Driver specific to https://esports.mail.ru and https://esports.my.com to automatically start pick & ban rooms based on available matches.
Note: This is outdated as the websites merged into https://pvp.gg which has its own online pick-ban system.
!sync_cup cup http://cup_url [>cat]
, to start the synchronisation;!desync_cup cup
, to stop the synchronization.
The following fields are added into the configuration file:
"driver": {
"refresh_period": 60,
"max_advance": 3600,
"utc_offset": 0
},
Integer. Refresh rate of the driver in seconds.
Integer. Maximum advance to take before creating a match.
Integer. Offset in hours of the parsed times.
- Reparse
members.csv
or provide a more dynamic way of adding team captains at the last-minute - Cross-server non-interference (When the bot is invited in several Discord guilds, it will run on the same member list)
- Take
config.json
as parameter - Configurable role names and list
- Configurable map list
- Forward pick & ban results in a room for a new
Streamer
role - Add
!stream
command for a newStreamer
role to notify matches are streamed - Handle unicode team names in order to create valid Discord chat channel names.
- Add
!setup
for admin to create all channels and required roles (first time install). - Add
!wipe_match_rooms
for admin to remove all match chat rooms. - Add
!wipe_team_roles
for admin to remove all team captain roles. - (idea) Import
members.csv
directly from esports website - (idea) Automatically launch
!bo1
/!bo3
based on info from esports website - (idea) Handle match result gathering (with vote from both teams)
- Add progress for long operations, e.g.
!refresh
,!wipe_teams
,!wipe_matches
- Add CSV upload instead of static memberlist.
- Support multiple cups at the same time, e.g.
!start_cup x
and!stop_cup x
- Regroup match chat rooms by categories (new Discord feature, requires new discord.py)
- Export pick/ban stats command, or on
!stop_cup
-
!export_members
to export server member list -
!unstream x
to cancel!stream x
. -
!undo
to undo a!ban
or!pick
- unlimited and dynamid map pools instead of just 7 maps
- Replace Esports Driver with a Toornament Driver