aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Metin2

Een Metin2 database-site bouwen (item & mob proto)

Een Metin2 database-site verandert de item- en monsterdata van het spel in een web-wiki die bezoekers kunnen doorzoeken en filteren. Spelers kunnen vragen beantwoorden als "waar dropt dit item?", "welk level is deze mob?" of "welke bonussen geeft dit kostuum?" zonder in te loggen. In deze gids loop ik stap voor stap door hoe je item_proto- en mob_proto-data neemt, in een schone web-database importeert en er een snelle, doorzoekbare database-site van bouwt.

De databronnen begrijpen: proto-bestanden

In Metin2 wordt elk item en monster dat het spel kent in twee hoofdstructuren gedefinieerd: item_proto en mob_proto. Op de meeste servers bestaan deze zowel als binaire item_proto/mob_proto-bestanden als platte-tekstbronnen:

  • item_proto / item_names.txt — de vnum van elk item, het type (wapen, harnas, kostuum, drank…), subtype, de value0–5-velden, bonussen (applies), prijs en namen.
  • mob_proto / mob_names.txt — de vnum van elk monster, het level, de rank (pawn/boss/king…), HP/aanvalswaarden, ervaring en namen.
  • item_names.txt en mob_names.txt — de mapping vnum → gelokaliseerde naam. Voor een meertalige wiki zijn deze bestanden cruciaal.

De schoonste weg voor een website is deze data importeren in een aparte wiki-database zonder de live player-tabellen aan te raken. Zo kun je elk schema bouwen dat je wilt zonder ooit de gameserver te belasten.

De data in een web-database importeren

Veel servers houden proto-data ook in MySQL bij (bijvoorbeeld een player.item_proto-tabel). Heb je alleen platte-tekstbestanden, dan is de gezondste aanpak een klein importscript dat ze één keer parseert en naar je eigen wiki-tabellen schrijft. Laten we beginnen met een eenvoudig schema:

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;

Bonusvelden (apply-types en waarden) opslaan in een aparte wiki_item_attrs-tabel als rijen gekoppeld via vnum maakt latere zoekopdrachten als "alle items met aanvalskracht +X" mogelijk.

De tab-gescheiden proto parseren

Bestanden als item_names.txt bestaan meestal uit tab-gescheiden kolommen met een kopregel. Een veilige import in PHP ziet er zo uit:

<?php
$fh = fopen('item_names.txt', 'r');
fgets($fh); // sla de kopregel over

$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);

Je kunt type- en bonusinformatie uit item_proto lezen en dezelfde rij bijwerken. Met ON DUPLICATE KEY UPDATE kun je de import na een game-update opnieuw draaien om de data te verversen zonder ze telkens te wissen.

De zoek- en filter-API

Het hart van een Metin2 database-site is zoeken. Laten we een endpoint bouwen dat overeenkomende items en mobs teruggeeft wanneer de gebruiker een deel van een naam typt. Plaats gebruikersinvoer nooit direct in de query; bind het als parameter met een prepared statement:

<?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());

Bij zeer grote item-sets kan name LIKE '%...%' traag worden. Naarmate de site groeit, overweeg een MySQL FULLTEXT-index of een zoekmachine (zoals Meilisearch); maar voor een paar duizend rijen is een geïndexeerde LIKE ruim voldoende.

De drop-relatie opbouwen: "waar dropt het?"

De informatie waar spelers het meest naar zoeken, is welk monster een item dropt. Drop-data staat op de server in bronnen als mob_drop_item.txt, common_drop_item.txt en drop_item_group. Importeer je deze relatie in een tabel die de mob-vnum aan de item-vnum koppelt, dan ontgrendel je tweerichtingsqueries:

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;

Nu kan een itempagina "monsters die dit item droppen" tonen en een mob-pagina "de drop-tabel van dit monster" met een JOIN. Onthoud bij het tonen van de drop-kans dat het ruwe waarschijnlijkheidsformaat in de bestanden per servertype kan verschillen; weet je het niet zeker, presenteer de kans dan niet als exact — label het als "bij benadering".

De interface: tooltips en iconen

Hoe accuraat de data ook is, niemand gebruikt het als de presentatie slecht is. Een goede itempagina bootst de in-game tooltip na: naam, type, levelvereiste, bonuslijst en prijs. Voor iconen kun je de item-iconen uit de gameclient als PNG exporteren en koppelen via vnum. Een paar praktische tips:

  • Escape elke string uit de database met htmlspecialchars() vóór het printen — namen met speciale tekens kunnen XSS veroorzaken.
  • Zet bonussen om in leesbare labels (bijv. apply type 1 → "Max HP"). Houd deze mapping in een klein woordenboekbestand.
  • Plaats tabellen op mobiel in een horizontaal scrollbare container om overflow te voorkomen.

Prestaties, caching en SEO

Database-sites zijn leeszwaar: de data verandert zelden maar wordt veel gelezen. Deze structuur is ideaal voor caching. Elke item- en mob-pagina moet een permanente URL hebben (bijv. /item/27003) en je zou resultaten een paar minuten moeten cachen. Voor SEO verhoogt het geven van een beschrijvende <title>, een meta-beschrijving en idealiter JSON-LD-data aan elke pagina de zichtbaarheid bij "Metin2 [itemnaam]"-zoekopdrachten. Een sitemap.xml genereren met alle item- en mob-URL's versnelt ook het verschijnen in zoekresultaten.

Veelgestelde vragen

Beïnvloedt de wiki-site de gameserver?

Niet als hij goed is opgezet. Importeer je de proto-data in een aparte wiki-database en laat je de site alleen uit die tabellen lezen, dan raak je de live game-database nooit aan.

Ik heb geen platte-tekst proto-bestanden, alleen binair. Wat nu?

De meeste servers houden ook een item_proto/mob_proto-tabel in MySQL bij waar je uit kunt lezen. Anders heb je community-tools (proto unpackers) nodig die de proto-bestanden naar een tekstversie omzetten.

De namen verschijnen met kapotte tekens, waarom?

Meestal is het een charset-mismatch. Maak de tabellen aan met utf8mb4, converteer de echte codering van het bestand (veel proto's gebruiken een Latin/Windows-codering) tijdens de import naar UTF-8, en voeg <meta charset="utf-8"> aan de pagina toe.

Wil je een professionele database/wiki-site voor je server? Ik kan je proto-data veilig importeren en een snelle, doorzoekbare, meertalige wiki bouwen. Om je project te bespreken, neem contact met me op.

Bu kategorideki tüm yazılar →

Devamı için