İçeriğe geç

Metin2 MySQL ile Sık Yapılan İşlemler: Eşya Verme, Ban, Seviye, GM

Hazırlayan: Metin2VIP Editörleri Yayın: 7 dk okuma

Kısaca: Sunucu açıkken eşya vermenin güvenli yolu player.item_award tablosudur: satır hesap adıyla eklenir, eşya oyuncu depoyu açınca yerleşir. Efsunlu eşya sunucu kapalıyken doğrudan item tablosuna yazılır. Ban için account tablosunda status 'BLOCK' ya da availDt ileri bir tarih yapılır, GM için common.gmlist'e satır eklenir. Karakter tablolarındaki her değişiklikten önce yedek alınır ve oyuncunun çıkıp db önbelleğinin boşalması beklenir; seviye SQL ile yükseltilecekse statü puanı, beceri puanı ve HP ayrıca eklenir.
İçindekiler
  1. Önce karakteri ve hesabı bul
  2. MySQL ile eşya verme
    1. Sunucu açıkken: item_award
    2. Sunucu kapalıyken: efsunlu eşyayı envantere yazmak
  3. Yang verme
  4. Metin2 ban atma ve kaldırma
  5. Seviye yükseltme
  6. GM yetkisi
  7. Sıkışan karakteri köye almak
  8. Uygunsuz karakter adını değiştirtmek
  9. Takılan bir görevi sıfırlamak
  10. Depo şifresini sıfırlamak
  11. İşlemden sonra

Metin2'de eşya vermek, ban atmak, seviye yükseltmek ya da GM eklemek MySQL'de tek satırlık sorgulardır; sonucu belirleyen, hangi tabloya ve ne zaman yazıldığıdır. Hesap tabloları (ban, GM listesi) her an düzenlenebilir. Karakter ve eşya tabloları ise oyuncu çevrim dışıyken ve db çekirdeğinin önbelleği boşken düzenlenir; sunucu açıkken eşya vermenin güvenli yolu item_award tablosudur.

Sorgular paketin SQL şemalarına ve db çekirdeğinin okuma-yazma kurallarına göre yazıldı; tabloları değiştirmemiş sunucularda aynen çalışır. Sütunların anlamı player tablosu, item tablosu ve account tablosu yazılarında; önbelleğin neden önemli olduğu Metin2'de MySQL nedir yazısında.

Önce karakteri ve hesabı bul

Sorguların çoğu karakter numarasını (player.id) ya da hesap adını (account.login) ister:

SELECT id, account_id, name, level, map_index FROM player.player
WHERE name = 'KarakterAdi';

SELECT p.id, p.name, p.level FROM player.player AS p
JOIN account.account AS a ON a.id = p.account_id
WHERE a.login = 'hesapadi';

Oyunun mt2 kullanıcısı beş veritabanının hepsinde okuma ve yazma yetkisine sahip olduğu için veritabanları arası JOIN bu kullanıcıyla da çalışır.

MySQL ile eşya verme

Sunucu açıkken: item_award

item_award'a eklenen satırı db 5 saniyede bir okur; bu yenilemeyi ENABLE_ITEMAWARD_REFRESH tanımı açar, tanım kapalıysa yeni satırlar db'ye ulaşmaz. Eşya, oyuncu depoyu (mall 0) ya da Nesne Marketi Deposu'nu (mall 1) açtığında ilk boş kutuya yerleşir; db satırın taken_time ve item_id sütunlarını doldurur. Aşağıdaki satır bir hesabın deposuna Hava Kılıcı öğreten bir Beceri Kitabı gönderir:

INSERT INTO player.item_award (login, vnum, count, given_time, why, mall, socket0)
VALUES ('hesapadi', 50300, 1, NOW(), 'destek', 0, 4);
  • login karakter adı değil hesap adıdır; db onu küçük harfe çevirerek eşleştirir.
  • why kısa bir not içindir; kimin hangi sebeple eşya aldığını sonradan görmeye yarar.
  • Beceri Kitabı'nda ve Unutkanlık Kitabı'nda socket0 boş bırakılırsa db rastgele bir beceri seçer. Süreli eşyalarda socket0 boşsa db süreyi kendisi başlatır.
  • item_award yalnız socket0-socket2 taşır, efsun taşımaz.
  • Depoda yer yoksa eşya bekler; Nesne Marketi Deposu'nda db yalnız ilk sayfanın 45 kutusunu kullanır.

