Entwicklung10 Min. Lesezeit

Metin2-Client für Android bauen und mit dem eigenen Testserver verbinden

Anleitung zum Cemre-Android-Port: APK bauen, Daten vorbereiten, kompatiblen Testserver einrichten und ABI-, Protokoll- und Portfehler beheben.

Von METIN2.GG

Ausgewählter Client und Umfang

Als nützlichsten öffentlich zugänglichen Ausgangspunkt für einen vollständigen Metin2-Client auf Android haben wir cemreefe/metin2-android gefunden. Das Projekt enthält den ursprünglichen C++-Client, einen Android-Launcher, Touch-Eingaben, native Bibliotheken und eine Anleitung für den Anschluss an einen kompatiblen Server. Dieser Leitfaden bezieht sich auf Revision 4ac33651d49000de95e520e6de4373213dc54405. Es ist keine universelle APK für jeden Privatserver: Client, Spieldaten und Server müssen zusammenpassen.

Zum Begriff Open Source gehört ein wichtiger Vorbehalt: Am 25. Oktober 2026 hatte das Haupt-Repository keine Lizenz für den vollständigen Client angegeben. Öffentlich einsehbarer Code darf dadurch nicht automatisch weiterverbreitet werden. OpenGr2ndma steht unter MPL-2.0; das gilt aber nur für diese Komponente. Für die ursprünglichen Spieldaten gelten eigene Rechte. Dieser Leitfaden enthält daher weder Spieldaten noch eine APK mit Spieldaten. Ausgewählte Quellcode-Revision, OpenGr2ndma-Lizenz.

Metin2-Krieger in silberblauer Rüstung auf einem Smartphone neben einem Entwicklungs-Laptop

Illustration: ein erkennbarer Metin2-Charakter auf einem Smartphone während der Vorbereitung eines Clients. Dies ist kein Screenshot eines Builds oder des Spiels.

Warum dieses Projekt und was die Foren zeigen

Im Turkmmo-Thema Metin2 Mobile & PC Cross Platform Source sind nach der Anmeldung BGFX/OpenGL-Archive verfügbar. Das geprüfte opengl.zip enthält tatsächlich ein Android-Projekt und den C++-Client. Es fehlen jedoch die für den Build benötigten Android-Bibliotheken .a/.so; die enthaltene Windows-Granny-Bibliothek kann sie nicht ersetzen. Eine fertige APK, einen vollständigen Gradle-Wrapper oder eine Lizenz für den gesamten Client haben wir nicht gefunden. Wir haben die Dateien geprüft, aber keine mitgelieferten Programme gestartet.

Das neuere Thema mit dem Titel Mobile Source … Full beschreibt im Beitrag einen Unity-Prototyp. Touch-Steuerung sowie Android/iOS werden dort als zukünftige Arbeit aufgeführt. Das separate große Archiv haben wir nicht geprüft; der Titel allein belegt keinen fertigen mobilen Client.

Projekt Öffentlich belegter Stand Eignung für diese Anleitung
Cemre Android-Port C++/Java, Bibliotheken für zwei ABIs, Profile, Dateninstallation, Touch-UI und lokaler Servercode Stärkster Kandidat der geprüften Projekte; Lizenz des Haupt-Clients ungeklärt
Geteiltes OpenGL-Archiv bei Turkmmo Android-Grundgerüst und umfangreicher Clientcode, aber keine Android-Bibliotheken Weitere Portierung und Abhängigkeiten nötig
Metin2ToUnity bei M2Dev Werkzeuge zur Konvertierung von Spielressourcen Ein Importer ist kein vollständiger Netzwerk-Client
metin2-godot MIT für den eigenen Code, dokumentierte Entwicklungsmeilensteine Interessante Entwicklungsbasis, kein fertiger Android-Port

Der Autor des Ports berichtet von Login, Spieleintritt, Kämpfen, Inventar und Speichern. Die wichtigsten Nachweise stammen aus einem x86_64-Emulator; ein echtes arm64-Gerät und längere Spielsitzungen müssen separat geprüft werden. Den größeren Überblick bietet unser Artikel zu mobilen Metin2-Clients.

Zuerst eine überprüfbare Kombination wählen

