Голосовые каналы по интересам — авто-создание временных комнат
Если у тебя на Discord-сервере комьюнити висит десяток статичных голосовых каналов «Кастомка 1», «Кастомка 2», «Для двоих», «AFK» — и половина из них вечно пустая, а игроки всё равно толпятся в одном — знакомая боль. Статичные каналы либо не хватает, либо их слишком много и список превращается в свалку. Решение, которое реально прижилось в геймерских комьюнити — voice channel hub: один «канал-генератор», зайдя в который бот тут же создаёт тебе персональную временную комнату и переносит туда, а когда все выходят — комната исчезает сама. Ниже — как это поднять на практике, какие боты для этого есть и какие грабли вылезают на реальных серверах.
Содержание
Как работает hub-канал технически
Идея простая, но механика прячется в правах Discord API. Создаётся один голосовой канал-триггер (обычно называют «➕ Создать канал» или «Join to Create»). Бот слушает событие voiceStateUpdate — когда пользователь заходит именно в этот канал, срабатывает скрипт:
- Бот создаёт новый голосовой канал в той же категории через
guild.channels.create()с правами, где владельцем назначается зашедший игрок. - Игрока сразу перемещают (
member.voice.setChannel()) из хаба в свежесозданную комнату. - Канал живёт, пока в нём есть хоть один участник.
- При выходе последнего человека бот слушает
voiceStateUpdateна пустоту канала и удаляет его черезchannel.delete(), обычно с задержкой 5-15 секунд (чтобы не удалить канал, если человек просто переподключается или у него лагает клиент).
Важный нюанс: боту нужны права Manage Channels и Move Members именно в той категории, где живёт хаб — иначе создание/удаление будет падать с ошибкой прав, и в логах бота ты увидишь Missing Permissions (код 50013). Проверить это можно в настройках роли бота: Server Settings → Roles → выбрать роль бота → убедиться, что галочки стоят на уровне категории, а не только сервера в целом (права на категории можно переопределить отдельно, и часто именно это забывают).
Готовые боты: сравнение вариантов
Писать своего бота с нуля ради этой фичи почти всегда избыточно — есть проверенные готовые решения с открытым кодом или бесплатным тарифом.
| Бот | Тип | Лимит бесплатно | Кастомизация | Где хостить |
|---|---|---|---|---|
| VoiceMaster | Хостится разработчиком | До 2 хабов на сервере (бесплатно), Premium снимает лимит | Через слэш-команды, без кода | Не нужен свой хостинг |
| Kokoro (JoinToCreate) | Открытый исходник (Node.js) | Без лимита, сам хостишь | Полный доступ к коду | Свой VPS/сервер |
| ChannelMaster | Хостится разработчиком | Ограниченно на бесплатном тарифе | Слэш-команды + веб-панель | Не нужен свой хостинг |
| Самописный на discord.js | Свой код | Без лимита | Полная свобода | Свой VPS/сервер |
Для 90% серверов достаточно VoiceMaster — он закрывает базовый сценарий за 10 минут настройки командой /voicemaster setup, без единой строчки кода. Если хочешь именных прав, интеграции с игровой статистикой или экономикой сервера — тогда либо форкаешь Kokoro и правишь под себя, либо пишешь своего бота на discord.js/discord.py.
Если у тебя уже крутится RCON-бот или бот статистики онлайна на том же VPS — логично разместить и voice-хаб бота там же, чтобы не плодить процессы. Про выбор такого бота есть отдельный разбор: Discord-бот для управления игровым сервером.
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверМинимальный самописный вариант на discord.js
Если хочется не зависеть от чужого бота и контролировать логику — вот скелет на discord.js v14, который реально можно взять за основу:
const { Events, ChannelType, PermissionsBitField } = require('discord.js');
const HUB_CHANNEL_ID = '123456789012345678';
const CATEGORY_ID = '987654321098765432';
const tempChannels = new Map(); // channelId -> ownerId
client.on(Events.VoiceStateUpdate, async (oldState, newState) => {
// Игрок зашёл в хаб — создаём временный канал
if (newState.channelId === HUB_CHANNEL_ID) {
const guild = newState.guild;
const member = newState.member;
const tempChannel = await guild.channels.create({
name: `🎮 ${member.user.username}`,
type: ChannelType.GuildVoice,
parent: CATEGORY_ID,
userLimit: 5,
permissionOverwrites: [
{
id: member.id,
allow: [PermissionsBitField.Flags.ManageChannels, PermissionsBitField.Flags.MoveMembers],
},
],
});
tempChannels.set(tempChannel.id, member.id);
await member.voice.setChannel(tempChannel);
}
// Проверяем, не опустел ли какой-то временный канал
const oldChannel = oldState.channel;
if (oldChannel && tempChannels.has(oldChannel.id) && oldChannel.members.size === 0) {
setTimeout(async () => {
const fresh = await oldChannel.guild.channels.fetch(oldChannel.id).catch(() => null);
if (fresh && fresh.members.size === 0) {
await fresh.delete().catch(() => {});
tempChannels.delete(oldChannel.id);
}
}, 10000);
}
});
Задержка в 10 секунд перед проверкой и delete — не декоративная деталь, а обязательная защита от гонки состояний: событие VoiceStateUpdate может прилететь до того, как второй игрок реально успел зайти при быстром переключении между каналами. Без неё бот периодически удаляет канал прямо под ногами у людей.
Лимит участников и автоматическое именование
Дефолтный лимит на временную комнату обычно ставят 4-5 человек — под стандартный отряд в шутере или пати в выживалках. Но если сервер многопрофильный (и шутеры, и выживание, и RP), лучше дать игроку выбор при создании через интерактивное меню: бот присылает эфемерное сообщение с кнопками «Дуо (2)», «Сквад (5)», «Без лимита», и уже по выбору выставляет userLimit.
Имя канала — тоже точка, где стоит подумать заранее. Варианты, которые реально работают:
🎮 {username}— просто ник создателя, самый предсказуемый вариант;Комната {username}— чуть теплее для русскоязычного комьюнити;- динамическое имя по игре, если бот интегрирован с Discord Rich Presence и видит, во что играет создатель (сложнее в реализации, но выглядит красиво в списке каналов).
Владелец временного канала должен иметь возможность переименовать его и поднять/снять лимит без прав администратора — иначе фича превращается в обузу для модераторов, которых будут дёргать в личку с просьбой «переименуй». В VoiceMaster это закрыто панелью управления через /voicemaster или кнопки в текстовом канале-логе; в самописном варианте это как раз permissionOverwrites на ManageChannels, которые ты видишь в примере кода выше.
Куда девать текстовые каналы temp-комнат
Отдельный вопрос — нужен ли временный текстовый канал в паре с голосовым. Для казуальных серверов обычно нет: игроки договариваются голосом. Но если у тебя RP-сервер или комьюнити активно шарит скриншоты/ссылки во время созвона — стоит генерировать приватный текстовый канал синхронно с голосовым, с теми же правами доступа (видят только те, кто в голосовом). Технически это тот же паттерн channels.create(), только type: ChannelType.GuildText, и permissionOverwrites синхронизируются с голосовым каналом при каждом входе/выходе участника.
На RP-серверах с FiveM это особенно актуально в связке с прокси-войсом — если у тебя уже настроен PMA-Voice или saltychat для дальности голоса в игре, temp-каналы Discord обычно используют как резервный внеигровой чат, а не основной. Подробности по игровому голосовому чату — в статье FiveM: рации и голосовой чат — PMA-Voice, saltychat.
Организация категорий и структура сервера
Хаб-канал и все временные комнаты держи в отдельной категории «🔊 Голосовые комнаты», физически отделённой от статичных каналов сообщества (общий чат, лобби модераторов, войс для стримов). Это не только для порядка — права на категорию наследуются каналами внутри неё, так что примени Manage Channels и Move Members боту один раз на уровне категории, и они автоматически применятся ко всем создаваемым temp-каналам.
Если структура сервера ещё не продумана целиком — до настройки авто-каналов стоит сначала навести порядок в базовой иерархии категорий и ролей, иначе временные комнаты просто добавят хаос в существующий бардак. Разбор с нуля есть здесь: Discord-сервер сообщества: структура каналов.
Ограничение Discord на количество каналов в одной категории — 50. Для большинства серверов это некритично, но если у тебя очень активное комьюнити с сотнями онлайн одновременно и почти каждый плодит свою комнату, можно упереться в лимит в пиковые часы. Решается либо повышением задержки удаления пустых каналов (чтобы освобождались быстрее), либо второй параллельной категорией-хабом с балансировкой между ними — этот сценарий уже редкий, но стоит держать в голове на вырост.
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверЧастые вопросы
Бот удаляет канал, пока я ещё говорю с другом, который просто перезашёл?
Это симптом слишком короткой задержки перед удалением. Увеличь таймаут до 10-15 секунд в коде (или в настройках VoiceMaster/Kokoro) — обычно хватает с запасом на реконнект клиента.
Можно ли ограничить, кто видит временную комнату в списке каналов?
Да, через permissionOverwrites — по умолчанию канал виден всем на сервере (ViewChannel: true для @everyone), но можно сделать приватным, скрыв его от всех кроме создателя и тех, кого он явно пригласит командой бота.
VoiceMaster бесплатный лимит в 2 хаба — это мало для нашего сервера с несколькими играми?
Для мультигейм-комьюнити логичнее один хаб с выбором лимита участников через кнопки при заходе, чем несколько отдельных хабов под каждую игру — так проще для новых участников и не упирается в бесплатный лимит бота.
Что если бот с temp-каналами упадёт, пока люди сидят внутри?
Каналы никуда не денутся — они обычные каналы Discord, просто без активного слушателя событий. При перезапуске бота стоит добавить проверку при старте: пройтись по категории и удалить все пустые каналы, оставшиеся от прошлой сессии (память бота tempChannels в примере кода выше не переживает рестарт, если не сохранять её в файл или базу).
Нужны ли отдельные права модераторам на временные комнаты?
Да, обязательно оставь модераторской роли Move Members и Mute Members на уровне категории, независимо от прав владельца temp-канала — иначе при конфликте между игроками модератор физически не сможет вмешаться.