İçeriğe geç
Türkiye'nin SRO tanıtım & topluluk platformu

Knight Online v19xx/v20xx Karakter Görünmeme & Region Görüntü Bugu Çözümü

Cevaplar0
Görüntüleme7
Ticaret Puanı
0
Katılım
8 Eyl 2026
Mesajlar
88
Tepkime puanı
1
Puanları
0
Mevcut Bakiye
2960 ₺
[C++ FIX] Knight Online v19xx/v20xx Karakter Görünmeme & Region Görüntü Bugu Çözümü
UserInOutForMe & RegionUserInOutForMe Paket Offset Senkronizasyon Düzeltmesi



Merhaba değerli forum sakinleri,

Knight Online v1960 ve benzeri sürümlerde (özel GameServer kaynak kodlarında) Moradon pazar alanı, Colony Zone veya savaş haritalarında sıkça karşılaşılan;
  • Oyuncuların birbirini görememesi / görünmez olması,
  • Gate (ışınlanma) sonrası etraftaki karakterlerin geç yüklenmesi veya hiç çizilmemesi,
  • Bölge (Region) sınırlarından geçerken anlık takılmalar ve client paket düşmeleri (drop),
sorunlarının temel kaynağı, sunucunun istemciye gönderdiği bölge güncelleme paketlerindeki **bayt offset (kaydırma) hatasıdır**.

Teknik Teşhis & Hatanın Nedeni' Alıntı:
RegionUserInOutForMe fonksiyonunda result(WIZ_REGIONCHANGE, uint8(1)) tanımlandığında paketin ilk 2 baytı opcode ve sub-opcode tarafından rezerve edilir. Ardından gelen 2 baytlık placeholder sayaç, paketin **2. indeksinden** başlar.
Orijinal kodda yer alan result.put(1, ...) komutu, sub-opcode'un üzerine veri yazarak paketin imzasını bozar. İstemci bozuk paketi okuyamadığı için çevredeki kullanıcıları render edemez.



Düzeltilmiş ve Optimize Edilmiş C++ Kodları

GameServerDlg.cpp
dosyanızı açarak mevcut fonksiyonları aşağıdaki hatasız ve optimize bloklar ile değiştiriniz:

C++:
void CGameServerDlg::UserInOutForMe(CUser *pSendUser)
{
    if (pSendUser == nullptr)
        return;

    Packet result(WIZ_REQ_USERIN);
    C3DMap* pMap = pSendUser->GetMap();
    ASSERT(pMap != nullptr);

    uint16 user_count = 0;
    result << uint16(0); // 2 bayt sayaç alanı ayrılıyor (Offset: 0)

    int16 rx = pSendUser->GetRegionX();
    int16 rz = pSendUser->GetRegionZ();

    foreach_region(x, z)
        GetRegionUserIn(pMap, rx + x, rz + z, result, user_count, pSendUser->GetEventRoom());

    // Sayacı paketin başlangıç noktasına (Offset 0) yazıyoruz
    result.put(0, uint16(user_count));

    // Kalabalık alanlarda bant genişliğini korumak için sıkıştırma kontrolü
    if (user_count < 100)
        pSendUser->Send(&result);
    else
        pSendUser->SendCompressed(&result);
}

void CGameServerDlg::RegionUserInOutForMe(CUser *pSendUser)
{
    if (pSendUser == nullptr)
        return;

    // 1. ADIM: Bölge temizleme / sıfırlama bildirimi (Küçük paketlerde SendCompressed KULLANMAYINIZ)
    Packet Ref(WIZ_REGIONCHANGE, uint8(0));
    pSendUser->Send(&Ref);

    // 2. ADIM: Çevredeki kullanıcı listesini toplama
    Packet result(WIZ_REGIONCHANGE, uint8(1));
    C3DMap* pMap = pSendUser->GetMap();
    ASSERT(pMap != nullptr);

    uint16 user_count = 0;
    result << uint16(0); // WIZ_REGIONCHANGE (1 byte) + SubOpcode 1 (1 byte) = Sayaç 2. bayttan başlar!

    int16 rx = pSendUser->GetRegionX();
    int16 rz = pSendUser->GetRegionZ();

    foreach_region(x, z)
        GetRegionUserList(pMap, rx + x, rz + z, result, user_count, pSendUser->GetEventRoom());

    // KRİTİK FİX: Offset 1 değil, kesinlikle 2 olmalıdır!
    result.put(2, uint16(user_count));

    if (user_count < 100)
        pSendUser->Send(&result);
    else
        pSendUser->SendCompressed(&result);

    // 3. ADIM: Bölge güncelleme tamamlandı bildirimi
    Packet IP(WIZ_REGIONCHANGE, uint8(2));
    pSendUser->Send(&IP);
}



Yapılan Kritik Değişiklikler Nelerdir?

  1. Offset İndeks Düzeltmesi (result.put(2, ...)): result.put(1, ...) hatası giderilerek sayaç doğru bellek adresine yazıldı; böylece istemci gelen oyuncu sayısını eksiksiz okur.
  2. Gereksiz Sıkıştırma Kaldırıldı: Yalnızca 2 bayttan oluşan `Ref` ve `IP` paketleri doğrudan Send() ile iletilerek CPU yükü ve LZF paket başlığı kirliliği engellendi.
  3. Sıkıştırma Eşiği İyileştirildi: Sıkıştırma limiti 500'den 100'e çekildi. 100+ oyuncunun olduğu kalabalık bölgelerde paket boyutu küçültülerek istemciye iletim hızı artırıldı.



Nasıl Uygulanır?

  1. GameServer projenizi Visual Studio ile açın.
  2. GameServerDlg.cpp içerisindeki ilgili iki fonksiyonu yukarıdaki kod ile güncelleyin.
  3. GameServer projenizi Release modunda yeniden derleyin (Rebuild Solution).
  4. Yeni GameServer.exe ile sunucunuzu başlatıp kalabalık haritalarda test edin.

Sorularınızı ve takıldığınız yerleri bu konu altından iletebilirsiniz. Herkese iyi geliştirmeler!
 

Konuyu görüntüleyenler

Yükleniyor...
Yükleniyor...
Şu anda sitemizde 40,472 Aktif Kullanıcı
Çevrimiçi üyeler
Konular 1,311
Mesajlar 4,191
Kullanıcılar 1,624
Son üye mrt
Geri
Üst