Die Hauptanleitung verbindet einen Android-Client über ein lokales Netzwerk mit deinem eigenen Testserver. Betreibe den Server auf einem separaten Linux-Rechner oder in einer VM und verbinde das Smartphone mit demselben WLAN. Die Alternative mit eingebettetem Server in der APK steht weiter unten.

Komponente Festgelegte Revision/Version
Android-Client 4ac33651d49000de95e520e6de4373213dc54405
m2dev-server-src 66068c1
m2dev-server: Konfiguration, Karten, SQL und Quests ad30738
Erwartete Datenstruktur von m2dev-client 98d2c1af; verwende nur Daten, die du nutzen darfst
Java / Gradle JDK 17 / Gradle 8.1.1
Android-Werkzeuge Plattform 33, Build Tools 33.0.1, NDK 25.2.9519653, CMake 3.22.1
Ziel-ABI arm64-v8a für ein passendes Smartphone, x86_64 für einen passenden Emulator

Build Tools 33.0.1 ist in app/build.gradle festgelegt. Das Installationsbeispiel im Upstream-Leitfaden nennt eine andere Patch-Version. Ersetze festgelegte Versionen nicht automatisch durch die neuesten.

1. Werkzeuge installieren und genaue Revision auschecken

Die Befehle sind für Bash unter Linux. Trage den tatsächlichen Pfad zum Android-SDK und zu einer separaten Gradle-8.1.1-Installation ein. JDK 17 muss in JAVA_HOME aktiv sein. Installiere das SDK mit den offiziellen Android-Werkzeugen und lies neue Lizenzbedingungen selbst, bevor du ihnen zustimmst. Dokumentation zum SDK Manager.

java -version
gradle --version
sdkmanager "platforms;android-33" "build-tools;33.0.1" \
  "ndk;25.2.9519653" "cmake;3.22.1" "platform-tools"

mkdir -p "$HOME/metin2-lab"
cd "$HOME/metin2-lab"
git clone https://github.com/cemreefe/metin2-android.git
cd metin2-android
git checkout --detach 4ac33651d49000de95e520e6de4373213dc54405
git submodule update --init --recursive
git submodule status

export M2_REPO="$PWD"
export M2_ANDROID="$M2_REPO/r10dev.net OPENGL-ITJA/android"
export ANDROID_SDK_ROOT="$HOME/Android/Sdk"
export GRADLE="/opt/gradle-8.1.1/bin/gradle"
printf 'sdk.dir=%s\n' "$ANDROID_SDK_ROOT" > "$M2_ANDROID/local.properties"

OpenGr2ndma ist in dieser Revision auf Commit 210f5c326531297495c24e7bb1e24dc1b1a77833 festgelegt. Ohne das Submodul schlägt CMake fehl; ein heruntergeladenes GitHub-ZIP initialisiert es nicht automatisch. Setze den Pfad r10dev.net OPENGL-ITJA wegen der Leerzeichen in Anführungszeichen.

2. Eigenes Profil anlegen und externen Katalog abschalten

Speichere diese Werte in profiles/home.properties. Ersetze 192.168.1.50 durch die LAN-Adresse deines Linux-Servers. Auf dem Smartphone verweist 127.0.0.1 auf das Smartphone selbst, nicht auf einen anderen Rechner.

m2.abi=arm64-v8a
m2.serverMode=remote
m2.serverHost=192.168.1.50
m2.authPort=11000
m2.channelPort=11011
m2.gamePortOffset=0
m2.applicationIdSuffix=.lab
m2.appLabel=Metin2 Local Lab
m2.versionName=home
m2.dataBundled=false
m2.dataUrl=
m2.dataVersion=1
m2.serverListUrl=
m2.devUrl=
m2.updateChannel=

Trage in servers/servers.json ausschließlich deinen Testserver ein:

{
  "version": 1,
  "servers": [
    {
      "name": "Home Lab",
      "host": "192.168.1.50",
      "authPort": 11000,
      "channelPort": 11011
    }
  ]
}

Das leere m2.serverListUrl= ist beabsichtigt. Fehlt die Einstellung, verwendet der Build den externen Standardkatalog des Autors. Ein leeres m2.devUrl= schaltet optionale Diagnose-Uploads und die Updateprüfung ab. So erscheint im Lab-Build nicht der Entwicklungsserver eines anderen Betreibers. Siehe ServerCatalog.java und DevReporter.java.

