Metin2 Source Yapısı: game, db ve Client Modülleri
Hazırlayan: Metin2VIP Editörleri Yayın: 9 dk okuma
İçindekiler
- Sunucu süreçleri birbiriyle nasıl konuşur?
- Sunucu klasörleri: hangi modül ne yapar?
- game/src içinde ne nerede?
- Bir paket sunucuda nasıl işlenir?
- Ana döngü: saniyede 25 nabız
- db/src içinde ne nerede?
- İstemci tarafı: UserInterface ve 15 kütüphane
- İstemcide C++ ile Python nasıl konuşur?
- Bir özelliği kaynakta nerede ararsın?
Metin2 server kaynağı iki programdan oluşur: oyunun kendisini yürüten game ve oyuncu verisini önbellekte tutup MySQL'e yazan db. Giriş sunucusu (auth) ayrı bir program değildir; CONFIG dosyasında AUTH_SERVER satırı bulunan bir game sürecidir. İki program common klasöründeki ortak başlıkları ve beş küçük kütüphaneyi (libthecore, libsql, libgame, libpoly, liblua) paylaşır. Client tarafında exe'yi UserInterface projesi üretir; grafik, harita, ses, paket ve Python bağlantısı 15 ayrı kütüphanededir.
Aşağıdaki harita, kaynak paketindeki Source/Serversrc/Server ve Source/Clientsrc/Client klasörlerine dayanır. Bu kaynak, Ymir'in orijinal kodu üzerine topluluk düzeltmeleri eklenmiş bir sürümdür; isteğe bağlı sistemler service.h ve Locale_inc.h bayraklarıyla açılıp kapanır. Derleme adımları Metin2 source derleme yazısında.
Sunucu süreçleri birbiriyle nasıl konuşur?
Bağlantıların hepsi TCP'dir; bu kaynakta __UDP_BLOCK__ bayrağı yüzünden çekirdeğin UDP soketi hiç açılmaz. Her paketin ilk baytı türünü söyleyen bir başlıktır ve başlıkların adı kimin kime konuştuğunu gösterir:
| Bağlantı | Başlık öneki | Ne taşır |
|---|---|---|
| İstemci → oyun çekirdeği ya da auth | HEADER_CG_ |
Oyuncunun istekleri: hareket, saldırı, sohbet, eşya kullanma (78 tür) |
| Oyun çekirdeği → istemci | HEADER_GC_ |
Görünen karakterler, eşyalar, puanlar, mesajlar (125 tür) |
| Oyun çekirdeği ↔ oyun çekirdeği | HEADER_GG_ |
P2P: oyuncunun hangi çekirdekte olduğu, fısıltı aktarımı, duyuru, bağırma, lonca, ışınlanma (29 tür) |
| Oyun çekirdeği ↔ db | HEADER_GD_, HEADER_DG_ |
Karakter yükleme ve kaydetme, protolar, lonca, evlilik gibi ortak veriler (105 ve 102 tür) |
db, oyuncu ve eşya kayıtlarının yüklendiği ve kaydedildiği yerdir. Açılışta item_proto, mob_proto, skill_proto, refine_proto, shop, item_attr, banword, land ve object tablolarını okur; bir oyun çekirdeği bağlandığında hepsini ona tek pakette gönderir. Karakter kaydı da db'ye gider ve önbellekte bekler; MySQL'e varsayılan olarak oyuncu verisi 7, eşya verisi 5 dakikada bir yazılır (conf.txt'deki PLAYER_CACHE_FLUSH_SECONDS ve ITEM_CACHE_FLUSH_SECONDS).
Oyun çekirdekleri MySQL'e tamamen db üzerinden bağlanmaz. CONFIG'deki COMMON_SQL bağlantısı locale tablosu gibi ortak ayarları okur, PLAYER_SQL lonca, arkadaş listesi ve quest fonksiyonları gibi yerlerde doğrudan sorgu çalıştırır, LOG_SQL günlük kayıtlarını yazar. auth'un PLAYER_SQL satırı ise account veritabanını gösterir; kullanıcı adı ve parola orada doğrulanır. Veritabanlarının içeriği Metin2 veritabanları, portların dağılımı Metin2 kanal ve portlar yazısında.
Sunucu klasörleri: hangi modül ne yapar?
| Klasör | Görevi |
|---|---|
common/ |
game ile db'nin ortak dili: sabitler ve sınırlar (length.h), eşya türleri ve yuvaları (item_length.h), game ile db arasındaki paket ve tablo yapıları (tables.h), özellik bayrakları (service.h) |
game/src/ |
Oyun çekirdeği. Klasördeki 173 .cpp dosyasının 169'u derlenir; test ile başlayan dördü derlemeye girmez |
db/src/ |
Veritabanı çekirdeği, 31 .cpp dosyası |
libthecore/ |
Çalışma zamanı: soketler, olay izleyici (FreeBSD'de kqueue, başka sistemlerde select), tamponlar, sinyaller, syslog ve syserr günlükleri, nabız döngüsü, TEA, DES ve GOST şifreleri, Korece metin yardımcıları |
libsql/ |
MySQL sorgularını ayrı bir iş parçacığında çalıştıran asenkron katman |
libgame/ |
Harita hücre nitelikleri (CAttribute), depo, ticaret penceresi ve market ızgarası (CGrid), TGA okuyucu |
libpoly/ |
Formül çözücü: skill_proto'daki atk, k, lv gibi değişkenli formülleri hesaplar |
liblua/ |
Lua 5.0.3; quest motoru bunun üstünde çalışır. 5.2 klasörü varsayılan derlemede kullanılmaz |
common başlıkları iki programın arasındaki sözleşmedir. Buradaki bir yapıyı ya da bayrağı değiştirmek game ile db'nin birlikte yeniden derlenmesini, değişiklik istemciye giden bir paketi etkiliyorsa istemcinin de güncellenmesini gerektirir.
game/src içinde ne nerede?
| Konu | Dosyalar |
|---|---|
| Ağ ve oturum | desc*.cpp (bağlantılar), input*.cpp (paket işleyicileri), packet.h, packet_info.cpp, p2p.cpp |
| Karakter | char.cpp, char_*.cpp (eşya, etki, at, durum), char_manager.cpp |
| Savaş | battle.cpp, char_battle.cpp, pvp.cpp |
| Beceri | char_skill.cpp, skill.cpp, skill_power.cpp |
| Eşya | item.cpp, item_attribute.cpp, item_manager*.cpp, refine.cpp, cube.cpp, blend_item.cpp, DragonSoul.cpp |
| Harita ve canavarlar | sectree*.cpp, regen.cpp, mob_manager.cpp, dungeon.cpp, map_location.cpp |
| Quest | questmanager.cpp, questlua*.cpp, questnpc.cpp, questpc.cpp |
| Sistemler | guild*.cpp, party.cpp, marriage.cpp, exchange.cpp, shop*.cpp, safebox.cpp, fishing.cpp, mining.cpp, horse_rider.cpp, PetSystem.cpp, OXEvent.cpp, monarch.cpp, threeway_war.cpp, DragonLair.cpp |
| Komutlar | cmd.cpp (komut tablosu ve yetki seviyeleri), cmd_general.cpp, cmd_gm.cpp, cmd_emotion.cpp |
| Ayar ve dil | config.cpp, locale_service.cpp, locale.cpp, constants.cpp |
| Veritabanı ve günlük | db.cpp, log.cpp, input_db.cpp |
| Ana döngü | main.cpp, event.cpp, event_queue.cpp |
Ülkeye göre değişen davranışlar LC_IsEurope(), LC_IsYMIR() gibi fonksiyonlarla seçilir. Hangisinin geçerli olduğunu common veritabanındaki LOCALE değeri belirler; bu pakette turkey'dir ve LC_IsEurope() doğru döner. Kaynak koddaki yorumlar ve oyuncuya giden metinlerin aslı Korecedir (cp949), düzenleyicide başka bir kod sayfasıyla açılınca bozuk görünür.
Bir paket sunucuda nasıl işlenir?
- libthecore'un olay izleyicisi soketi okunabilir bildirir, gelen baytlar bağlantının (DESC) tamponuna alınır.
CInputProcessor::Process(input.cpp) ilk bayttaki başlığa bakar ve paketin boyunupacket_info.cpp'deki tablodan bulur. Tanınmayan başlıktasyserr'e "UNKNOWN HEADER" yazılır ve bağlantı kapatılır.- Paketi bağlantının bulunduğu aşamanın işleyicisi alır: el sıkışmada
CInputHandshake, giriş, karakter seçimi ve yüklemedeCInputLogin, oyunda ve ölüykenCInputMain, auth'taCInputAuth. CInputMain::Analyze(input_main.cpp) başlığa göre ilgili fonksiyonu çağırır; oyun mantığı karakter nesnesinin (CHARACTER) yöntemlerinde yürür.- Sonuç istemciye
GCpaketi olarak gider. Kaydedilmesi gereken veri (karakter, eşya, lonca) db'yeGDpaketleriyle gider; db'nin cevaplarınıCInputDB::Analyze(input_db.cpp) işler.
Örnek: bir sohbet mesajının yolu
- Oyuncu mesajı yazıp Enter'a basar;
uichat.pymesajınet.SendChatPacketile gönderir ve istemciHEADER_CG_CHATpaketini kurar. - Çekirdekte paket
CInputMain::AnalyzeüzerindenCInputMain::Chat'e gelir. Chat, yasaklı kelimeleri banword listesiyle*yapar; bağırmada seviye ve bekleme süresi sınırlarını denetler.- Normal mesaj görüş alanındaki karakterlere
HEADER_GC_CHATolarak gider. Bağırma ayrıcaHEADER_GG_SHOUTile diğer çekirdeklere aktarılır. - Alan istemci paketi oyun aşamasının başlık listesinde tanır, kendi küfür süzgecinden geçirir ve sohbet penceresine yazar.
Ana döngü: saniyede 25 nabız
Oyun çekirdeği tek bir döngüde çalışır. libthecore döngüyü saniyede 25 nabızla kurar. Her nabızda zamanlanmış olaylar (event.cpp) işlenir; her saniye db'ye çekirdekteki oyuncu sayısı bildirilir, belli aralıklarla bekleyen karakter kayıtları ve eşya güncellemeleri yapılır. Nabızların arasında karakterler güncellenir, soketler okunup yazılır.
Oyun mantığının tamamı bu tek iş parçacığında döner; yalnız MySQL sorguları libsql'in ayrı iş parçacığında, döngüyü bekletmeden yürür. Kodda süreler bu yüzden saniye değil nabız cinsinden yazılır: PASSES_PER_SEC(5) 5 saniye, yani 125 nabız demektir. CONFIG'deki PASSES_PER_SEC satırının neden 25 kalması gerektiği CONFIG ayarları yazısında. db çekirdeğinin nabız sayısı ise conf.txt'deki CLIENT_HEART_FPS ile verilir.
db/src içinde ne nerede?
| Dosya | Görevi |
|---|---|
Main.cpp, Config.cpp |
Açılış, conf.txt okuma, MySQL bağlantıları |
ClientManager*.cpp |
Oyun çekirdeklerinden gelen isteklerin merkezi. ClientManagerBoot protoları ve tabloları yükler; Login, Player, Guild, Party, EventFlag, HorseName dosyaları kendi konularını işler |
Cache.cpp |
Oyuncu ve eşya önbelleği, MySQL'e gecikmeli yazma |
ProtoReader.cpp, CsvReader.cpp |
item_proto.txt ve mob_proto.txt okuyucuları |
GuildManager.cpp |
Lonca savaşları ve puanları |
PrivManager.cpp |
Krallık, lonca ve karakter bonusları (EXP, drop, Yang oranı) |
ItemAwardManager.cpp |
item_award tablosundan eşya verme |
Marriage.cpp, Monarch.cpp |
Evlilik ve kral sistemi verisi |
ItemIDRangeManager.cpp |
Her oyun çekirdeğine çakışmayan bir eşya numarası aralığı dağıtma |
HB.cpp |
hotbackup veritabanına yedek |
İstemci tarafı: UserInterface ve 15 kütüphane
| Modül | .cpp |
Görevi |
|---|---|---|
| UserInterface | 95 | Exe: açılış (UserInterface.cpp), ana döngü (PythonApplication.cpp), ağ aşamaları (PythonNetworkStream*.cpp, AccountConnector.cpp), karakter görünümü (InstanceBase*.cpp), oyuncunun durumu (PythonPlayer*.cpp), Python'a açılan modüller (Python*Module.cpp) |
| EterLib | 71 | Direct3D 8 aygıtı, doku ve yazı tipi, metin çizimi, IME, klavye ve fare girdisi, kamera, soket akışı, kaynak yöneticisi |
| GameLib | 59 | Harita ve arazi yükleme (MapOutdoor*.cpp), aktörler ve hareketleri (ActorInstance*.cpp), ırk verisi (.msm), eşya verisi (ItemData, ItemManager), oklar ve büyüler gibi uçan nesneler, harita nesneleri (Property) |
| EffectLib | 18 | .mse efektleri, parçacıklar, efekt modelleri |
| EterBase | 17 | Temel araçlar: CRC32, dosya eşleme, LZO, TEA, paket şifrelemesi, zamanlayıcı, syserr.txt günlüğü, çökme dökümü |
| EterGrnLib | 15 | Granny .gr2 modelleri, hareketleri ve ayrıntı düzeyi (LOD) |
| MilesLib | 11 | 2B ve 3B sesler, müzik akışı |
| EterPythonLib | 11 | Pencere sistemi (wndMgr), yuva pencereleri, çizim modülleri (grp) |
| SpeedTreeLib | 7 | .spt ağaçları ve çimen |
| EterPack | 6 | Paket dosyaları (.eix, .epk) |
| ScriptLib | 6 | Python yorumlayıcısını gömme (PythonLauncher), uzantıya göre kaynak türü (gr2, dds, tga, sub, mse...), hata ayıklama modülü |
| EterLocale | 5 | Kod sayfası dönüşümleri; Arapça, Japonca ve Vietnamca metin desteği |
| SphereLib | 4 | Görünürlük hesabı için küre ağacı ve görüş konisi |
| EterImageLib | 4 | DDS (DXT) ve TGA görüntü okuma |
| PRTerrainLib | 3 | Arazi ve doku setleri (TextureSet) |
| CWebBrowser | 1 | Oyun içi web penceresi (Windows'un tarayıcı bileşeni) |
UserInterface dışındaki projelerin hepsi statik kütüphanedir ve exe'ye gömülür. İstemcinin özellik bayrakları UserInterface/Locale_inc.h dosyasındadır; kütüphanelerin hemen hepsi bu dosyayı ön derlenmiş başlığına aldığı için bir bayrak bütün çözümü etkiler.
İstemcide C++ ile Python nasıl konuşur?
Exe açılırken Python 2.7 yorumlayıcısını başlatır ve ona 38 modül tanıtır: net (ağ), player (oyuncunun kendi durumu), chr ve chrmgr (karakterler), item, skill, nonplayer (canavar verisi), app (pencere ve uygulama), wndMgr ve grp (arayüz ve çizim), pack, snd, background, miniMap, quest, guild, shop, safebox, exchange, messenger, systemSetting ve diğerleri. root paketindeki .py dosyaları arayüzü bu modüllerle kurar; hangi pencerenin açılacağına, bir tuşun ne yapacağına Python tarafı karar verir.
Bilgi iki yönde akar. Bir betik net.SendChatPacket(metin, tür) gibi bir fonksiyon çağırdığında C++ paketi kurup gönderir. Sunucudan gelen paketi ise C++ çözer (PythonNetworkStreamPhaseGame.cpp içindeki başlık listesi), kendi durumunu günceller ve gerekirse oyun penceresindeki bir Python fonksiyonunu çağırır. Bu fonksiyonların adları BINARY_ ile başlar; game.py'de 38 tane vardır.
İstemcinin ağ tarafı sunucudaki aşamaların aynısını izler: çevrimdışı, el sıkışma, giriş, karakter seçimi, yükleme ve oyun. Her aşamanın işleyicisi ayrı bir dosyadadır (PythonNetworkStreamPhaseLogin.cpp, PythonNetworkStreamPhaseSelect.cpp, PythonNetworkStreamPhaseLoading.cpp, PythonNetworkStreamPhaseGame.cpp). Dosyalar paketlerden EterPack üzerinden okunur, her uzantı ScriptLib'deki tabloya göre doğru sınıfa (model, görüntü, efekt) verilir; paket biçimi Metin2 pack dosyaları, açılış sırası Metin2 client klasör yapısı yazısında.
Bir özelliği kaynakta nerede ararsın?
| Konu | Sunucu | İstemci |
|---|---|---|
| Hasar hesabı | battle.cpp, char_battle.cpp |
Hesaplamaz, sunucunun sayısını gösterir |
| Puanlar ve efsunların etkisi | char.cpp (ComputePoints, ApplyPoint), constants.cpp |
uitooltip.py (gösterim) |
| Beceriler | char_skill.cpp, skill.cpp |
PythonSkill.cpp, skilldesc.txt, skilltable.txt |
| Artı basma | char_item.cpp (DoRefine), refine.cpp |
uirefine.py |
| Efsun ekleme ve değiştirme | item_attribute.cpp |
uitooltip.py |
| Drop | item_manager.cpp, item_manager_read_tables.cpp |
Yok |
| Canavarların doğması | regen.cpp, sectree_manager.cpp |
Yok |
| Quest fonksiyonları | questlua_*.cpp (her dosya bir Lua tablosu: pc, item, npc, game...) |
uiquest.py (pencere) |
| GM komutları | cmd.cpp, cmd_gm.cpp, cmd_general.cpp |
Yok |
| CONFIG anahtarları | config.cpp |
Yok |
| item_proto okuma | db: ClientManagerBoot.cpp, ProtoReader.cpp |
ItemManager.cpp (istemci kopyası) |
| Giriş | input_auth.cpp, input_login.cpp |
AccountConnector.cpp, intrologin.py |
| Paket listesi | packet.h, packet_info.cpp |
Packet.h, PythonNetworkStream.cpp |
Hasarın oyuncu açısından nasıl hesaplandığı Metin2 hasar hesaplama, quest tablolarındaki fonksiyonların listesi Metin2 quest fonksiyonları yazısında. Komut tablosundaki yetki seviyeleriyle birlikte bütün komutlar GM komutları sayfasında toplanıyor.
Sık sorulan sorular
- Metin2 source'da hasar hesabı hangi dosyada?
- Sunucunun game/src klasöründe: saldırı ve savunma hesabı battle.cpp'de, hasarın hedefe uygulanması ve kritik ile delici vuruş char_battle.cpp'de. İstemci hasarı hesaplamaz, sunucunun bildirdiği sayıyı gösterir.
- auth ayrı bir program mı?
- Hayır. auth, CONFIG dosyasında AUTH_SERVER satırı bulunan bir game sürecidir. Aynı ikili dosya çalışır, yalnız giriş paketlerini işler ve kullanıcı adıyla parolayı account veritabanında doğrular.
- Quest fonksiyonları kaynakta nerede?
- game/src altındaki questlua_*.cpp dosyalarında. Her dosya bir Lua tablosunu kaydeder: questlua_pc.cpp pc.*, questlua_item.cpp item.*, questlua_npc.cpp npc.* fonksiyonlarını tanımlar.
- Client'taki Python dosyaları C++ koduna nasıl ulaşır?
- Exe, Python'a net, player, item, chr, app, wndMgr gibi 38 modül açar. root paketindeki betikler bu modüllerin fonksiyonlarını çağırır; sunucudan gelen paketler C++ tarafında çözülüp game.py'deki BINARY_ ile başlayan fonksiyonlara iletilir.
İlgili sayfalar
- Metin2 Client Klasör Yapısı: Hangi Dosya Ne İşe Yarar? (Server kurma)
- Metin2 CONFIG Ayarları: Game Çekirdeği Seçenekleri ve Anlamları (Server kurma)
- Metin2 Hasar Nasıl Hesaplanır? Saldırı, Savunma ve Bonusların Sırası (Wiki)
- Metin2 Kanal ve Port Yapısı: auth, ch1, ch99 ve P2P (Server kurma)
- Metin2 Pack Dosyaları: EPK ve EIX Nedir? (Server kurma)
Kategori: Server Kurma Kaynak Kod kaynak kod geliştirici db source game
Bu sayfadaki bilgiler Metin2'nin sunucu yazılımındaki hesaplamalara ve standart oyun dosyalarına dayanır. Oyun dosyalarını değiştiren sunucularda değerler farklı olabilir. İçerikleri nasıl hazırlıyoruz?