Rehber - Discord Botunda Seviye / XP Sistemi Nasıl Yapılır? (SQLite + Rol Ödülü) | SroCave - SRO Destek Forumu

Rehber Discord Botunda Seviye / XP Sistemi Nasıl Yapılır? (SQLite + Rol Ödülü)

  • Konbuyu başlatan Konbuyu başlatan Jhaeger
  • Başlangıç tarihi Başlangıç tarihi
  • Cevaplar Cevaplar 0
  • Görüntüleme Görüntüleme 3

Jhaeger

King of the Underworld
Ayın En Aktif Üyesi
Katılım
9 Şub 2024
Mesajlar
946
Tepkime puanı
1,780
Puanları
93
jhaeger
Discord Botunda Seviye / XP Sistemi Yapımı
discord.py ve SQLite ile kalıcı seviye sistemi​



Selamlar SroCave Ailesi!

Sunucunuzda üyeleri aktif tutmanın en etkili yollarından biri seviye (XP) sistemidir. Üyeler mesaj yazdıkça XP kazanır, seviye atlar ve liderlik tablosunda yarışır. Bu rehberde sıfırdan, kalıcı kayıtlı bir seviye sistemi yapacağız.

Botumuzda şunlar olacak:
  • Mesaj yazdıkça rastgele XP kazanma (spam engelleyen bekleme süresiyle)
  • Otomatik seviye atlama mesajı
  • Belirli seviyelerde otomatik rol ödülü
  • /rank : Seviye kartı (ilerleme çubuğu ve sıralama)
  • /liderlik : Sunucunun ilk 10 kişisi
  • /xp-ekle ve /xp-sifirla : Yönetici komutları

📝 Not: Bu konu, SQLite temelini anlattığımız konunun devamı niteliğindedir. Veritabanı mantığını kaçırdıysanız önce şuna göz atın: Discord Botunda Veritabanı Kullanmak: Kalıcı Kayıt Sistemi



🧠 Sistem Nasıl Çalışır?​

  1. Üye bir mesaj yazar.
  2. Bot, üyenin son XP aldığı zamana bakar. 60 saniye geçmediyse hiçbir şey yapmaz (spam engeli).
  3. Süre geçtiyse üyeye 15 - 25 arası rastgele XP verilir.
  4. XP, o seviyenin gerektirdiği miktara ulaştıysa seviye atlanır ve kalan XP bir sonraki seviyeye devredilir.
  5. Her şey seviye.db dosyasına kaydedilir. Bot kapansa bile veriler kaybolmaz.

📐 Seviye Formülü
Bir seviyeden diğerine geçmek için gereken XP:
Kod:
gereken_xp = 5 * (seviye ** 2) + 50 * seviye + 100

  • Seviye 0 → 1: 100 XP
  • Seviye 1 → 2: 155 XP
  • Seviye 2 → 3: 220 XP
  • Seviye 3 → 4: 295 XP
  • Seviye 4 → 5: 380 XP
Seviye yükseldikçe gereken XP artar, böylece sistem zamanla zorlaşır. Rakamları kendi sunucunuza göre değiştirebilirsiniz.



⚙️ Gerekli Kurulum​

Bash:
pip install -U discord.py python-dotenv

📄 .env Dosyası
Kod:
TOKEN=BOT_TOKENINIZ

⚠️ Uyarı: .env ve seviye.db dosyalarını asla başkalarıyla paylaşmayın, GitHub'a yüklüyorsanız .gitignore içine ekleyin.

🔑 Botu Davet Ederken
  • Scope olarak bot ve applications.commands
  • Yetkiler: Send Messages, Embed Links ve rol ödülü kullanacaksanız Manage Roles
  • Rol ödülü için bot rolünün, vereceği rollerden daha yukarıda olması gerekir.



🤖 Tam Bot Kodu (bot.py)​


Python:
import os
import time
import random
import sqlite3
from typing import Optional

import discord
from discord import app_commands
from discord.ext import commands
from dotenv import load_dotenv

load_dotenv()

# ---------- Ayarlar ----------
MIN_XP = 15          # Mesaj başına en az XP
MAX_XP = 25          # Mesaj başına en fazla XP
COOLDOWN = 60        # XP kazanma bekleme süresi (saniye)

