Einen soliden Metin2-Patcher bauen gehört zu den wichtigsten Infrastrukturaufgaben, wenn du deinen eigenen Server betreibst: Statt den Client von Hand herunterzuladen und Dateien zu kopieren, erwarten Spieler, dass der Launcher, den sie öffnen, Updates leise erledigt. Ein gut entworfener Launcher vergleicht die Version auf dem Server mit der auf der Festplatte des Spielers, lädt nur die geänderten Dateien herunter und startet das Spiel mit den richtigen Parametern. In dieser Anleitung bauen wir eine einfache, aber robuste Architektur für automatische Updates von Anfang bis Ende.
Wie ein Launcher funktioniert: die Architektur in Kürze
Die Patcher-Logik ist im Grunde nur ein Synchronisationsproblem. Es gibt drei Teile:
- Ein serverseitiges Manifest: eine Datei, die Pfad, Größe und
hash(zum Beispiel SHA-256) jeder Datei im veröffentlichten Client auflistet. - Ein Dateispeicher: ein HTTP(S)-Server oder CDN, von dem die aktuellen Client-Dateien heruntergeladen werden können.
- Die Client-Anwendung (Launcher): sie lädt das Manifest herunter, vergleicht es mit den lokalen Dateien, holt die fehlenden/geänderten und startet das Spiel.
Die Kernidee ist hier der inhaltsbasierte Vergleich. Anstatt einem Datum oder einer Versionsnummer zu vertrauen, prüfst du den Hash jeder Datei; so werden halb heruntergeladene oder beschädigte Dateien beim nächsten Start automatisch repariert.
Die Manifest-Datei erzeugen
Schreibe zuerst ein kleines Skript, das den zu veröffentlichenden Client-Ordner durchläuft und ein Manifest erzeugt. Unten ein einfaches PowerShell-Beispiel; du kannst dieselbe Logik auch in Python oder als CI-Schritt einrichten:
$root = "C:\dist\metin2-client"
$items = Get-ChildItem $root -Recurse -File | ForEach-Object {
$rel = $_.FullName.Substring($root.Length + 1).Replace('\','/')
[pscustomobject]@{
path = $rel
size = $_.Length
hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower()
}
}
$items | ConvertTo-Json -Depth 3 | Out-File "$root\manifest.json" -Encoding utf8
Das entstehende manifest.json sieht so aus:
[
{ "path": "metin2client.exe", "size": 5242880, "hash": "9f2c..." },
{ "path": "pack/root.eix", "size": 184320, "hash": "ab17..." },
{ "path": "pack/root.epk", "size": 9437184, "hash": "5e0d..." }
]
Lege das Manifest in dasselbe Verzeichnis wie die Client-Dateien, unter eine feste URL (zum Beispiel https://cdn.meinserver.com/client/manifest.json). Für jeden neuen Patch führst du dieses Skript einfach erneut aus und veröffentlichst das Manifest neu.
Die Client-Seite: Vergleich und Download
Da du den Launcher für Windows schreibst, ist C# (.NET) eine praktische Wahl; HttpClient, SHA256 und WPF/WinForms sind eingebaut. Der Kernablauf lautet: das Manifest herunterladen, den Hash jeder lokalen Datei berechnen und die Dateien herunterladen, die nicht übereinstimmen.
using System.Security.Cryptography;
string Sha256(string file)
{
using var stream = File.OpenRead(file);
using var sha = SHA256.Create();
return Convert.ToHexString(sha.ComputeHash(stream)).ToLowerInvariant();
}
async Task SyncAsync(string baseUrl, string localRoot, List<Entry> manifest)
{
using var http = new HttpClient();
foreach (var entry in manifest)
{
var local = Path.Combine(localRoot, entry.path);
bool needs = !File.Exists(local) || Sha256(local) != entry.hash;
if (!needs) continue;
Directory.CreateDirectory(Path.GetDirectoryName(local)!);
var bytes = await http.GetByteArrayAsync($"{baseUrl}/{entry.path}");
await File.WriteAllBytesAsync(local, bytes);
}
}
Für große .epk/.eix-Pakete solltest du das Streaming auf die Festplatte statt GetByteArrayAsync bevorzugen, damit der Speicher nicht überläuft und du einen Fortschrittsbalken speisen kannst. Einen Prozentsatz zeigst du an, indem du die je Datei heruntergeladenen Bytes ins Verhältnis zur Gesamtgröße setzt.
Das Spiel korrekt starten
Sobald die Synchronisation abgeschlossen ist, startet der Launcher den Client. Das Arbeitsverzeichnis auf den Client-Ordner zu setzen ist wichtig, sonst findet das Spiel seine Pakete nicht:
var psi = new ProcessStartInfo
{
FileName = Path.Combine(localRoot, "metin2client.exe"),
WorkingDirectory = localRoot,
UseShellExecute = false
};
Process.Start(psi);
Bei Bedarf kann der Launcher ein Argument übergeben, um dem Client eine Sitzung/ein Token zu übermitteln; vermeide es aber, sensible Daten im Klartext auf der Kommandozeile zu senden — nutze stattdessen eine temporäre Datei oder eine Named Pipe.
Hinweise zu Update und Sicherheit
- Nutze HTTPS. Das Manifest und die Dateien über einfaches HTTP auszuliefern öffnet die Tür für Man-in-the-Middle-Manipulation (MITM).
- Signiere das Manifest. Für ein robusteres Setup signierst du das Manifest mit einem privaten Schlüssel und prüfst es mit einem im Launcher eingebetteten öffentlichen Schlüssel, damit kein gefälschtes Manifest eingeschleust werden kann.
- Self-Update. Der Launcher selbst muss ebenfalls aktualisiert werden. Ein üblicher Ansatz: die neue Version als
launcher.exe.newherunterladen und die Datei beim Beenden mit einem kleinen Hilfsskript austauschen. - Wiederholen und reparieren. Wird ein Download unterbrochen, stimmt der Hash beim nächsten Start nicht, also wird die Datei erneut geholt — Reparatur ist ein natürliches Nebenprodukt dieser Architektur.
Häufige Fehler beim Metin2-Patcher bauen
Die meisten Probleme kommen nicht von der Architektur, sondern von den Details. Am häufigsten: Schrägstriche in relativen Pfaden vermischen (Windows \ vs URL /), Hashes mit inkonsistenter Groß-/Kleinschreibung vergleichen und den Launcher aufblähen, indem riesige Pakete vollständig in den Speicher geladen werden. Erzeuge das Manifest immer als letzten Schritt der Distribution; sonst ist eine gerade hinzugefügte Datei nicht im Manifest und erreicht die Spieler nie.
Häufige Fragen
Welche Sprache/Technologie soll ich wählen?
Wenn du Windows anvisierst, ist C# (.NET) der reibungsärmste Weg; du lieferst es als Einzeldatei-publish aus. Willst du Plattformübergreifend oder eine schlankere UI, funktionieren auch C++/Qt oder Electron, aber Electron hat einen Kostenpunkt bei der Größe.
Warum SHA-256 statt MD5?
MD5 wird aus Sicherheitsgründen abgeraten, weil es kollisionsanfällig ist. MD5 ist zwar schnell für reine Integritätsprüfungen, doch sobald du eine Sicherheitsebene wie die Manifest-Signierung hinzufügst, ist es sauberer, konsistent bei SHA-256 zu bleiben.
Soll ich den gesamten Client oder nur den Diff verteilen?
In dieser Architektur werden nur Dateien heruntergeladen, deren Hash sich geändert hat, du erhältst also faktisch inkrementelle Updates. Für die Erstinstallation erleichtert es den Spielern das Leben, zusätzlich einen Link zum einmaligen Download des vollständigen Clients anzubieten.
Willst du einen soliden Patcher für deinen eigenen Server? Ich baue den kompletten Launcher-Stack, von der Manifest-Erzeugung bis zum Self-Update, und liefere ihn mit einer UI, die zu deiner Marke passt. Lass uns über dein Projekt sprechen: nimm Kontakt mit mir auf.