3. APK zuerst ohne Spieldaten bauen

So trennst du Fehler in Werkzeugkette und nativen Bibliotheken von Daten- oder Serverproblemen. Ein erfolgreicher Build allein bedeutet noch nicht, dass du die Spielwelt betreten kannst.

cd "$M2_ANDROID"
"$GRADLE" --no-daemon --max-workers=4 assembleDebug \
  -Pm2profile=home -Pm2abi=arm64-v8a
ls -lh app/build/outputs/apk/debug/app-debug.apk

Für einen x86_64-Emulator ändere das letzte Argument zu -Pm2abi=x86_64. Die ABI muss zum Zielgerät passen. Bei dieser Prüfung enthielt das Repository keine fertige öffentliche APK; der Befehl erstellt einen eigenen Debug-Build.

Konkretes Build-Ergebnis

Unser erster Windows-Build der unveränderten Revision brach bei der C++-Kompilierung ab: UserInterface/Locale.h überlagerte die Systemdatei <locale.h>. In einer separaten Arbeitskopie entfernten wir ${CMAKE_CURRENT_SOURCE_DIR}/UserInterface aus der Liste include_directories(...) in clientsource/CMakeLists.txt und fügten direkt danach Folgendes ein:

add_compile_options("-iquote${CMAKE_CURRENT_SOURCE_DIR}/UserInterface")

Das Spielverzeichnis bleibt damit für Include-Angaben in Anführungszeichen verfügbar, stört aber nicht mehr bei der Suche nach System-Headern. Mit der Änderung lief assembleDebug für x86_64 durch und erzeugte eine APK mit der nativen Client-Bibliothek. Das belegt einen Build der angepassten Arbeitskopie, nicht den unveränderten Upstream-Build auf jedem Windows-Rechner. Der Linux-Ablauf oben folgt dem Code und der Anleitung des Autors. Spieleintritt, echtes Smartphone, Leistung und eingebetteter Server wurden dabei nicht getestet.

4. Kompatible Daten mit dem vorgesehenen Skript vorbereiten

Lege einen Daten-Checkout mit der erwarteten Struktur unter ~/metin2-lab/client-data ab und verwende nur Daten, zu deren Nutzung du berechtigt bist. Diese Anleitung gewährt keine Rechte an Modellen, Karten oder Musik. Ein beliebiges Pack eines anderen Privatservers ist kein geprüfter Ersatz; Protos, Python-UI und Dateiformate können abweichen.

sudo apt install rsync patch python3-pil libsodium23 liblzo2-2 zip imagemagick ninja-build
export M2_DATA="$HOME/metin2-lab/client-data"
export M2_STAGE="$HOME/metin2-lab/staged-data"
test -d "$M2_DATA/assets/root"
"$M2_ANDROID/tools/stage_client_data.sh" "$M2_DATA" "$M2_STAGE" en

stage_client_data.sh führt Packs in festgelegter Reihenfolge zusammen, legt root darüber, konvertiert item_proto/mob_proto und ergänzt Kompatibilitätsskripte, Skalierung und Touch-HUD. Prüfe zuerst das Staging, bevor du den Renderer verdächtigst. Benenne koreanische Dateien nicht massenhaft in Kleinbuchstaben um.

Der Client benötigt zusätzlich die Standardbibliothek von Python 2.7.18, genauer das Verzeichnis Lib, nicht das Python 3 des Hostsystems. Entpacke es aus dem offiziellen Python-2.7.18-Quellarchiv in einen eigenen Arbeitsordner. Setze zum Beispiel M2_PYLIB=~/metin2-lab/python-2.7.18/Lib. Python 2 ist keine unterstützte Laufzeit für normale Hostdienste; hier ist es eine Abhängigkeit des alten Clients.

Für ein Datenpaket in der APK setze m2.dataBundled=true in home.properties und führe dann Folgendes aus:

export M2_PYLIB="$HOME/metin2-lab/python-2.7.18/Lib"
test -f "$M2_PYLIB/os.py"
M2_CLIENT_DATA="$M2_STAGE" M2_PYLIB="$M2_PYLIB" \
M2_BUNDLE_OUT="$HOME/metin2-lab/bundle" GRADLE="$GRADLE" \
  "$M2_ANDROID/tools/make_bundle.sh" home 1