# Seviye ödülü rolleri: {seviye: rol_id}
# Örnek: LEVEL_ROLLERI = {5: 123456789012345678, 10: 234567890123456789}
LEVEL_ROLLERI = {}

# ---------- Bot ----------
intents = discord.Intents.default()
bot = commands.Bot(command_prefix=commands.when_mentioned, intents=intents)

# ---------- Veritabanı ----------
conn = sqlite3.connect("seviye.db")
c = conn.cursor()
c.execute("""
    CREATE TABLE IF NOT EXISTS levels (
        guild_id INTEGER,
        user_id  INTEGER,
        xp       INTEGER DEFAULT 0,
        level    INTEGER DEFAULT 0,
        PRIMARY KEY (guild_id, user_id)
    )
""")
conn.commit()

cooldown_listesi = {}


# ---------- Yardımcı Fonksiyonlar ----------
def gerekli_xp(level: int) -> int:
    """Bu seviyeden bir sonrakine geçmek için gereken XP."""
    return 5 * (level ** 2) + 50 * level + 100


def kayit_getir(guild_id: int, user_id: int):
    """(xp, level) döner. Kayıt yoksa None döner."""
    c.execute("SELECT xp, level FROM levels WHERE guild_id = ? AND user_id = ?", (guild_id, user_id))
    return c.fetchone()


def xp_ver(guild_id: int, user_id: int, miktar: int):
    """XP ekler, seviye atlamayı hesaplar. (xp, level, seviye_atladi_mi) döner."""
    xp, level = kayit_getir(guild_id, user_id) or (0, 0)
    eski_level = level
    xp += miktar

    while xp >= gerekli_xp(level):
        xp -= gerekli_xp(level)
        level += 1

    c.execute("""
        INSERT INTO levels (guild_id, user_id, xp, level) VALUES (?, ?, ?, ?)
        ON CONFLICT(guild_id, user_id) DO UPDATE SET xp = excluded.xp, level = excluded.level
    """, (guild_id, user_id, xp, level))
    conn.commit()
    return xp, level, level > eski_level


def siralama_bul(guild_id: int, xp: int, level: int) -> int:
    c.execute("""
        SELECT COUNT(*) FROM levels
        WHERE guild_id = ? AND (level > ? OR (level = ? AND xp > ?))
    """, (guild_id, level, level, xp))
    return c.fetchone()[0] + 1


def ilerleme_cubugu(xp: int, gerekli: int, uzunluk: int = 10) -> str:
    dolu = int((xp / gerekli) * uzunluk)
    return "█" * dolu + "░" * (uzunluk - dolu)


async def rol_odulleri_ver(uye: discord.Member, level: int):
    """Ulaşılan seviyeye kadar olan tüm rol ödüllerini verir."""
    for gereken_seviye, rol_id in LEVEL_ROLLERI.items():
        if level < gereken_seviye:
            continue
        rol = uye.guild.get_role(rol_id)
        if rol and rol not in uye.roles:
            try:
                await uye.add_roles(rol, reason=f"Seviye {gereken_seviye} ödülü")
            except discord.Forbidden:
                print(f"Rol verilemedi: {rol.name} (bot rolünü yukarı taşıyın)")


# ---------- Bot Olayları ----------
@bot.event
async def setup_hook():
    await bot.tree.sync()  # Slash komutları Discord'a kaydet


@bot.event
async def on_ready():
    print(f"Bot giriş yaptı: {bot.user}")


@bot.listen("on_message")
async def xp_kazan(message: discord.Message):
    if message.author.bot or message.guild is None:
        return

    anahtar = (message.guild.id, message.author.id)
    simdi = time.time()
    if simdi - cooldown_listesi.get(anahtar, 0) < COOLDOWN:
        return
    cooldown_listesi[anahtar] = simdi

    kazanilan = random.randint(MIN_XP, MAX_XP)
    xp, level, atladi = xp_ver(message.guild.id, message.author.id, kazanilan)

    if atladi:
        await message.channel.send(f"🎉 {message.author.mention} seviye atladı! Yeni seviye: **{level}**")
        await rol_odulleri_ver(message.author, level)


