Настройка интеграции с Discord для Bedrock сервера

Материал из ARK-HOSTER.RU | Документация хостинга
Перейти к: навигация, поиск

Настройка интеграции с Discord для Bedrock сервера

1. Подготовка

  • Убедитесь, что Bedrock сервер установлен и работает.
  • Создайте Discord бота через Discord Developer Portal.
  • Получите токен бота и ID канала для уведомлений.
  • Установите Node.js или Python для скриптов интеграции.
  • Рекомендуется использовать Ubuntu 24.04 LTS.

2. Создание Discord бота

Регистрация бота

1. Перейдите на https://discord.com/developers/applications 2. Нажмите "New Application" 3. Введите имя приложения 4. Перейдите в раздел "Bot" 5. Нажмите "Add Bot" 6. Скопируйте токен бота (понадобится позже)

Настройка прав бота

1. В разделе "Bot" включите необходимые права:

  • Send Messages
  • Embed Links
  • Read Message History
  • Use External Emojis

2. Скопируйте URL для приглашения бота:

  • Раздел "OAuth2" → "URL Generator"
  • Выберите scope: `bot`
  • Выберите права: `Send Messages`, `Read Message History`
  • Скопируйте URL и откройте в браузере для приглашения

3. Установка Node.js и зависимостей

Установка Node.js

1. Установите Node.js:

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

2. Проверьте установку:

node -v
npm -v

Создание проекта

1. Создайте директорию:

sudo mkdir -p /opt/bedrock-discord
cd /opt/bedrock-discord

2. Инициализируйте npm проект:

sudo npm init -y

3. Установите discord.js:

sudo npm install discord.js axios

4. Создание базового бота

Базовый скрипт бота

1. Создайте файл бота:

sudo nano bot.js

2. Добавьте содержимое:

const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js');
const { spawn } = require('child_process');
const fs = require('fs');

\# Конфигурация
const config = {
    token: process.env.DISCORD_TOKEN || 'YOUR_BOT_TOKEN',
    channelId: process.env.DISCORD_CHANNEL_ID || 'YOUR_CHANNEL_ID',
    logFile: '/opt/bedrock/logs/latest.log'
};

\# Создание клиента
const client = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent
    ]
});

\# Обработка подключения
client.once('ready', () => {
    console.log(`Bot connected as ${client.user.tag}`);
    sendMessage('🟢 Bedrock сервер бот запущен и готов к работе!');
});

\# Команды бота
client.on('messageCreate', async (message) => {
    if (message.author.bot) return;
    
    const prefix = '!';
    if (!message.content.startsWith(prefix)) return;
    
    const args = message.content.slice(prefix.length).trim().split(' ');
    const command = args.shift().toLowerCase();
    
    switch (command) {
        case 'status':
            await handleStatusCommand(message);
            break;
        case 'start':
            await handleStartCommand(message);
            break;
        case 'stop':
            await handleStopCommand(message);
            break;
        case 'players':
            await handlePlayersCommand(message);
            break;
    }
});

\# Функции обработки команд
async function handleStatusCommand(message) {
    const status = getServerStatus();
    const embed = new EmbedBuilder()
        .setTitle('Статус Bedrock сервера')
        .setColor(status ? 0x00FF00 : 0xFF0000)
        .setDescription(status ? '🟢 Сервер запущен' : '🔴 Сервер остановлен')
        .setTimestamp();
    
    if (status) {
        const info = getServerInfo();
        if (info) {
            embed.addFields(
                { name: 'Memory', value: `${info.memory} MB`, inline: true },
                { name: 'CPU', value: `${info.cpu}%`, inline: true }
            );
        }
    }
    
    await message.reply({ embeds: [embed] });
}

async function handleStartCommand(message) {
    if (!message.member.permissions.has('ADMINISTRATOR')) {
        return message.reply('❌ У вас нет прав для выполнения этой команды');
    }
    
    sendMessage('⏳ Запуск сервера...');
    const proc = spawn('sudo', ['systemctl', 'start', 'minecraft-bedrock']);
    
    proc.on('close', (code) => {
        if (code === 0) {
            sendMessage('🟢 Сервер успешно запущен!');
        } else {
            sendMessage('❌ Ошибка при запуске сервера');
        }
    });
}

