Bir Metin2 database sitesi, oyundaki item ve canavar verisini ziyaretçilerin arayıp filtreleyebileceği bir web wiki'sine dönüştürür. Oyuncular "bu eşya nereden düşüyor?", "hangi mob kaç level?" ya da "bu kostümün bonusları ne?" gibi soruların cevabını oyuna girmeden bulabilir. Bu yazıda item_proto ve mob_proto verisini alıp temiz bir web veritabanına aktararak aranabilir, performanslı bir database sitesi kurmayı adım adım anlatıyorum.
Veri kaynaklarını anlamak: proto dosyaları
Metin2'de oyunun bildiği her item ve canavar iki ana yapıda tanımlıdır: item_proto ve mob_proto. Çoğu serverde bunlar hem ikili (binary) item_proto/mob_proto dosyaları hem de düz metin kaynakları olarak bulunur:
item_proto/item_names.txt— her eşyanınvnum'u, tipi (silah, zırh, kostüm, iksir…), alt tipi,value0–5alanları, bonusları (apply'lar), fiyatı ve isimleri.mob_proto/mob_names.txt— her canavarınvnum'u, seviyesi, rank'ı (pawn/boss/king…), can/saldırı değerleri, deneyimi ve isimleri.item_names.txtvemob_names.txt— vnum → yerelleştirilmiş isim eşlemesi. Çok dilli bir wiki için bu dosyalar kritiktir.
Web sitesi için en temiz yol, bu veriyi player veritabanındaki canlı tablolara dokunmadan ayrı bir wiki veritabanına aktarmaktır. Böylece oyun sunucusunu hiç yormadan, istediğin şemayı kurabilirsin.
Veriyi web veritabanına aktarmak
Pek çok server, proto verisini MySQL'de de tutar (örneğin player.item_proto tablosu). Eğer sende düz metin dosyaları varsa, bunları bir kez ayrıştırıp (parse) kendi wiki tablolarına yazan küçük bir import betiği yazmak en sağlıklısıdır. Önce sade bir şema kuralım:
CREATE TABLE wiki_items (
vnum INT UNSIGNED PRIMARY KEY,
name VARCHAR(64) NOT NULL,
type VARCHAR(32) NOT NULL,
subtype VARCHAR(32) NULL,
level SMALLINT UNSIGNED DEFAULT 0,
price INT UNSIGNED DEFAULT 0,
KEY idx_name (name),
KEY idx_type (type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE wiki_mobs (
vnum INT UNSIGNED PRIMARY KEY,
name VARCHAR(64) NOT NULL,
level SMALLINT UNSIGNED DEFAULT 0,
rank VARCHAR(16) NULL,
exp INT UNSIGNED DEFAULT 0,
KEY idx_name (name),
KEY idx_level (level)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Bonus alanlarını (apply tipleri ve değerleri) ayrı bir wiki_item_attrs tablosunda vnum'a bağlı satırlar olarak tutmak, ileride "saldırı gücü +X olan tüm eşyalar" gibi aramaları mümkün kılar.
Tab ile ayrılmış proto'yu ayrıştırmak
item_names.txt gibi dosyalar genellikle TAB ile ayrılmış sütunlardan oluşur ve ilk satır başlıktır. PHP ile güvenli bir import şöyle görünür:
<?php
$fh = fopen('item_names.txt', 'r');
fgets($fh); // başlık satırını atla
$stmt = $pdo->prepare(
"INSERT INTO wiki_items (vnum, name, type)
VALUES (:vnum, :name, :type)
ON DUPLICATE KEY UPDATE name = VALUES(name)"
);
while (($line = fgets($fh)) !== false) {
$cols = explode("\t", trim($line));
if (count($cols) < 2) continue;
$stmt->execute([
':vnum' => (int) $cols[0],
':name' => $cols[1],
':type' => 'unknown',
]);
}
fclose($fh);
Tip ve bonus bilgisini item_proto'dan okuyup aynı satırı güncelleyebilirsin. Import'u oyun güncellemesinde tekrar çalıştırmak için ON DUPLICATE KEY UPDATE kullanmak, veriyi her seferinde sıfırlamadan tazelemeni sağlar.
Arama ve filtreleme API'si
Bir Metin2 database sitesinin kalbi aramadır. Kullanıcı bir isim parçası yazınca eşleşen item ve mob'ları döndüren bir endpoint kuralım. Kullanıcı girdisini asla doğrudan sorguya gömme; hazır ifade (prepared statement) ile parametre olarak bağla:
<?php
$q = trim($_GET['q'] ?? '');
$type = $_GET['type'] ?? null;
$sql = "SELECT vnum, name, type, level FROM wiki_items WHERE name LIKE :q";
$params = [':q' => '%' . $q . '%'];
if ($type) {
$sql .= " AND type = :type";
$params[':type'] = $type;
}
$sql .= " ORDER BY level DESC, name ASC LIMIT 50";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($stmt->fetchAll());
Çok sayıda eşya için name LIKE '%...%' yavaşlayabilir. Site büyüdüğünde MySQL FULLTEXT indeksine veya bir arama motoruna (Meilisearch gibi) geçmeyi düşün; ama birkaç bin satır için indeksli LIKE fazlasıyla yeterlidir.
Drop ilişkisini kurmak: "nereden düşer?"
Oyuncuların en çok aradığı bilgi, bir eşyanın hangi canavardan düştüğüdür. Drop verisi server'da mob_drop_item.txt, common_drop_item.txt ve drop_item_group gibi kaynaklarda tutulur. Bu ilişkiyi mob vnum ile item vnum'u bağlayan bir tabloya aktarırsan, iki yönlü sorgu açılır:
CREATE TABLE wiki_drops (
mob_vnum INT UNSIGNED NOT NULL,
item_vnum INT UNSIGNED NOT NULL,
chance DECIMAL(8,4) NULL,
PRIMARY KEY (mob_vnum, item_vnum),
KEY idx_item (item_vnum)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Artık bir item sayfasında "bu eşyayı düşüren canavarlar"ı, bir mob sayfasında ise "bu canavarın drop listesi"ni JOIN ile listeleyebilirsin. Drop şansını gösterirken, dosyalardaki ham olasılık formatının server tipine göre farklılaşabileceğini unutma; bilmiyorsan oranı kesin gibi sunma, "yaklaşık" olarak belirt.
Arayüz: tooltip ve ikonlar
Veri ne kadar doğru olsa da sunum kötüyse kimse kullanmaz. İyi bir item sayfası, oyundaki tooltip'i taklit eder: isim, tip, level şartı, bonus listesi ve fiyat. İkonlar için oyun istemcisindeki item ikonlarını PNG olarak dışa aktarıp vnum ile eşleştirebilirsin. Birkaç pratik öneri:
- Veritabanından gelen her metni ekrana basarken
htmlspecialchars()ile kaçışla — özel karakterli isimler XSS'e yol açabilir. - Bonusları okunur etiketlere çevir (örn. apply tipi 1 → "Maksimum Can"). Bu eşlemeyi küçük bir sözlük dosyasında tut.
- Mobil için tabloları yatay kaydırılabilir bir kapsayıcıya al; taşmayı önler.
Performans, önbellek ve SEO
Database siteleri okuma-ağırlıklıdır: veri nadiren değişir, ama çok okunur. Bu yapı önbelleklemeye çok uygundur. Her item ve mob sayfası kalıcı bir URL'ye sahip olmalı (örn. /item/27003) ve sonuçları birkaç dakika önbellekte tutmalısın. SEO açısından her sayfaya açıklayıcı bir <title>, meta açıklama ve mümkünse JSON-LD verisi eklemek, "Metin2 [eşya adı]" aramalarında görünürlüğünü artırır. Tüm item ve mob URL'lerini içeren bir sitemap.xml üretmek de aramaya çıkmanı hızlandırır.
Sık Sorulan Sorular
Wiki sitesi oyun sunucusunu etkiler mi?
Doğru kurulduğunda hayır. Proto verisini ayrı bir wiki veritabanına aktarıp, siteyi sadece o tablolardan okutursan canlı oyun veritabanına hiç dokunmazsın.
Düz metin proto dosyam yok, sadece binary var. Ne yapmalıyım?
Çoğu server, MySQL'de bir item_proto/mob_proto tablosu da tutar; oradan okuyabilirsin. Yoksa proto dosyalarını metne dönüştüren topluluk araçları (proto unpacker'lar) ile düz metin sürümünü çıkarman gerekir.
İsimler bozuk karakterlerle görünüyor, neden?
Genellikle karakter seti uyuşmazlığıdır. Tabloları utf8mb4 ile oluştur, import'ta dosyanın gerçek kodlamasını (çoğu proto için Latin/Windows kodlaması olabilir) UTF-8'e dönüştür ve sayfaya <meta charset="utf-8"> ekle.
Sunucun için profesyonel bir database/wiki sitesi mi istiyorsun? Proto verini güvenle aktarıp aranabilir, hızlı ve çok dilli bir wiki kurabilirim. Projeni konuşmak için benimle iletişime geç.