Kaydın durumu şöyle izlenir; taken_time doluysa eşya teslim edilmiştir:

SELECT id, vnum, count, taken_time, item_id FROM player.item_award
WHERE login = 'hesapadi' ORDER BY id DESC LIMIT 5;

Etkinlik ödülü gibi toplu dağıtımlar da aynı tabloyla yapılır. Son 7 günde giriş yapmış, engelli olmayan bütün hesapların Nesne Marketi Deposu'na 50 Kırmızı İksir(K):

INSERT INTO player.item_award (login, vnum, count, given_time, why, mall)
SELECT login, 27001, 50, NOW(), 'etkinlik', 1 FROM account.account
WHERE status = 'OK' AND last_play > DATE_SUB(NOW(), INTERVAL 7 DAY);

Sunucu kapalıyken: efsunlu eşyayı envantere yazmak

Efsunlu bir eşya item_award ile verilemez; sunucu stop.py ile kapatıldıktan sonra doğrudan item tablosuna eklenir. Sunucu açıkken eklenen bir satırın kimliği bir oyun çekirdeğinin vereceği kimlikle çakışabileceği için bu adım sunucu kapalıyken yapılır. Önce envanterde dolu kutulara bakılır:

SELECT pos, vnum, count FROM player.item
WHERE owner_id = 1234 AND `window` = 'INVENTORY' ORDER BY pos;

Ardından satır eklenir. Aşağıdaki sorgu 1234 numaralı karakterin ilk kutusuna bir açık gümüş yuvalı, %10 yarı insan ve %10 kritik vuruş efsunlu bir Kılıç+9 koyar; Kılıç iki kutu kapladığı için 0 ve 5 numaralı kutular boş olmalıdır:

INSERT INTO player.item (owner_id, `window`, pos, count, vnum, socket0,
    attrtype0, attrvalue0, attrtype1, attrvalue1)
VALUES (1234, 'INVENTORY', 0, 1, 19, 1, 17, 10, 15, 10);

id boş bırakılır, MySQL kendisi verir; db açılırken kimlik bloklarını tablodaki en büyük kimliğe göre kurduğu için sunucu kapalıyken eklenen satır çakışmaz. window MySQL 8'de ayrılmış bir kelime olduğundan ters tırnak içinde yazılır. Efsun numaraları ve yuva değerleri item tablosu yazısında.

Yang verme

UPDATE player.player SET gold = LEAST(gold + 1000000, 1999999999)
WHERE id = 1234 LIMIT 1;

LEAST Yang'ın oyunun sınırını aşmasını engeller; 2.000.000.000'a ulaşan bir karakter artık Yang kazanamaz. Oyuncu oyundaysa SQL yerine IMPLEMENTOR yetkili bir GM, oyuncuyla aynı çekirdekteyken /set KarakterAdi gold 1000000 yazar; komut değeri eskisinin üstüne ekler, eksi değer düşer.

Metin2 ban atma ve kaldırma

-- kalıcı engel
UPDATE account.account SET status = 'BLOCK' WHERE login = 'hesapadi' LIMIT 1;

-- 7 günlük kapatma
UPDATE account.account SET availDt = DATE_ADD(NOW(), INTERVAL 7 DAY)
WHERE login = 'hesapadi' LIMIT 1;

-- karakter adından hesabı bulup engellemek
UPDATE account.account AS a
JOIN player.player AS p ON p.account_id = a.id
SET a.status = 'BLOCK'
WHERE p.name = 'KarakterAdi';

-- engeli ve süreli kapatmayı kaldırmak
UPDATE account.account SET status = 'OK', availDt = NOW()
WHERE login = 'hesapadi' LIMIT 1;

