Înapoi la blogToate tutorialele Metin2
Tutoriale Metin2 · Lecția 96 din 99

Compatibilitatea protocolului game–client în Metin2: de ce se strică conexiunea

2 noiembrie 2026 5 min de citit

Serverul și clientul își trimit continuu mesaje: „jucătorul s-a mișcat”, „a scris în chat”, „a primit un item”. Fiecare mesaj are o formă fixă, stabilită dinainte, ca un formular tipizat. Dacă serverul completează formularul cu o rubrică în plus, iar clientul îl citește pe cel vechi, totul se decalează: clientul citește numere greșite, se blochează sau este deconectat. Lecția îți explică, fără matematică, de ce se întâmplă asta și cum faci schimbări fără să rupi jocul.

Pe scurt: mesajele (pachetele) sunt definite în cod, pe server în packet.h și în client în Packet.h. Numărul fiecărui mesaj și ordinea și mărimea rubricilor trebuie să fie identice pe ambele părți. Dacă schimbi una, compilezi și distribui ambele în același timp și testezi pe serverul de test.

Nivel: Avansat. Ce trebuie să știi înainte: ce sunt game, db, client și sursa, compilarea game și compilarea clientului. Ajută și lecția despre diferențele client–server la iteme noi.

Cuvinte pe care le vei întâlni

CuvântCe înseamnă
ProtocolRegulile comune după care serverul și clientul își trimit mesaje.
Pachet (packet)Un mesaj trimis prin rețea.
HeaderPrimul octet al pachetului: un număr care spune ce fel de mesaj e (chat, mișcare, item).
StructDescrierea în cod a unui pachet: ce rubrici are, în ce ordine și cât de mare e fiecare.
Octet (byte)Cea mai mică unitate de date. BYTE = 1 octet, WORD = 2 octeți, DWORD = 4 octeți.
CG / GCDirecția: CG = de la client la game, GC = de la game la client.

Cum arată un pachet, pe exemplul chatului

În sursa serverului verificată, în game/src/packet.h:

cpp
typedef struct command_chat
{
	BYTE	header;
	WORD	size;
	BYTE	type;
} TPacketCGChat;

În sursa clientului, în source/UserInterface/Packet.h:

cpp
typedef struct command_chat
{
	BYTE	header;
	WORD	length;
	BYTE	type;
} TPacketCGChat;

Observi ceva? A doua rubrică se numește size pe server și length în client. Nu contează. Numele există doar pentru programatori. Prin rețea circulă doar octeții: 1 octet de header, 2 octeți de lungime, 1 octet de tip, apoi textul. Ce contează e să fie aceeași ordine și aceeași mărime.

Numărul mesajului e și el identic pe ambele părți. Pe server, HEADER_CG_CHAT = 3 și HEADER_GC_CHAT = 4; în client, la fel.

De ce un câmp în plus strică totul

Imaginează-ți un formular de bancă cu rubricile: nume (20 de căsuțe), sumă (10 căsuțe). Dacă banca tipărește un formular nou cu o rubrică „telefon” între ele, dar casierul îl citește după șablonul vechi, el va citi telefonul ca sumă. Exact asta se întâmplă cu pachetele.

În sursă, la începutul listei de pachete apare #pragma pack(1). Asta îi spune compilatorului: „nu lăsa spații goale între rubrici”. Fără ea, compilatorul ar putea adăuga octeți de umplutură, iar serverul și clientul (compilate cu unelte diferite, unul pe FreeBSD, altul în Visual Studio) ar putea ajunge la mărimi diferite pentru același struct. De aceea nu muți definiții de pachete în afara zonei #pragma pack(1) ... #pragma pack().

Ce se strică, concret

Ce veziCauză probabilă
Clientul se deconectează imediat după loginUn pachet trimis la intrare are altă mărime pe o parte
Clientul se blochează la o acțiune anumePachetul acelei acțiuni diferă
Valori absurde în joc (nivel 0, yang uriaș, nume ciudate)Rubrici citite decalat
syserr cu mesaje despre pachete necunoscute sau mărimi greșiteHeader necunoscut sau lungime greșită

Mesajele exacte din syserr diferă de la pachet la pachet.

Pasul 1: Înainte să schimbi un pachet

Pune-ți întâi întrebarea: chiar trebuie? Multe lucruri se pot face cu pachete existente, de exemplu un mesaj de chat (vezi prima modificare în sursă) sau un quest.

Dacă trebuie, găsește struct-ul pe ambele părți:

sh
grep -n "struct command_chat" /usr/home/sursa/game/src/packet.h

Pe Windows, în Visual Studio, folosește Edit → Find and Replace → Find in Files cu același text în sursa clientului.

Pasul 2: Schimbă simetric

  1. Notează struct-ul vechi: fiecare rubrică, tipul ei, mărimea în octeți.
  2. Adaugă noua rubrică în aceeași poziție pe server și în client, cu același tip.
  3. Verifică și codul care completează și citește pachetul: dacă trimite o mărime fixă, trebuie actualizată.
  4. Dacă pachetul trece și prin db sau între core-uri, verifică și acolo: db și game au structurile comune în folderul common/, iar core-urile își trimit și ele mesaje între ele.

Pasul 3: Compilează și distribuie împreună

  • Compilezi game (și db, dacă ai atins common/) și clientul.
  • Le testezi împreună pe serverul de test: login, chat, inventar, comerț, schimbare de canal, relogare, mesaje lungi.
  • La lansare, clienții vechi nu vor mai merge corect. Pui serverul nou și clientul nou în aceeași mentenanță, iar clientul ajunge la jucători prin update cu autopatcher.

Regula de siguranță: serverul nu are încredere în client

Clientul poate fi modificat de oricine. Orice valoare primită de la client (o cantitate, o poziție, un ID de item) trebuie verificată pe server: e în limite? are jucătorul voie? există itemul? Un pachet nou fără verificări e o ușă deschisă pentru trișori. Detalii în protecția împotriva accesului neautorizat.

Greșeli des întâlnite

  • Schimbi doar serverul și uiți clientul (sau invers).
  • Pui rubrica nouă în altă poziție pe cele două părți.
  • Folosești tipuri diferite (WORD pe o parte, DWORD pe cealaltă).
  • Lași jucătorii cu clientul vechi după update.
  • Te bazezi pe verificările din client. Ele pot fi ocolite.

Întrebări frecvente

Am schimbat doar o iconiță în client. Afectează protocolul?

Nu. Iconițele, textele și interfața din pack-uri nu schimbă pachetele.

Pot adăuga un pachet complet nou în loc să modific unul existent?

Da, și e adesea mai sigur. Îi dai un header nefolosit, același pe ambele părți, și îl înregistrezi acolo unde serverul și clientul își țin lista de pachete cunoscute. Testează-l temeinic.

De ce după update merge pe un canal și pe altul nu?

Probabil un core rulează alt binar game. Verifică cu sha256 fișierul folosit de fiecare core (vezi deploy).

Ce urmează

Mergi la versionare și release pentru game, db și client. Toate lecțiile sunt în lista tutorialelor Metin2.

Server Metin2 gata de joc

Găzduire Metin2 în România, cu instalare de serverfiles, bază de date MySQL și protecție Anti-DDoS inclusă.

DiscordWhatsApp