Das Ergebnis sind ~/metin2-lab/bundle/metin2-home-1.apk und ein versioniertes Daten-ZIP. Plane genug Speicher für gestagte Daten, ZIP und APK ein. Änderst du später die Daten, erhöhe m2.dataVersion; das Löschen des alten ZIPs allein veranlasst eine installierte App nicht dazu, dieselbe Version erneut zu entpacken. Die APK-Buildnummer ist davon getrennt. Details stehen in make_bundle.sh.

5. Kompatiblen Server und erreichbare Core-Adressen vorbereiten

Dieser Abschnitt folgt dem Self-Hosting-Leitfaden des Autors. Verwende eine separate Linux-Test-VM und ändere keinen bestehenden Produktivserver. Upstream nennt Ubuntu 22.04, g++ 11, CMake 3.22 und MariaDB 10.6.

sudo apt install build-essential cmake git mariadb-server python3
cd "$HOME/metin2-lab"
git clone https://github.com/d1str4ught/m2dev-server-src.git
git -C m2dev-server-src checkout --detach 66068c1
git -C m2dev-server-src apply "$M2_REPO/server/m2dev-server-src-linux.patch"
cmake -S m2dev-server-src -B m2dev-server-src/build -DCMAKE_BUILD_TYPE=Release
cmake --build m2dev-server-src/build -j4

git clone https://github.com/d1str4ught/m2dev-server.git m2srv
git -C m2srv checkout --detach ad30738
cp m2dev-server-src/build/bin/{db,game,qc} m2srv/share/bin/
cp m2srv/share/bin/qc m2srv/share/locale/english/quest/qc
(cd m2srv/share/locale/english/quest && python3 make.py)

Lege vor dem Start die Datenbanken und einen eingeschränkten Benutzer an. Das folgende SQL ist für eine neue, separate VM ohne vorhandene Datenbanken dieser Namen gedacht. Ersetze in sudo mariadb beide Platzhalter DOPLN_VLASTNI_HESLO durch dasselbe starke Passwort. Führe das SQL nicht mit dem wörtlichen Platzhalter aus.

CREATE DATABASE account;
CREATE DATABASE common;
CREATE DATABASE player;
CREATE DATABASE log;
CREATE DATABASE hotbackup;
CREATE USER 'm2lab'@'127.0.0.1' IDENTIFIED BY 'DOPLN_VLASTNI_HESLO';
CREATE USER 'm2lab'@'localhost' IDENTIFIED BY 'DOPLN_VLASTNI_HESLO';
GRANT ALL ON account.* TO 'm2lab'@'127.0.0.1', 'm2lab'@'localhost';
GRANT ALL ON common.* TO 'm2lab'@'127.0.0.1', 'm2lab'@'localhost';
GRANT ALL ON player.* TO 'm2lab'@'127.0.0.1', 'm2lab'@'localhost';
GRANT ALL ON log.* TO 'm2lab'@'127.0.0.1', 'm2lab'@'localhost';
GRANT ALL ON hotbackup.* TO 'm2lab'@'127.0.0.1', 'm2lab'@'localhost';

Importiere anschließend die vier mitgelieferten Schemas. Laut Runtime-Anleitung soll hotbackup anfangs leer bleiben:

cd "$HOME/metin2-lab/m2srv"
for db in account common player log; do
  sudo mariadb "$db" < "sql/$db.sql"
done

Ersetze in share/conf/db.txt bei SQL_ACCOUNT, SQL_PLAYER, SQL_COMMON und SQL_HOTBACKUP Benutzer und Passwort durch deine m2lab-Zugangsdaten. Ändere in share/conf/game.txt entsprechend ACCOUNT_SQL, PLAYER_SQL, COMMON_SQL und LOG_SQL. Behalte übrige Werte und die unterschiedliche Feldreihenfolge der Dateien bei. Echte Zugangsdaten gehören nicht in ein öffentliches Git-Repository. DB-Konfiguration, Game-Konfiguration.

