Como Integrar um Bot de Discord com seu Servidor de MU Online
Aprenda a criar e configurar um bot de Discord que se conecta ao banco de dados do seu servidor MU Online para exibir rankings, status e notificações.
Visão Geral
Integrar um bot de Discord ao seu servidor de MU Online permite automatizar tarefas como exibir rankings em tempo real, notificar Castle Siege, anunciar top resets e monitorar o status do servidor — tudo diretamente nos canais do Discord da sua comunidade.
Este tutorial cobre a criação de um bot com Node.js + discord.js v14, conexão ao SQL Server do MuServer (Season 6 Episode 3, compatível com S4–S13) e implantação no mesmo VPS Windows Server onde o servidor MU roda.
Pré-requisitos
- VPS com Windows Server 2012/2016/2019 e MuServer instalado
- SQL Server 2008/2012/2014/2017 com banco
MuOnlineacessível - Node.js 18 LTS instalado no VPS (ou em outra máquina com acesso à porta 1433)
- Uma conta de desenvolvedor no Discord com permissão para criar aplicações
- Acesso ao painel do Discord Developer Portal
Parte 1 — Criar a Aplicação e o Bot no Discord
1. Acesse discord.com/developers/applications e clique em New Application.
2. Dê um nome à aplicação (ex: MuBot ViciadosMU) e confirme.
3. No menu lateral, acesse Bot → clique em Add Bot → confirme.
4. Em Privileged Gateway Intents, habilite:
SERVER MEMBERS INTENTMESSAGE CONTENT INTENT
5. Copie o Token do bot — você usará no arquivo .env. Nunca compartilhe este token publicamente.
6. Acesse OAuth2 → URL Generator, marque os escopos bot e applications.commands, e nas permissões marque:
- Send Messages
- Embed Links
- Read Message History
- Use Slash Commands
7. Copie a URL gerada, abra no navegador e adicione o bot ao servidor Discord da sua comunidade.
Parte 2 — Configurar o SQL Server para Conexões Externas
1. Abra o SQL Server Configuration Manager no VPS.
2. Em SQL Server Network Configuration → Protocols for MSSQLSERVER, habilite TCP/IP.
3. Clique duas vezes em TCP/IP → aba IP Addresses → role até IPAll → defina TCP Port como 1433.
4. Reinicie o serviço SQL Server:
net stop MSSQLSERVER
net start MSSQLSERVER
5. Crie um usuário SQL de leitura exclusivo para o bot (não use sa):
USE [master]
GO
CREATE LOGIN [mubot_reader] WITH PASSWORD = 'SuaSenhaForte!123',
DEFAULT_DATABASE = [MuOnline],
CHECK_EXPIRATION = OFF,
CHECK_POLICY = OFF;
GO
USE [MuOnline]
GO
CREATE USER [mubot_reader] FOR LOGIN [mubot_reader];
GO
-- Permissão de leitura apenas nas tabelas necessárias
GRANT SELECT ON [dbo].[Character] TO [mubot_reader];
GRANT SELECT ON [dbo].[MEMB_INFO] TO [mubot_reader];
GRANT SELECT ON [dbo].[CastleSiege] TO [mubot_reader];
GO
INSERT, UPDATE ou DELETE ao usuário do bot. Acesso de escrita ao banco de dados do MU pode comprometer a integridade do servidor.6. No firewall do Windows Server, abra a porta 1433 (somente se o bot rodar externamente):
netsh advfirewall firewall add rule name="SQL Server MuBot" ^
protocol=TCP dir=in localport=1433 action=allow
Parte 3 — Instalar e Configurar o Projeto do Bot
1. No VPS (ou servidor dedicado ao bot), abra o PowerShell e crie a estrutura do projeto:
mkdir C:\MuBot
cd C:\MuBot
npm init -y
npm install discord.js@14 mssql dotenv
2. Crie o arquivo C:\MuBot\.env:
DISCORD_TOKEN=SEU_TOKEN_AQUI
CLIENT_ID=ID_DA_SUA_APLICACAO
GUILD_ID=ID_DO_SEU_SERVIDOR_DISCORD
DB_SERVER=127.0.0.1
DB_PORT=1433
DB_DATABASE=MuOnline
DB_USER=mubot_reader
DB_PASSWORD=SuaSenhaForte!123
3. Crie o arquivo C:\MuBot\database.js:
const sql = require('mssql');
require('dotenv').config();
const config = {
server: process.env.DB_SERVER,
port: parseInt(process.env.DB_PORT),
database: process.env.DB_DATABASE,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
options: {
encrypt: false,
trustServerCertificate: true,
enableArithAbort: true,
},
pool: {
max: 10,
min: 0,
idleTimeoutMillis: 30000,
},
connectionTimeout: 15000,
requestTimeout: 15000,
};
const pool = new sql.ConnectionPool(config);
const poolConnect = pool.connect();
pool.on('error', err => {
console.error('[DB] Erro no pool de conexões:', err);
});
module.exports = { pool, poolConnect, sql };
Parte 4 — Implementar os Comandos Slash
1. Crie C:\MuBot\commands\ranking.js:
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { pool, poolConnect, sql } = require('../database');
module.exports = {
data: new SlashCommandBuilder()
.setName('ranking')
.setDescription('Exibe o Top 10 de resets do servidor'),
async execute(interaction) {
await interaction.deferReply();
try {
await poolConnect;
const request = pool.request();
const result = await request.query(`
SELECT TOP 10
ROW_NUMBER() OVER (ORDER BY c.Resets DESC, c.cLevel DESC) AS Posicao,
c.Name AS Personagem,
c.Resets AS Resets,
c.cLevel AS Level,
CASE c.Class
WHEN 0 THEN 'Dark Wizard'
WHEN 1 THEN 'Soul Master'
WHEN 2 THEN 'Grand Master'
WHEN 16 THEN 'Dark Knight'
WHEN 17 THEN 'Blade Knight'
WHEN 18 THEN 'Blade Master'
WHEN 32 THEN 'Fairy Elf'
WHEN 33 THEN 'Muse Elf'
WHEN 34 THEN 'High Elf'
WHEN 48 THEN 'Magic Gladiator'
WHEN 64 THEN 'Dark Lord'
WHEN 80 THEN 'Summoner'
ELSE 'Desconhecido'
END AS Classe
FROM MuOnline.dbo.Character c
WHERE c.Name NOT LIKE 'GM_%'
ORDER BY c.Resets DESC, c.cLevel DESC
`);
const embed = new EmbedBuilder()
.setTitle('🏆 Top 10 Resets')
.setColor(0xFFD700)
.setTimestamp()
.setFooter({ text: 'ViciadosMU' });
const linhas = result.recordset.map(row =>
`**${row.Posicao}.** ${row.Personagem} — ` +
`${row.Resets} Resets | Lv ${row.Level} | ${row.Classe}`
).join('\n');
embed.setDescription(linhas || 'Nenhum dado encontrado.');
await interaction.editReply({ embeds: [embed] });
} catch (err) {
console.error('[ranking] Erro:', err);
await interaction.editReply('Erro ao consultar o banco de dados. Tente novamente.');
}
},
};
2. Crie C:\MuBot\commands\status.js:
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { pool, poolConnect, sql } = require('../database');
module.exports = {
data: new SlashCommandBuilder()
.setName('status')
.setDescription('Mostra o status atual do servidor MU'),
async execute(interaction) {
await interaction.deferReply();
try {
await poolConnect;
const request = pool.request();
const result = await request.query(`
SELECT COUNT(*) AS Online
FROM MuOnline.dbo.MEMB_STAT
WHERE ConnectStat = 1
`);
const online = result.recordset[0].Online;
const embed = new EmbedBuilder()
.setTitle('🟢 Status do Servidor')
.setColor(0x00FF00)
.addFields(
{ name: 'Jogadores Online', value: `${online}`, inline: true },
{ name: 'Servidor', value: 'Online', inline: true }
)
.setTimestamp()
.setFooter({ text: 'ViciadosMU' });
await interaction.editReply({ embeds: [embed] });
} catch (err) {
console.error('[status] Erro:', err);
await interaction.editReply('Servidor indisponível ou erro de conexão.');
}
},
};
Parte 5 — Arquivo Principal e Registro de Comandos
1. Crie C:\MuBot\index.js:
const { Client, GatewayIntentBits, Collection } = require('discord.js');
const fs = require('fs');
const path = require('path');
require('dotenv').config();
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
],
});
client.commands = new Collection();
const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(f => f.endsWith('.js'));
for (const file of commandFiles) {
const command = require(path.join(commandsPath, file));
client.commands.set(command.data.name, command);
}
client.once('ready', () => {
console.log(`[Bot] Online como ${client.user.tag}`);
});
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) return;
try {
await command.execute(interaction);
} catch (err) {
console.error(err);
if (interaction.replied || interaction.deferred) {
await interaction.followUp({ content: 'Erro interno.', ephemeral: true });
} else {
await interaction.reply({ content: 'Erro interno.', ephemeral: true });
}
}
});
client.login(process.env.DISCORD_TOKEN);
2. Crie C:\MuBot\deploy-commands.js para registrar os slash commands:
const { REST, Routes } = require('discord.js');
const fs = require('fs');
const path = require('path');
require('dotenv').config();
const commands = [];
const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(f => f.endsWith('.js'));
for (const file of commandFiles) {
const command = require(path.join(commandsPath, file));
commands.push(command.data.toJSON());
}
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
(async () => {
try {
console.log('Registrando slash commands...');
await rest.put(
Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID),
{ body: commands }
);
console.log('Slash commands registrados com sucesso!');
} catch (err) {
console.error(err);
}
})();
3. Execute o registro dos comandos:
cd C:\MuBot
node deploy-commands.js
4. Inicie o bot:
node index.js
Parte 6 — Manter o Bot Rodando com PM2
Para que o bot inicie automaticamente e seja reiniciado em caso de falha, use o PM2:
npm install -g pm2
cd C:\MuBot
pm2 start index.js --name "mubot"
pm2 save
pm2 startup
pm2 logs mubot para monitorar os logs em tempo real e pm2 restart mubot para reiniciar após atualizações.Troubleshooting
Erro ECONNREFUSED 127.0.0.1:1433 → O SQL Server não está escutando na porta 1433. Verifique se o protocolo TCP/IP está habilitado no SQL Server Configuration Manager e se o serviço foi reiniciado.
Erro Login failed for user 'mubot_reader' → Confirme que o SQL Server está no modo de autenticação misto (SQL Server and Windows Authentication). Acesse Properties → Security no SQL Server Management Studio.
Slash commands não aparecem no Discord → Execute node deploy-commands.js novamente. Comandos de guild aparecem em até 1 minuto; comandos globais podem levar até 1 hora.
Query retorna 0 jogadores online → Verifique se a tabela MEMB_STAT existe no seu banco. Algumas versões do MuServer usam ConnectServer.dbo.MEMB_STAT em banco separado.
Character pode ter nome diferente dependendo da versão do MuServer: T_Character, Characters ou dbo.Character. Ajuste as queries conforme o schema do seu banco executando SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'.Perguntas frequentes
Qual versão do Node.js devo usar?
Use Node.js 18 LTS ou superior. Versões anteriores podem ter incompatibilidades com a biblioteca discord.js v14, que exige pelo menos Node.js 16.9.0.
O bot precisa estar no mesmo servidor (VPS) que o MU?
Não necessariamente. O bot pode rodar em qualquer máquina com acesso ao SQL Server. Basta liberar a porta 1433 no firewall do VPS e configurar o SQL Server para aceitar conexões remotas.
Como evitar que o bot exponha dados sensíveis dos jogadores?
Nunca retorne campos como password, serial ou md5pwd nas queries. Use SELECT somente nas colunas necessárias (Name, Level, Class, Reset) e crie um usuário SQL de leitura específico para o bot.
O bot para de responder após algumas horas — por quê?
Isso normalmente indica que a conexão com o SQL Server foi encerrada por inatividade. Implemente reconexão automática com pool de conexões (mssql usa pool por padrão) e configure connectionTimeout e requestTimeout no objeto de configuração.