Ban hesaba işler ve girişte denetlenir; oyundaki oyuncuyu düşürmek için aynı çekirdekteki bir GM /dc KarakterAdi yazar. Birden çok tabloyu birleştiren UPDATE'te MySQL LIMIT kabul etmez, bu yüzden üçüncü sorgudan önce aynı JOIN ile SELECT çalıştırıp tek satır döndüğünü görmek gerekir. Sütunların ayrıntısı ve sohbet yasağı gibi diğer yollar account tablosu yazısında.

Seviye yükseltme

Sağlıklı yol oyuncu oyundayken tecrübe vermektir: IMPLEMENTOR yetkili bir GM, oyuncuyla aynı çekirdekteyken /set KarakterAdi exp 50000000 yazar. Oyun seviye atlamalarını kendisi yapar; statü ve beceri puanları ile rastgele HP artışı her seviyede normal yoldan gelir, seviye CONFIG'deki MAX_LEVEL'ı geçmez. Gereken tecrübe EXP tablosu sayfasından toplanır. Komutların ayrıntısı GM komutları rehberi yazısında.

SQL ile yükseltmek gerekiyorsa seviye atlamanın verdiği her şey elle eklenir. Her seviye 3 statü puanı (o seviye STATUS_POINT_GET_LEVEL_LIMIT'i aşmadıkça), beceri yolu seçilmiş karakterde 5. seviyeden sonraki her seviye 1 beceri puanı ve varsayılan sınıf tablosunda ortalama 40 HP ile 20 SP verir. Bulunulan seviyenin geçilmiş çeyreklerinin puanı (level_step) zaten alınmış olduğu için düşülür:

UPDATE player.player
SET stat_point = stat_point + 3 * (90 - level) - level_step,
    skill_point = skill_point + IF(skill_group > 0, 90 - GREATEST(level, 5), 0),
    random_hp = random_hp + 40 * (90 - level),
    random_sp = random_sp + 20 * (90 - level),
    exp = 0,
    level_step = 0,
    level = 90
WHERE id = 1234 AND level < 90 LIMIT 1;

level bilerek en sona yazılır: MySQL tek tablolu UPDATE'te atamaları soldan sağa yapar ve sonraki ifadeler önceki atamanın yeni değerini görür. level = 90 başa yazılsaydı bütün 90 - level ifadeleri sıfır olurdu. sub_skill_point eklenmez, karakter girerken yeniden hesaplanır.

GM yetkisi

GM eklemenin bütün adımları GM yapma yazısında. Var olan GM'leri görmek ve bir GM'in seviyesini değiştirmek:

SELECT mID, mAccount, mName, mServerIP, mAuthority FROM common.gmlist;

UPDATE common.gmlist SET mAuthority = 'HIGH_WIZARD'
WHERE mName = 'KarakterAdi' LIMIT 1;

Değişiklik sunucu yeniden başlatılınca ya da IMPLEMENTOR bir GM oyunda /reload a yazınca geçerli olur.

Sıkışan karakteri köye almak

Karakter bir yere sıkıştıysa ya da hatalı bir koordinatta kaldıysa konumu krallığının başlangıç köyüne çekilir. Altı konum sütunu birlikte değişir; aşağıdaki değerler Shinsoo'nun köyü Yongan Bölgesi içindir, Chunjo için 21, 55700, 157900, Jinno için 41, 969600, 278400 yazılır:

UPDATE player.player
SET map_index = 1, x = 469300, y = 964200,
    exit_map_index = 1, exit_x = 469300, exit_y = 964200
WHERE id = 1234 LIMIT 1;

Karakterin krallığı player_index.empire sütunundadır (1 Shinsoo, 2 Chunjo, 3 Jinno).

Uygunsuz karakter adını değiştirtmek

UPDATE player.player SET change_name = 1 WHERE id = 1234 LIMIT 1;

Oyuncu bu karakterle girmeden önce karakter seçim ekranında yeni bir ad seçmek zorunda kalır. Oyun yeni adı kendi kurallarıyla ve başka bir karakterde kullanılıp kullanılmadığına bakarak denetler; adı doğrudan name sütununa yazmak bu denetimleri atlar.

Takılan bir görevi sıfırlamak

Quest bayrakları player.quest tablosunda quest adı (szName) ve bayrak adı (szState) olarak tutulur; questin bulunduğu aşama __status adlı bayraktır. Bir questin bütün bayraklarını silmek onu baştan başlatır. Oyuncu çevrim dışıyken:

SELECT szName, szState, lValue FROM player.quest
WHERE dwPID = 1234 AND szName = 'gorev_adi';

DELETE FROM player.quest WHERE dwPID = 1234 AND szName = 'gorev_adi';

Depo şifresini sıfırlamak

Hesap sahibi olduğu doğrulanan oyuncu depo şifresini unuttuysa şifre boşaltılır; boş şifreyle depo başlangıç şifresi olan 000000 ile açılır:

UPDATE player.safebox SET password = ''
WHERE account_id = (SELECT id FROM account.account WHERE login = 'hesapadi') LIMIT 1;

Depo şifresi her depo açılışında MySQL'den okunduğu için bu işlem sunucu açıkken de yapılabilir.

İşlemden sonra

Aynı SELECT'i yeniden çalıştırıp sonucu gör. SQL ile yapılan değişiklikler oyunun günlüklerine düşmez; kimin, ne zaman, hangi sebeple eşya ya da ban aldığını kendi kaydında tut. Oyun içinde olanların izini sürmek için log veritabanı yazısına, düzenli yedek için server yedekleme yazısına bak.

Sık sorulan sorular

Metin2'de MySQL ile item nasıl verilir?
Sunucu açıkken player.item_award tablosuna hesap adı, vnum, adet, given_time ve mall değeriyle bir satır eklenir; db yeni satırları 5 saniyede bir okur ve eşya oyuncu depoyu ya da Nesne Marketi Deposu'nu açınca ilk boş kutuya yerleşir. Efsunlu bir eşya ise sunucu kapalıyken doğrudan player.item tablosuna eklenir.
item_award ile verdiğim eşya gelmedi, neden?
login sütununa karakter adı değil hesap adı yazılmalıdır. mall 0 ise eşya normal depoya, 1 ise Nesne Marketi Deposu'na gelir ve oyuncunun o depoyu açması gerekir. Depoda yer yoksa ya da vnum item_proto'da yoksa eşya yerleşmez; taken_time boş kaldıkça kayıt beklemededir.
Seviyeyi MySQL'den yükselttim, karakterin HP'si neden düşük?
Azami HP'nin bir kısmı her seviye atlamada eklenen rastgele artışlardan gelir ve random_hp sütununda birikir. level sütununu değiştirmek bu artışı vermez; seviye başına ortalama 40 HP random_hp'ye, 20 SP random_sp'ye eklenmelidir. Statü ve beceri puanları da ayrıca eklenir.
Ban attım ama oyuncu hâlâ oyunda, neden?
status ve availDt yalnız girişte denetlenir; oyundaki oyuncuyu düşürmez. Oyuncunun bağlantısı aynı çekirdekteki bir GM tarafından /dc KarakterAdi ile kesilir; ban bir sonraki giriş denemesinde geçerli olur.

İlgili sayfalar

Kategori: Server Kurma Server Kurulumu mysql gm sunucu yönetimi ban sql eşya verme

Bu sayfadaki bilgiler Metin2'nin sunucu yazılımındaki hesaplamalara ve standart oyun dosyalarına dayanır. Oyun dosyalarını değiştiren sunucularda değerler farklı olabilir. İçerikleri nasıl hazırlıyoruz?

Bu sayfa işine yaradı mı?

Giriş yap, oy ver ya da sayfayı kaydet. Okumak için üyelik gerekmez. WhatsApp X'te paylaş
Yanlış ya da eksik bir bilgi mi gördün? Bildir
Neyin yanlış olduğunu, doğrusunun ne olduğunu ve bunu nereden bildiğini yaz. Mesajın editörlere gider; yazı, kontrol edildikten sonra düzeltilir.
Yalnız editör görür.

Tartışma

Kurallar

Henüz yorum yok. Bu konuda bir deneyimin ya da sorun varsa ilk yorumu sen yaz.

Giriş yap ya da kayıt ol, sonra yorum yaz. Metin2VIP üyeliği hiçbir oyun sunucusunun hesabı değildir.