Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/VasquezRivero92/Discord_Faceit/llms.txt

Use this file to discover all available pages before exploring further.

When a Faceit match starts, the bot creates two private voice channels — one for each team — so players can communicate without interference. Only the players on each roster are granted access. When the match ends or is cancelled, players are returned to their original channels and the temporary channels are deleted. All of this logic lives in services/voice.js.
Voice channels are created in the same category as DISCORD_WAITING_ROOM_CHANNEL_ID. Make sure this channel exists and is placed inside a category — temporary match channels will appear alongside it.

Channel Creation — createMatchVoiceChannels()

async function createMatchVoiceChannels(guild, waitingRoomId, faction1, faction2, db)
Called during the match_status_starting / match_status_ready webhook event when autoVoiceChannels is enabled. The function:
  1. Fetches the waiting room channel to read its parentId (category).
  2. Builds a permissionOverwrites array for each team:
    • Everyone (guild.id) → Connect denied.
    • BotViewChannel, Connect, Speak, ManageChannels, MoveMembers allowed.
    • Each linked player in the roster → Connect, Speak allowed (resolved via db.getDiscordIdByFaceitId() with a db.getDiscordIdByNickname() fallback).
  3. Creates the two voice channels with guild.channels.create():
    • 🔊 <faction1.name> (or 🔊 Equipo A if no name)
    • 🔊 <faction2.name> (or 🔊 Equipo B if no name)
  4. Returns { vc1Id, vc2Id } for storage in Firestore via db.addActiveMatch().
Placing the waiting room channel inside a Discord category ensures that both team channels appear neatly grouped below it for the duration of the match.

Player Movement — movePlayersToVoice()

async function movePlayersToVoice(guild, players, voiceChannelId, db, reason)
Immediately after channels are created, movePlayersToVoice() is called once per team roster. For each player:
  1. Their Faceit player ID is resolved to a Discord ID (same two-step lookup as above).
  2. The guild member is fetched.
  3. If the member is currently in any voice channel, their current channel ID is recorded in originalStates[discordId] and then member.voice.setChannel(voiceChannelId) moves them.
The originalStates map is persisted to Firestore alongside the active match record so that cleanup can restore players to the correct channel.

Auto-Move on Reconnect

When autoMovePlayers is enabled, the voiceStateUpdate event handler checks whether a member who just connected (or entered the waiting room) is a participant in an active match. If they are, member.voice.setChannel() is called to move them directly to their team channel — no manual action required after a disconnect.

Match Cleanup — cleanupVoiceChannel()

async function cleanupVoiceChannel(guild, vcId, waitingRoomId, originalVoiceStates, reason)
Called for both team channels when a match finishes or is cancelled:
1

Restore original positions

For each member still in the temporary channel, the function checks originalVoiceStates[member.id]. If a previous channel ID is found it fetches that channel and calls member.voice.setChannel(originalChannel). If no original channel is recorded, members are moved to the waiting room instead.
2

Delete the channel

After all members have been moved, vc.delete(reason) removes the temporary channel. The deletion is logged via db.addLogEntry().
Cleanup is triggered by:
  • match_status_finished webhook event.
  • match_status_cancelled / match_status_aborted webhook event.
  • Force-cleanup from the admin panel (POST /api/admin/matches/<id>/cleanup).

Orphan Cleanup on Startup

async function cleanupOrphanVoiceChannels(guild, waitingRoomId)
When the bot starts (events/ready.js), it scans every channel in the guild for voice channels whose name starts with 🔊. Any found are cleaned up via cleanupVoiceChannel(). This handles the case where the bot was restarted mid-match and temporary channels were left behind from the previous session.

Expired Match Cleanup

Every 5 minutes, a setInterval in events/ready.js calls cleanupExpiredMatches(), which checks all active matches in Firestore for entries older than 2 hours (matchTimeoutMinutes, default 120). Expired matches are force-cleaned — voice channels deleted, match removed from Firestore, and the live panel updated.

Feature Flags

FlagEffect
autoVoiceChannelsCreates 🔊 TeamName voice channels when a match starts
autoMovePlayersMoves players from their current voice channel to their team channel on match start, and auto-moves reconnecting players during an active match

autoVoiceChannels

Channels are created with per-player permission overwrites so that only each team’s members can connect. The bot retains full control to move and delete them.

autoMovePlayers

Works both at match start (bulk move) and during the match (reconnect detection via voiceStateUpdate). Original channel states are always preserved for restoration.

Build docs developers (and LLMs) love