- 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
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-ekleve/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?
- Üye bir mesaj yazar.
- Bot, üyenin son XP aldığı zamana bakar. 60 saniye geçmediyse hiçbir şey yapmaz (spam engeli).
- Süre geçtiyse üyeye 15 - 25 arası rastgele XP verilir.
- XP, o seviyenin gerektirdiği miktara ulaştıysa seviye atlanır ve kalan XP bir sonraki seviyeye devredilir.
- Her şey
seviye.dbdosyasına kaydedilir. Bot kapansa bile veriler kaybolmaz.
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
Gerekli Kurulum
Bash:
pip install -U discord.py python-dotenv
Kod:
TOKEN=BOT_TOKENINIZ
Uyarı:
.envveseviye.dbdosyalarını asla başkalarıyla paylaşmayın, GitHub'a yüklüyorsanız.gitignoreiçine ekleyin.
- Scope olarak
botveapplications.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 IGNOREmantığı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?
- Discord'da Ayarlar > Gelişmiş > Geliştirici Modu'nu açın.
- Sunucu Ayarları > Roller bölümünde role sağ tıklayıp Rol ID'sini Kopyala deyin.
- Koddaki
LEVEL_ROLLERIkı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.commandsscope'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 = 5yapabilirsiniz. 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-dotenvkomutunu çalıştırın. - database is locked: Aynı
seviye.dbdosyası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 (
#komutgibi) 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
aiosqliteile 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!