async function handleStopCommand(message) {
    if (!message.member.permissions.has('ADMINISTRATOR')) {
        return message.reply('❌ У вас нет прав для выполнения этой команды');
    }
    
    sendMessage('⏳ Остановка сервера...');
    const proc = spawn('sudo', ['systemctl', 'stop', 'minecraft-bedrock']);
    
    proc.on('close', (code) => {
        if (code === 0) {
            sendMessage('🔴 Сервер остановлен');
        } else {
            sendMessage('❌ Ошибка при остановке сервера');
        }
    });
}

async function handlePlayersCommand(message) {
    \# Чтение последних строк лога для получения списка игроков
    const logContent = readLastLines(config.logFile, 100);
    const players = extractPlayersFromLog(logContent);
    
    const embed = new EmbedBuilder()
        .setTitle('Игроки на сервере')
        .setDescription(players.length > 0 ? players.join('\n') : 'Никого нет на сервере')
        .setColor(0x0099FF)
        .setTimestamp();
    
    await message.reply({ embeds: [embed] });
}

\# Вспомогательные функции
function getServerStatus() {
    const proc = spawn('systemctl', ['is-active', 'minecraft-bedrock']);
    return new Promise((resolve) => {
        let output = '';
        proc.stdout.on('data', (data) => {
            output += data.toString();
        });
        proc.on('close', () => {
            resolve(output.trim() === 'active');
        });
    });
}

function getServerInfo() {
    return new Promise((resolve) => {
        const proc = spawn('pgrep', ['bedrock_server']);
        proc.stdout.on('data', (data) => {
            const pid = data.toString().trim();
            if (pid) {
                const memProc = spawn('ps', ['-o', 'rss=', '-p', pid]);
                const cpuProc = spawn('ps', ['-o', '%cpu=', '-p', pid]);
                
                let memory = '';
                let cpu = '';
                
                memProc.stdout.on('data', (data) => {
                    memory = (parseInt(data.toString()) / 1024).toFixed(2);
                });
                
                cpuProc.stdout.on('data', (data) => {
                    cpu = data.toString().trim();
                });
                
                memProc.on('close', () => {
                    resolve({ memory, cpu });
                });
            } else {
                resolve(null);
            }
        });
        proc.on('close', () => {
            if (!proc.stdout.readableLength) resolve(null);
        });
    });
}

function sendMessage(content) {
    const channel = client.channels.cache.get(config.channelId);
    if (channel) {
        channel.send(content);
    }
}

function readLastLines(file, lines) {
    try {
        const content = fs.readFileSync(file, 'utf-8');
        const allLines = content.split('\n');
        return allLines.slice(-lines).join('\n');
    } catch (error) {
        return '';
    }
}

function extractPlayersFromLog(logContent) {
    const players = [];
    const lines = logContent.split('\n');
    \# Упрощенная логика - нужна доработка под конкретный формат логов
    lines.forEach(line => {
        if (line.includes('Player') && line.includes('connected')) {
            const match = line.match(/Player[^:]*:\s*(\w+)/);
            if (match) players.push(match[1]);
        }
    });
    return [...new Set(players)];
}

\# Запуск бота
client.login(config.token);

3. Создайте файл конфигурации:

sudo nano .env

4. Добавьте конфигурацию:

DISCORD_TOKEN=your_bot_token_here
DISCORD_CHANNEL_ID=your_channel_id_here

5. Мониторинг логов сервера

Скрипт мониторинга логов

1. Создайте скрипт:

sudo nano log-monitor.js

2. Добавьте содержимое:

const { Client, GatewayIntentBits } = require('discord.js');
const fs = require('fs');
const { spawn } = require('child_process');

const client = new Client({
    intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages]
});

const config = {
    token: process.env.DISCORD_TOKEN,
    channelId: process.env.DISCORD_CHANNEL_ID,
    logFile: '/opt/bedrock/logs/latest.log'
};

let lastPosition = 0;

client.once('ready', () => {
    console.log('Log monitor started');
    
    \# Чтение файла каждые 5 секунд
    setInterval(() => {
        monitorLogs();
    }, 5000);
});

function monitorLogs() {
    try {
        const stats = fs.statSync(config.logFile);
        if (stats.size < lastPosition) {
            lastPosition = 0; \# Файл был ротирован
        }
        
        const stream = fs.createReadStream(config.logFile, {
            start: lastPosition,
            encoding: 'utf-8'
        });
        
        let buffer = '';
        
        stream.on('data', (chunk) => {
            buffer += chunk;
            const lines = buffer.split('\n');
            buffer = lines.pop(); \# Последняя неполная строка
            
            lines.forEach(line => {
                processLogLine(line);
            });
        });
        
        lastPosition = stats.size;
    } catch (error) {
        console.error('Error reading log file:', error);
    }
}

