Discord.js v14 Slash Commands: Sıfırdan Profesyonel Bot Komutları Yazma Rehberi

Discord.js v14 Slash Commands: Sıfırdan Profesyonel Bot Komutları Yazma Rehberi

Discord.js v14 ile Slash Commands'a Giriş

Discord'un eski prefix tabanlı komut sistemi (örneğin !yardım) artık resmi olarak desteklenmiyor. 2022'den itibaren Discord, tüm botların Slash Commands (/komut) mimarisine geçmesini zorunlu kıldı. Discord.js v14 bu yeni sistemi mükemmel destekliyor. Bu rehberde sıfırdan çok dosyalı, profesyonel bir Slash Command altyapısı kuracağız.

Proje Kurulumu ve Klasör Yapısı

Öncelikle gerekli paketleri yükleyelim ve dosya yapısını oluşturalım:

npm init -y
npm install discord.js @discordjs/rest discord-api-types dotenv

# Klasör yapısı:
# src/
# ├── commands/
# │   ├── genel/
# │   │   ├── ping.js
# │   │   └── yardim.js
# │   └── moderasyon/
# │       └── ban.js
# ├── events/
# │   ├── ready.js
# │   └── interactionCreate.js
# └── index.js

Ana Bot Dosyası (index.js)

const { Client, GatewayIntentBits, Collection } = require('discord.js');
const fs = require('fs');
const path = require('path');
require('dotenv').config();

// Bot istemcisini oluştur
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.GuildMembers,
  ],
});

// Komutları bir Collection'a yükle
client.commands = new Collection();

const commandsPath = path.join(__dirname, 'commands');
const commandFolders = fs.readdirSync(commandsPath);

for (const folder of commandFolders) {
  const folderPath = path.join(commandsPath, folder);
  const commandFiles = fs.readdirSync(folderPath).filter(f => f.endsWith('.js'));

  for (const file of commandFiles) {
    const command = require(path.join(folderPath, file));
    if ('data' in command && 'execute' in command) {
      client.commands.set(command.data.name, command);
      console.log(`✅ Komut yüklendi: /${command.data.name}`);
    }
  }
}

// Event dosyalarını yükle
const eventsPath = path.join(__dirname, 'events');
const eventFiles = fs.readdirSync(eventsPath).filter(f => f.endsWith('.js'));

for (const file of eventFiles) {
  const event = require(path.join(eventsPath, file));
  if (event.once) {
    client.once(event.name, (...args) => event.execute(...args, client));
  } else {
    client.on(event.name, (...args) => event.execute(...args, client));
  }
}

client.login(process.env.TOKEN);

Örnek Komut: /ping (commands/genel/ping.js)

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('ping')
    .setDescription('Botun gecikme süresini gösterir.'),

  async execute(interaction) {
    // Önce "düşünüyor" mesajı gönder (3 saniye limitini aşmamak için)
    await interaction.deferReply();

    const sent = await interaction.fetchReply();
    const latency = sent.createdTimestamp - interaction.createdTimestamp;
    const apiLatency = Math.round(interaction.client.ws.ping);

    const embed = new EmbedBuilder()
      .setColor(latency < 100 ? '#00ff00' : latency < 200 ? '#ffff00' : '#ff0000')
      .setTitle('🏓 Pong!')
      .addFields(
        { name: '📡 Bot Gecikmesi', value: `${latency}ms`, inline: true },
        { name: '💙 API Gecikmesi', value: `${apiLatency}ms`, inline: true },
      )
      .setTimestamp()
      .setFooter({ text: 'CodeMareFi Bot' });

    await interaction.editReply({ embeds: [embed] });
  },
};

Komut Kaydetme Script'i (deploy-commands.js)

Slash komutlarını Discord API'sine kaydetmeden önce bu script'i bir kere çalıştırmanız gerekiyor:

const { REST, Routes } = require('discord.js');
const fs = require('fs');
const path = require('path');
require('dotenv').config();

const commands = [];
const commandsPath = path.join(__dirname, 'src', 'commands');
const commandFolders = fs.readdirSync(commandsPath);

for (const folder of commandFolders) {
  const folderPath = path.join(commandsPath, folder);
  const commandFiles = fs.readdirSync(folderPath).filter(f => f.endsWith('.js'));
  for (const file of commandFiles) {
    const command = require(path.join(folderPath, file));
    commands.push(command.data.toJSON());
  }
}

const rest = new REST({ version: '10' }).setToken(process.env.TOKEN);

(async () => {
  try {
    console.log(`${commands.length} uygulama komutu yenileniyor...`);

    // Guild (sunucu) bazlı kayıt — anlık güncelleme için idealdir
    const data = await rest.put(
      Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID),
      { body: commands },
    );

    console.log(`✅ ${data.length} uygulama komutu başarıyla yüklendi!`);
  } catch (error) {
    console.error(error);
  }
})();

interactionCreate Event'i (events/interactionCreate.js)

module.exports = {
  name: 'interactionCreate',
  async execute(interaction, client) {
    // Slash command değilse işleme
    if (!interaction.isChatInputCommand()) return;

    const command = client.commands.get(interaction.commandName);

    if (!command) {
      console.error(`${interaction.commandName} adında komut bulunamadı!`);
      return;
    }

    try {
      await command.execute(interaction);
    } catch (error) {
      console.error(`❌ /${interaction.commandName} komutunda hata:`, error);

      const errorMessage = {
        content: '⚠️ Bu komutu çalıştırırken bir hata oluştu!',
        ephemeral: true, // Sadece komutu kullanan kişi görsün
      };

      if (interaction.replied || interaction.deferred) {
        await interaction.followUp(errorMessage);
      } else {
        await interaction.reply(errorMessage);
      }
    }
  },
};
🤖 İpucu: Global vs Guild Komutları

Guild (sunucu) komutları anında aktif olur, test için idealdir. Global komutlar ise Discord'a yayılması ~1 saat sürer ama tüm sunucularda çalışır. Production'a geçmeden önce mutlaka global komutlara geçin: Routes.applicationCommands(CLIENT_ID)

0 Yorum

YORUM YAPMAK İÇİN SİSTEME SIZMANIZ GEREKİYOR

Lütfen yukarıdaki butonu kullanarak giriş yapın veya kimlik oluşturun.

Yorumlar yükleniyor...