# ---------- Slash Komutları ----------
@bot.tree.command(name="rank", description="Seviye kartını gösterir")
@app_commands.describe(uye="Seviyesine bakılacak üye (boş bırakırsanız kendiniz)")
@app_commands.guild_only()
async def rank(interaction: discord.Interaction, uye: Optional[discord.Member] = None):
    uye = uye or interaction.user
    if uye.bot:
        return await interaction.response.send_message("🤖 Botların seviyesi yoktur.", ephemeral=True)

    kayit = kayit_getir(interaction.guild.id, uye.id)
    xp, level = kayit or (0, 0)
    gerekli = gerekli_xp(level)
    sira = f"#{siralama_bul(interaction.guild.id, xp, level)}" if kayit else "Henüz yok"

    embed = discord.Embed(title=f"📊 {uye.display_name} - Seviye Kartı", color=0x5865F2)
    embed.set_thumbnail(url=uye.display_avatar.url)
    embed.add_field(name="Seviye", value=f"**{level}**", inline=True)
    embed.add_field(name="Sıralama", value=f"**{sira}**", inline=True)
    embed.add_field(
        name="İlerleme",
        value=f"{ilerleme_cubugu(xp, gerekli)}\n{xp} / {gerekli} XP",
        inline=False,
    )
    await interaction.response.send_message(embed=embed)


@bot.tree.command(name="liderlik", description="Sunucunun ilk 10 kişisini gösterir")
@app_commands.guild_only()
async def liderlik(interaction: discord.Interaction):
    c.execute("""
        SELECT user_id, xp, level FROM levels
        WHERE guild_id = ?
        ORDER BY level DESC, xp DESC
        LIMIT 10
    """, (interaction.guild.id,))
    satirlar = c.fetchall()

    if not satirlar:
        return await interaction.response.send_message("Henüz kimse XP kazanmamış.", ephemeral=True)

    madalyalar = ["🥇", "🥈", "🥉"]
    metin = "\n".join(
        f"{madalyalar[i] if i < 3 else f'**{i + 1}.**'} <@{uid}> • Seviye **{lvl}** ({xp} XP)"
        for i, (uid, xp, lvl) in enumerate(satirlar)
    )

    embed = discord.Embed(title="🏆 Liderlik Tablosu", description=metin, color=0xFEE75C)
    await interaction.response.send_message(embed=embed)


@bot.tree.command(name="xp-ekle", description="Bir üyeye XP ekler (Yönetici)")
@app_commands.describe(uye="XP verilecek üye", miktar="Eklenecek XP miktarı")
@app_commands.default_permissions(administrator=True)
@app_commands.guild_only()
async def xp_ekle(interaction: discord.Interaction, uye: discord.Member, miktar: app_commands.Range[int, 1, 100000]):
    if uye.bot:
        return await interaction.response.send_message("🤖 Botlara XP verilemez.", ephemeral=True)

    xp, level, atladi = xp_ver(interaction.guild.id, uye.id, miktar)
    await rol_odulleri_ver(uye, level)

    ek = f"\n🎉 Seviye atladı! Yeni seviye: **{level}**" if atladi else ""
    await interaction.response.send_message(
        f"✅ {uye.mention} kullanıcısına **{miktar} XP** eklendi.{ek}",
        allowed_mentions=discord.AllowedMentions.none(),
    )


@bot.tree.command(name="xp-sifirla", description="Bir üyenin XP ve seviyesini sıfırlar (Yönetici)")
@app_commands.describe(uye="Sıfırlanacak üye")
@app_commands.default_permissions(administrator=True)
@app_commands.guild_only()
async def xp_sifirla(interaction: discord.Interaction, uye: discord.Member):
    c.execute("DELETE FROM levels WHERE guild_id = ? AND user_id = ?", (interaction.guild.id, uye.id))
    conn.commit()
    await interaction.response.send_message(
        f"🧹 {uye.mention} kullanıcısının XP ve seviyesi sıfırlandı.",
        allowed_mentions=discord.AllowedMentions.none(),
    )


bot.run(os.getenv("TOKEN"))

Botu başlatmak için:
Bash:
python bot.py