function processLogLine(line) {
    const channel = client.channels.cache.get(config.channelId);
    if (!channel) return;
    
    \# Игрок подключился
    if (line.includes('Player') && line.includes('connected')) {
        const playerMatch = line.match(/Player[^:]*:\s*(\w+)/);
        if (playerMatch) {
            channel.send(`🟢 **${playerMatch[1]}** присоединился к серверу!`);
        }
    }
    
    \# Игрок отключился
    if (line.includes('Player') && line.includes('disconnected')) {
        const playerMatch = line.match(/Player[^:]*:\s*(\w+)/);
        if (playerMatch) {
            channel.send(`🔴 **${playerMatch[1]}** покинул сервер`);
        }
    }
    
    \# Ошибки сервера
    if (line.toLowerCase().includes('error') || line.toLowerCase().includes('exception')) {
        channel.send(`⚠️ **Ошибка сервера:** \`${line.substring(0, 200)}\``);
    }
    
    \# Сервер запустился
    if (line.includes('Server started')) {
        channel.send('🟢 **Сервер запущен!**');
    }
    
    \# Сервер остановился
    if (line.includes('Server stopped')) {
        channel.send('🔴 **Сервер остановлен**');
    }
}

client.login(config.token);

6. Настройка systemd сервиса для бота =

Создание сервиса

1. Создайте файл сервиса:

sudo nano /etc/systemd/system/bedrock-discord.service

2. Добавьте конфигурацию:

[Unit]
Description=Bedrock Discord Bot
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/opt/bedrock-discord
Environment=NODE_ENV=production
EnvironmentFile=/opt/bedrock-discord/.env
ExecStart=/usr/bin/node bot.js
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

3. Запустите сервис:

sudo systemctl daemon-reload
sudo systemctl enable bedrock-discord
sudo systemctl start bedrock-discord
sudo systemctl status bedrock-discord

7. Альтернатива на Python

Установка Python библиотек

1. Установите discord.py:

sudo apt install -y python3-pip
sudo pip3 install discord.py requests

2. Создайте простой бот:

sudo nano discord_bot.py

3. Добавьте базовый код:

import discord
import asyncio
import subprocess
import os

intents = discord.Intents.default()
intents.message_content = True

client = discord.Client(intents=intents)

@client.event
async def on_ready():
    print(f'Bot connected as {client.user}')

@client.event
async def on_message(message):
    if message.author == client.user:
        return
    
    if message.content.startswith('!status'):
        status = check_server_status()
        await message.channel.send(f'Server status: {status}')

def check_server_status():
    result = subprocess.run(
        ['systemctl', 'is-active', 'minecraft-bedrock'],
        capture_output=True,
        text=True
    )
    return 'active' if result.stdout.strip() == 'active' else 'inactive'

client.run(os.getenv('DISCORD_TOKEN'))

8. Настройка прав sudo =

Настройка sudo для бота

1. Создайте правило sudo:

sudo nano /etc/sudoers.d/bedrock-discord

2. Добавьте права (для Node.js бота, запущенного от root):

\# Если бот запущен от root, sudo не нужен
\# Если от другого пользователя:
\# bedrock-discord ALL=(ALL) NOPASSWD: /bin/systemctl start minecraft-bedrock
\# bedrock-discord ALL=(ALL) NOPASSWD: /bin/systemctl stop minecraft-bedrock
\# bedrock-discord ALL=(ALL) NOPASSWD: /bin/systemctl restart minecraft-bedrock

9. Примеры использования =

Базовые команды

1. `!status` - проверка статуса сервера 2. `!start` - запуск сервера (требует прав администратора) 3. `!stop` - остановка сервера (требует прав администратора) 4. `!players` - список игроков на сервере

10. Устранение неполадок =

Проблемы с подключением

1. Проверьте токен бота 2. Проверьте права бота на сервере Discord 3. Проверьте логи бота:

sudo journalctl -u bedrock-discord -f

Заключение

Настройка интеграции с Discord для Bedrock сервера позволяет получать уведомления о событиях сервера и управлять им прямо из Discord. Это удобный способ мониторинга и управления сервером.

Для размещения ваших Bedrock серверов с Discord интеграцией на надежном хостинге рекомендуем воспользоваться услугами [ARK-HOSTER.RU](https://ark-hoster.ru):

Наши специалисты помогут с настройкой Discord интеграции для Bedrock серверов!