MariaDB soll nur an 127.0.0.1 gebunden sein; das Smartphone verbindet sich nicht mit der Datenbank. Ergänze in dieser VM unter [mysqld] die Datei /etc/mysql/mariadb.conf.d/99-metin2-lab.cnf um:

[mysqld]
bind-address=127.0.0.1
sql_mode=NO_ENGINE_SUBSTITUTION

Prüfe nach sudo systemctl restart mariadb die Verbindung mit mariadb -h 127.0.0.1 -u m2lab -p account. Gib das Passwort erst an der Eingabeaufforderung ein. Diese alte Runtime benötigt den SQL-Modus; übertrage ihn nicht auf eine Datenbank, die ein anderes Projekt verwendet.

Lege einen neuen Test-Spielaccount in dieser Datenbank an; der Dump enthält auch vorbereitete Accounts. Ersetze die Beispielwerte durch eigene Testdaten:

INSERT INTO account.account (login, password, social_id, status)
VALUES ('VLASTNI_TEST_LOGIN', PASSWORD('VLASTNI_TEST_HESLO'), '1234567', 'OK');

Führe nach der Datenbankvorbereitung python3 install.py in m2srv aus. Das Skript erzeugt Konfigurationsdateien. Setze anschließend in jeder Datei channels/channel1/coreN/CONFIG die für das Smartphone erreichbare Adresse:

BIND_IP: 192.168.1.50

Die automatische Erkennung kann die LAN-Adresse des Servers überspringen. Jeder Core teilt dem Client außerdem seine eigene Adresse mit. Prüfe den Wert erneut, wenn du install.py noch einmal ausführst, denn das Skript erzeugt die Dateien neu.

Verbindung Standard-TCP-Port Erreichbarkeit vom Smartphone
Login 11000 Ja, nur im Test-LAN
Spiel-Cores von Channel 1 11011, 11012, 11013 Alle drei, da ein Kartenwechsel den Client umleiten kann
DB-Prozess 9000 Interne Serverkommunikation
P2P zwischen Cores 12000 und höher Interne Serverkommunikation

Starte den Channel in m2srv mit python3 start.py 1 und beende ihn mit python3 stop.py. Prüfe die Auth-Logs und alle drei Core-Logs. Funktioniert der Login, aber nach der Charakterauswahl erscheint wieder die Serverliste, kontrolliere zuerst Adresse und Port des Ziel-Cores. Der Auth-Port allein genügt nicht.

Aktualisiere den Server nicht blind. Ab Server-Commit 0cc595bf097dcf89ddba60615e56fe790823cd22 wechselt der Handshake zu 0xf8 mit libsodium/XChaCha20. Dieser Client erwartet das ältere 0xfb/0xfa. Für einen neueren Server muss das Protokoll tatsächlich in den Client portiert werden; eine andere IP oder ein neues Passwort hilft nicht.

6. Auf dem Smartphone installieren und den ersten Lauf untersuchen

adb devices
adb shell getprop ro.product.cpu.abilist
adb install -r "$HOME/metin2-lab/bundle/metin2-home-1.apk"
adb shell pm path com.metin2.client.lab

Starte die App, wähle deinen Eintrag Home Lab und melde dich nur mit dem Testaccount deines Servers an. Die Paket-ID dieses Profils ist com.metin2.client.lab; externe App-Daten liegen daher üblicherweise hier:

adb shell ls /sdcard/Android/data/com.metin2.client.lab/files/
adb shell cat /sdcard/Android/data/com.metin2.client.lab/files/syserr.txt
adb logcat -d > metin2-android-logcat.txt

Das Basispaket heißt com.metin2.client, das Upstream-Offline-Profil com.metin2.client.offline. Die Verzeichnisse sind verschieden. Die App verwendet getExternalFilesDir(null), also prüfe den tatsächlichen App-Pfad auf dem Gerät. Kontrolliere bei Updateproblemen zuerst ABI, Paket-ID und APK-Signatur. Eine unüberlegte Deinstallation kann Offline-Charaktere löschen.

Symptom Zuerst prüfen
CMake findet OpenGr2ndma nicht Initialisiertes Submodul und festgelegten Commit prüfen
APK passt nicht zur ABI ro.product.cpu.abilist mit -Pm2abi vergleichen
Verbindung direkt nach Login getrennt Handshake-Version des Servers, danach Logs
Rückkehr nach Charakterwahl Weitergeleitete IP, BIND_IP und alle Core-Ports
Fehlende UI oder schwarzer Bildschirm Staging, Protos, Python Lib und syserr.txt
Alte Daten nach Update Höhere m2.dataVersion, richtiges Profil und ZIP