📖 Kod Açıklaması​

  • gerekli_xp(): Seviye formülünü içerir. Zorluğu değiştirmek için sadece bu fonksiyonu düzenlemeniz yeterli.
  • PRIMARY KEY (guild_id, user_id): Her sunucu için her üyeye ayrı satır açar. Bot birden fazla sunucudaysa veriler karışmaz.
  • ON CONFLICT ... DO UPDATE: Kayıt varsa günceller, yoksa yeni oluşturur. Önceki konudaki INSERT OR IGNORE mantığının daha pratik hali.
  • cooldown_listesi: Üyelerin son XP aldığı zamanı tutar. Bot yeniden başlayınca sıfırlanır, bunun zararı yoktur.
  • @bot.listen("on_message"): Botun kendi mesaj işleyicisini bozmadan mesajları dinler.
  • while xp >= gerekli_xp(level): Çok XP eklendiğinde birden fazla seviye atlamayı doğru hesaplar.
  • default_permissions(administrator=True): Yönetici komutlarını sadece yetkililere gösterir.
  • AllowedMentions.none(): Mesajda üyeyi etiketlemeden adını gösterir, gereksiz bildirim atmaz.

📝 Not: bot.tree.sync() komutları global olarak kaydeder, ilk seferde komutların görünmesi biraz zaman alabilir.



🎁 Rol Ödülü Nasıl Eklenir?​

  1. Discord'da Ayarlar > Gelişmiş > Geliştirici Modu'nu açın.
  2. Sunucu Ayarları > Roller bölümünde role sağ tıklayıp Rol ID'sini Kopyala deyin.
  3. Koddaki LEVEL_ROLLERI kısmını şöyle doldurun:

Python:
LEVEL_ROLLERI = {
    5:  123456789012345678,   # Seviye 5'te verilecek rol
    10: 234567890123456789,   # Seviye 10'da verilecek rol
    20: 345678901234567890,   # Seviye 20'de verilecek rol
}

⚠️ Çok Önemli: Botun rolü, vereceği rollerden daha yukarıda olmalıdır. Sunucu Ayarları > Roller bölümünden bot rolünü yukarı taşıyın. Aksi halde rol verilemez ve konsolda uyarı görürsünüz.



🧪 Örnek Kullanım​

Kod:
/rank
/rank uye:@Ahmet
/liderlik
/xp-ekle uye:@Ahmet miktar:500
/xp-sifirla uye:@Ahmet



🧯 Sık Karşılaşılan Hatalar​

  • Slash komutlar görünmüyor: Botu applications.commands scope'u ile davet etmemiş olabilirsiniz. Botu tekrar davet edin, Discord'u yenileyin (CTRL + R).
  • XP artmıyor: 60 saniyelik bekleme süresine takılmış olabilirsiniz. Test ederken COOLDOWN = 5 yapabilirsiniz. Botların mesajları da sayılmaz.
  • Rol verilmiyor: Botta Manage Roles yetkisi yoktur veya bot rolü, verilecek rolün altındadır.
  • ModuleNotFoundError: dotenv: pip install python-dotenv komutunu çalıştırın.
  • database is locked: Aynı seviye.db dosyasını aynı anda başka bir program veya ikinci bir bot kopyası kullanıyordur.

Hata çözümleri için ayrıntılı konumuz: Discord Bot Hataları ve Çözümleri



💡 Geliştirme Fikirleri​

  • Seviye atlama mesajını bir özel kanala göndermek
  • Belirli kanallarda (#komut gibi) XP kazanımını kapatmak
  • Rolü olanlara XP boost (2x XP) vermek
  • Ses kanalında geçirilen süreye göre XP vermek
  • Pillow ile görsel seviye kartı oluşturmak
  • Büyük sunucular için aiosqlite ile asenkron veritabanı kullanmak



🔗 Faydalı Kaynaklar​


🏁 Sonuç​

Artık mesaj yazdıkça XP kazandıran, seviye atlayan, rol ödülü veren ve liderlik tablosu bulunan, tamamen kalıcı bir seviye sisteminiz var. Formülü, XP miktarını ve rolleri kendi sunucunuza göre ayarlayarak ona kendi kimliğinizi verebilirsiniz.

⚠️ Not: Botunuzu geliştirirken kodlarınızı yedeklemeyi ve veritabanı dosyasını güvenli tutmayı unutmayın!

Sorularınızı aşağıya yazabilirsiniz, herkese kolay gelsin! 💜​
 
Etiketler Etiketler
#bot #botmaker #communitymanager #communityowner #discord #discordmanager #gifty #guardcommunity #jhaeger #mmoelite

Geri
Üst Alt