[Çözüm] Transmutation Ve Private Shop Search Sistemlerinde Oluşan Stack Sorunu Düzeltmesi

  • Konuyu açan Konuyu açan Caelnarae
  • Açılış Tarihi Açılış Tarihi
  • Yanıt Yanıt 2
  • Gösterim Gösterim 203

Caelnarae

Üye
Üye
Mesaj
2
Beğeni
3
Puan
40
Ticaret Puanı
0
Konu: Çözülemedi - Transmutation ve Private Shop Search sistemleri ile ilgili ufak bug

Problemin kaynağı:

Bug sunucu tarafında, CShop::BroadcastUpdateItem (source/server/game/src/shop.cpp) içerisinde yer alıyor:
TPacketGCShopUpdateItem pack2; // <- sıfırlanmıyor!

Özel dükkandan (ticaret aynası dahil) bir eşya satın alındığında, sunucu önce r_item.pkItem = NULL atamasını yapar ve ardından BroadcastUpdateItem(pos) fonksiyonunu çağırır. Bu fonksiyonun ilk koşul bloğu şu şekildedir:
if (m_pkPC && !m_itemVector[pos].pkItem)
pack2.item.vnum = 0; // sadece vnum sıfırlanıyor

Stack üzerindeki pack2 yapısı sıfırlanmadığı için dwTransmutationVnum dâhil olmak üzere diğer alanlarda çöp (garbage) bellek değerleri kalır. İstemci bu paketi SetItemData ile kopyalar ve uishop.py dosyasında shop.GetItemChangeLookVnum(idx) != 0 şartı sağlandığında ingame_convert_Mark.tga simgesini ekrana çizer. Pencereyi kapatıp açtığınızda ise SHOP_SUBHEADER_GC_START paketi doğru değerle (0) gönderilir ve simge kaybolur — bu da tam olarak yaşanan davranışı açıklar.

Çözümü:
shop.cpp dosyası içerisinde pack2 yapısını sıfırlayın:

C++:
Genişlet Daralt Kopyala
TPacketGCShopUpdateItem pack2;
memset(&pack2, 0, sizeof(pack2));

Aynı dosyadaki Start() fonksiyonu da halihazırda bu yaklaşımı kullanmaktadır. Bu işlem, satılan eşya slotundaki dwTransmutationVnum ve diğer tüm başlatılmamış alanları temizler. Hem normal dükkan hem de ticaret aynası üzerinden yapılan satın alımlar bu fonksiyon üzerinden geçtiği için her iki durum da çözüme kavuşur. İşlemi tamamlamak için game projesini yeniden derlemeniz yeterlidir.

Örnek:


C++:
Genişlet Daralt Kopyala
void CShop::BroadcastUpdateItem(BYTE pos)
{
    TPacketGCShop pack;
    TPacketGCShopUpdateItem pack2;
#if defined(ENABLE_TRANSMUTATION)
    memset(&pack2, 0, sizeof(pack2));
#endif

    TEMP_BUFFER    buf;

    pack.header        = HEADER_GC_SHOP;
    pack.subheader    = SHOP_SUBHEADER_GC_UPDATE_ITEM;
    pack.size        = sizeof(pack) + sizeof(pack2);

    pack2.pos        = pos;

    if (m_pkPC && !m_itemVector[pos].pkItem)
        pack2.item.vnum = 0;
    else
    {
        pack2.item.vnum    = m_itemVector[pos].vnum;
        if (m_itemVector[pos].pkItem)
        {
            thecore_memcpy(pack2.item.alSockets, m_itemVector[pos].pkItem->GetSockets(), sizeof(pack2.item.alSockets));
            thecore_memcpy(pack2.item.aAttr, m_itemVector[pos].pkItem->GetAttributes(), sizeof(pack2.item.aAttr));
#if defined(ENABLE_TRANSMUTATION)
            pack2.item.dwTransmutationVnum = m_itemVector[pos].pkItem->GetTransmutationVnum();
#endif
        }
        else
        {
            memset(pack2.item.alSockets, 0, sizeof(pack2.item.alSockets));
            memset(pack2.item.aAttr, 0, sizeof(pack2.item.aAttr));
#if defined(ENABLE_TRANSMUTATION)
            pack2.item.dwTransmutationVnum = 0;
#endif
        }
    }

    pack2.item.price    = m_itemVector[pos].price;
#ifdef ENABLE_CHEQUE_SYSTEM
    pack2.item.cheque = m_itemVector[pos].cheque;
#endif
    pack2.item.count    = m_itemVector[pos].count;

    buf.write(&pack, sizeof(pack));
    buf.write(&pack2, sizeof(pack2));

    Broadcast(buf.read_peek(), buf.size());
}
 
