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

Metin2 patcher maken: een launcher met auto-update

Een degelijke Metin2 patcher maken is een van de belangrijkste stukjes infrastructuur wanneer je je eigen server draait: in plaats van de client met de hand te downloaden en bestanden te kopiëren, verwachten spelers dat de launcher die ze openen de updates stilletjes afhandelt. Een goed ontworpen launcher vergelijkt de versie op de server met die op de schijf van de speler, downloadt alleen de gewijzigde bestanden en start het spel met de juiste parameters. In deze gids bouwen we een eenvoudige maar robuuste architectuur voor automatische updates, van begin tot eind.

Hoe een launcher werkt: de architectuur in het kort

Patcher-logica is eigenlijk gewoon een synchronisatieprobleem. Er zijn drie delen:

  • Een manifest aan de serverkant: een bestand dat het pad, de grootte en de hash (bijvoorbeeld SHA-256) van elk bestand in de gepubliceerde client opsomt.
  • Een bestandsopslag: een HTTP(S)-server of CDN waarvandaan de huidige clientbestanden kunnen worden gedownload.
  • De clientapplicatie (launcher): die downloadt het manifest, vergelijkt het met de lokale bestanden, haalt de ontbrekende/gewijzigde op en start het spel.

Het kernidee hier is vergelijking op basis van inhoud. In plaats van te vertrouwen op een datum of versienummer verifieer je de hash van elk bestand; zo worden half gedownloade of beschadigde bestanden bij de volgende start automatisch hersteld.

Het manifestbestand genereren

Schrijf eerst een klein script dat de clientmap die je gaat publiceren doorloopt en een manifest produceert. Hieronder een eenvoudig PowerShell-voorbeeld; je kunt dezelfde logica ook in Python of als CI-stap opzetten:

$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

Het resulterende manifest.json ziet er zo uit:

[
  { "path": "metin2client.exe", "size": 5242880, "hash": "9f2c..." },
  { "path": "pack/root.eix",     "size": 184320,  "hash": "ab17..." },
  { "path": "pack/root.epk",     "size": 9437184, "hash": "5e0d..." }
]

Plaats het manifest in dezelfde map als de clientbestanden, onder een vaste URL (bijvoorbeeld https://cdn.mijnserver.com/client/manifest.json). Bij elke nieuwe patch draai je dit script gewoon opnieuw en publiceer je het manifest opnieuw.

De clientkant: vergelijken en downloaden

Omdat je de launcher voor Windows schrijft, is C# (.NET) een praktische keuze; HttpClient, SHA256 en WPF/WinForms zitten er al in. De kernflow is: download het manifest, bereken de hash van elk lokaal bestand en download de bestanden die niet overeenkomen.

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

Voor grote .epk/.eix-pakketten gebruik je liever streaming naar schijf in plaats van GetByteArrayAsync, zodat je het geheugen niet uitput en een voortgangsbalk kunt voeden. Je toont een percentage door de gedownloade bytes per bestand af te zetten tegen de totale grootte.

Het spel correct starten

Zodra het synchroniseren klaar is, draait de launcher de client. De werkmap instellen op de clientmap is belangrijk, anders vindt het spel zijn pakketten niet:

var psi = new ProcessStartInfo
{
    FileName = Path.Combine(localRoot, "metin2client.exe"),
    WorkingDirectory = localRoot,
    UseShellExecute = false
};
Process.Start(psi);

Desgewenst kan de launcher een argument meegeven om een sessie/token aan de client door te geven; maar vermijd het versturen van gevoelige gegevens in platte tekst op de opdrachtregel — gebruik in plaats daarvan een tijdelijk bestand of een named pipe.

Aandachtspunten voor update en beveiliging

  • Gebruik HTTPS. Het manifest en de bestanden via gewone HTTP serveren opent de deur naar man-in-the-middle (MITM)-manipulatie.
  • Onderteken het manifest. Voor een steviger opzet onderteken je het manifest met een privésleutel en verifieer je het met een publieke sleutel die in de launcher is ingebouwd, zodat er geen vervalst manifest kan worden geïnjecteerd.
  • Self-update. De launcher zelf moet ook worden bijgewerkt. Een gangbare aanpak: download de nieuwe versie als launcher.exe.new en wissel het bestand bij het afsluiten met een klein hulpscript.
  • Opnieuw proberen en herstellen. Als een download wordt onderbroken, komt de hash bij de volgende start niet overeen, dus wordt het bestand opnieuw opgehaald — herstel is een natuurlijk bijproduct van deze architectuur.

Veelgemaakte fouten bij het maken van een Metin2 patcher

De meeste problemen komen niet van de architectuur maar van de details. De meest voorkomende: slashes door elkaar halen in relatieve paden (Windows \ vs URL /), hashes vergelijken met inconsistent hoofdlettergebruik, en de launcher opblazen door enorme pakketten volledig in het geheugen te laden. Genereer het manifest altijd als de laatste stap van de distributie; anders zit een bestand dat je net hebt toegevoegd niet in het manifest en bereikt het de spelers nooit.

Veelgestelde vragen

Welke taal/technologie moet ik kiezen?

Als je Windows als doel hebt, is C# (.NET) het pad met de minste wrijving; je levert het als een publish in één bestand. Wil je cross-platform of een strakkere UI, dan werken C++/Qt of Electron ook, maar Electron heeft een kostenpost in grootte.

Waarom SHA-256 in plaats van MD5?

MD5 wordt vanwege de beveiliging afgeraden omdat het gevoelig is voor collisions. Hoewel MD5 snel is voor eenvoudige integriteitscontroles, is het schoner om consistent met SHA-256 te blijven zodra je een beveiligingslaag zoals manifestondertekening toevoegt.

Moet ik de hele client of alleen het verschil distribueren?

In deze architectuur worden alleen bestanden waarvan de hash is veranderd gedownload, dus je krijgt in feite incrementele updates. Voor de eerste installatie maakt het aanbieden van een link om de volledige client één keer te downloaden het de spelers makkelijker.

Wil je een degelijke patcher voor je eigen server? Ik bouw de volledige launcher-stack, van manifestgeneratie tot self-update, en lever hem met een UI die past bij je merk. Laten we het over je project hebben: neem contact met me op.

Bu kategorideki tüm yazılar →

Devamı için