Den vollständigen Server in die APK integrieren

Das Upstream-Profil bundled baut Android-Serverprozesse, verwendet eine SQLite-Schicht statt MySQL und packt Serverdaten zusammen mit dem Client ein. Das Smartphone braucht dann keinen entfernten Server. Dafür ist ein eigener Build samt Datenpaket nötig; es geschieht nicht automatisch mit der APK aus Schritt 3.

Ersetze für den Offline-Modus zunächst servers/servers.json durch diesen lokalen Katalog:

{
  "version": 2,
  "servers": [
    { "name": "Single Player", "embedded": true }
  ]
}

Andernfalls bleibt nach den vorherigen LAN-Schritten nur der entfernte Home Lab-Eintrag sichtbar. Setze in profiles/bundled.properties m2.serverListUrl=, m2.devUrl= und m2.updateChannel= leer. Behalte m2.serverMode=embedded, m2.dataBundled=true und das Suffix .offline bei. Erhöhe m2.dataVersion für ein neues Datenpaket. Mit vorbereitetem Source- und Runtime-Checkout verwendest du:

"$M2_REPO/r10dev.net OPENGL-ITJA/server/tools/make-server-pack.sh" \
  "$HOME/metin2-lab/m2srv" \
  "$HOME/metin2-lab/m2dev-server-src" \
  "$HOME/metin2-lab/server-pack"

M2_SERVER_PACK="$HOME/metin2-lab/server-pack" \
M2_CLIENT_DATA="$M2_STAGE" M2_PYLIB="$M2_PYLIB" \
M2_BUNDLE_OUT="$HOME/metin2-lab/bundle" GRADLE="$GRADLE" \
  "$M2_ANDROID/tools/make_bundle.sh" bundled 1

Prüfe vorher bundled.properties, deinen Katalog, dataVersion und den Testaccount in der Seed-Datenbank. make-server-pack.sh erwartet Runtime-Checkout, Source-Checkout und Ausgabeverzeichnis in dieser Reihenfolge. Übernimm nicht das abweichende Beispiel aus dem Webabschnitt der Upstream-Dokumentation. Der Gradle-Task für den eingebetteten Server verwendet Linux-spezifische NDK-Pfade; ein Windows-Offline-Build wurde hier nicht geprüft.

Ein erfolgreicher Build, ein gestartetes Spiel, ein Login und längeres Spielen sind verschiedene Ergebnisse. Prüfe selbst, ob du einen Charakter erstellen, eine Karte betreten, kämpfen, zwischen Cores wechseln und nach einem Neustart das gespeicherte Inventar wiederfinden kannst. Ohne diese Prüfungen gilt keine konkrete Smartphone-/Server-Kombination als verifiziert.

Häufig gestellte Fragen

Verbindet sich dieser Client mit meinem bevorzugten Privatserver?

Nur wenn der Betreiber ein kompatibles Protokoll und passende Daten unterstützt und diesen Client zulässt. Diese Anleitung behandelt die genannte Cemre/m2dev-Kombination, nicht Server mit eigenen Änderungen. Die APK ersetzt nicht universell deren Launcher.

Ist dies auch eine Anleitung für das iPhone?

Nein. Das beschriebene Projekt und die Werkzeuge zielen auf Android. Eine iOS-Erwähnung in einem anderen Entwicklungsbeitrag bestätigt keine iOS-Version dieses Clients.

Darf ich die APK samt Spieldaten öffentlich teilen?

Öffentlicher Quellcode oder die Lizenz einer Bibliothek klärt nicht die Rechte am gesamten Client oder den ursprünglichen Spieldaten. Vor einer Weitergabe musst du die Berechtigung für jede enthaltene Komponente klären. Dieser Artikel erteilt keine solchen Rechte.

Verwandte Seiten

Finde deinen perfekten Server

Durchsuche die bestbewerteten Metin2 Privatserver auf METIN2.GG oder trage deinen eigenen Server in die Rangliste ein.