az önce dev'de gördüm bunu, oraya yazdığımı burayada yazayım;

Burada bir sorun var, ENABLE_TRANSMUTATION definesi yoksa pack2 için memset call olmayacak.

Zaten bu kadar memset call'a gerek yok. Brace initialization kullanın. "T x{}" value-initialization'dır, Metin2'de structlar POD ve aggregate tanımını sağladığı için nesne zero-initialize edilecektir. Velhasıl şöyle bir yaklaşım daha sağlıklı olabilir ileriye dönük:

C++:
Genişlet Daralt Kopyala
void CShop::BroadcastUpdateItem(BYTE pos)
{
    if (pos >= m_itemVector.size()) // why haven't they added this check? comments are really important.
    {
        sys_err("CShop::BroadcastUpdateItem: invalid pos %u (size %u)", pos, m_itemVector.size());
        return;
    }

    TPacketGCShop pack{};
    TPacketGCShopUpdateItem pack2{};
    TEMP_BUFFER buf;

    pack.header    = HEADER_GC_SHOP;
    pack.subheader = SHOP_SUBHEADER_GC_UPDATE_ITEM;
    pack.size      = sizeof(pack) + sizeof(pack2);

    pack2.pos = pos;

    const SHOP_ITEM& item = m_itemVector[pos];

    if (!(m_pkPC && !item.pkItem))
    {
        pack2.item.vnum = item.vnum;

        if (item.pkItem)
        {
            thecore_memcpy(pack2.item.alSockets, item.pkItem->GetSockets(), sizeof(pack2.item.alSockets));
            thecore_memcpy(pack2.item.aAttr, item.pkItem->GetAttributes(), sizeof(pack2.item.aAttr));
#if defined(ENABLE_TRANSMUTATION)
            pack2.item.dwTransmutationVnum = item.pkItem->GetTransmutationVnum();
#endif
        }
    }

    pack2.item.price = item.price;
#if defined(ENABLE_CHEQUE_SYSTEM)
    pack2.item.cheque = item.cheque;
#endif
    pack2.item.count = item.count;

    buf.write(&pack, sizeof(pack));
    buf.write(&pack2, sizeof(pack2));

    Broadcast(buf.read_peek(), buf.size());
}
 
az önce dev'de gördüm bunu, oraya yazdığımı burayada yazayım;

Burada bir sorun var, ENABLE_TRANSMUTATION definesi yoksa pack2 için memset call olmayacak.

Zaten bu kadar memset call'a gerek yok. Brace initialization kullanın. "T x{}" value-initialization'dır, Metin2'de structlar POD ve aggregate tanımını sağladığı için nesne zero-initialize edilecektir. Velhasıl şöyle bir yaklaşım daha sağlıklı olabilir ileriye dönük:

C++:
Genişlet Daralt Kopyala
void CShop::BroadcastUpdateItem(BYTE pos)
{
    if (pos >= m_itemVector.size()) // why haven't they added this check? comments are really important.
    {
        sys_err("CShop::BroadcastUpdateItem: invalid pos %u (size %u)", pos, m_itemVector.size());
        return;
    }

    TPacketGCShop pack{};
    TPacketGCShopUpdateItem pack2{};
    TEMP_BUFFER buf;

    pack.header    = HEADER_GC_SHOP;
    pack.subheader = SHOP_SUBHEADER_GC_UPDATE_ITEM;
    pack.size      = sizeof(pack) + sizeof(pack2);

    pack2.pos = pos;

    const SHOP_ITEM& item = m_itemVector[pos];

    if (!(m_pkPC && !item.pkItem))
    {
        pack2.item.vnum = item.vnum;

        if (item.pkItem)
        {
            thecore_memcpy(pack2.item.alSockets, item.pkItem->GetSockets(), sizeof(pack2.item.alSockets));
            thecore_memcpy(pack2.item.aAttr, item.pkItem->GetAttributes(), sizeof(pack2.item.aAttr));
#if defined(ENABLE_TRANSMUTATION)
            pack2.item.dwTransmutationVnum = item.pkItem->GetTransmutationVnum();
#endif
        }
    }

    pack2.item.price = item.price;
#if defined(ENABLE_CHEQUE_SYSTEM)
    pack2.item.cheque = item.cheque;
#endif
    pack2.item.count = item.count;

    buf.write(&pack, sizeof(pack));
    buf.write(&pack2, sizeof(pack2));

    Broadcast(buf.read_peek(), buf.size());
}
Şimdi tam bunu diyecektim. Ellerine sağlık.
 
Geri
Üst