Yardım game.core hatası

  • Konuyu açan Konuyu açan brave
  • Açılış Tarihi Açılış Tarihi
  • Yanıt Yanıt 13
  • Gösterim Gösterim 314
Konu sahibi bu konuda soru soruyor. Sorusu ile ilgili bilgisi olanların yanıtlamasını bekliyor.

brave

Üye
Üye
Mesaj
154
Çözümler
5
Beğeni
35
Puan
479
Ticaret Puanı
0
Anlam veremediğim şekilde sürekli bu şekilde core hatası alıyorum. ClearItem'a bu sefer 187. slot olarak gelmiş hata bazen 201 geldiğide oluyor. ClearItem ve DestroyItem fonksiyonlarında herhangi bir değişiklik yapmadım. Sorunun çözümü hakkında yardımcı olabilecek biri var mı?

1767700626893.webp





item_manager.cpp:
Genişlet Daralt Kopyala
void ITEM_MANAGER::DestroyItem(LPITEM item)
{
    if (item->GetSectree())
        item->RemoveFromGround();

    if (item->GetOwner())
    {
        if (CHARACTER_MANAGER::instance().Find(item->GetOwner()->GetPlayerID()) != NULL)
        {
            sys_err("DestroyItem: GetOwner %s %s!!", item->GetName(), item->GetOwner()->GetName());
            item->RemoveFromCharacter();
        }
        else
        {
            sys_err ("WTH! Invalid item owner. owner pointer : %p", item->GetOwner());
        }
    }

    TR1_NS::unordered_set<LPITEM>::iterator it = m_set_pkItemForDelayedSave.find(item);

    if (it != m_set_pkItemForDelayedSave.end())
        m_set_pkItemForDelayedSave.erase(it);

    DWORD dwID = item->GetID();
    sys_log(2, "ITEM_DESTROY %s:%u", item->GetName(), dwID);

    if (!item->GetSkipSave() && dwID)
    {
        DWORD dwOwnerID = item->GetLastOwnerPID();

        db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_DESTROY, 0, sizeof(DWORD) + sizeof(DWORD));
        db_clientdesc->Packet(&dwID, sizeof(DWORD));
        db_clientdesc->Packet(&dwOwnerID, sizeof(DWORD));
    }
    else
    {
        sys_log(2, "ITEM_DESTROY_SKIP %s:%u (skip=%d)", item->GetName(), dwID, item->GetSkipSave());
    }

    if (dwID)
        m_map_pkItemByID.erase(dwID);

    m_VIDMap.erase(item->GetVID());

    M2_DELETE(item);
}

char_item.cpp:
Genişlet Daralt Kopyala
void CHARACTER::ClearItem()
{
    int        i;
    LPITEM    item;

    for (i = 0; i < INVENTORY_AND_EQUIP_SLOT_MAX; ++i)
    {
        if ((item = GetInventoryItem(i)))
        {
            item->SetSkipSave(true);
            ITEM_MANAGER::instance().FlushDelayedSave(item);

            item->RemoveFromCharacter();
            M2_DESTROY_ITEM(item);

            SyncQuickslot(QUICKSLOT_TYPE_ITEM, i, 255);
        }
    }
    for (i = 0; i < DRAGON_SOUL_INVENTORY_MAX_NUM; ++i)
    {
        if ((item = GetItem(TItemPos(DRAGON_SOUL_INVENTORY, i))))
        {
            item->SetSkipSave(true);
            ITEM_MANAGER::instance().FlushDelayedSave(item);

            item->RemoveFromCharacter();
            M2_DESTROY_ITEM(item);
        }
    }
#ifdef ENABLE_SPECIAL_STORAGE
    for (i = 0; i < SPECIAL_INVENTORY_MAX_NUM; ++i)
    {
        if ((item = GetItem(TItemPos(UPGRADE_INVENTORY, i))))
        {
            item->SetSkipSave(true);
            ITEM_MANAGER::instance().FlushDelayedSave(item);
            item->RemoveFromCharacter();
            M2_DESTROY_ITEM(item);
        }
    }
    for (i = 0; i < SPECIAL_INVENTORY_MAX_NUM; ++i)
    {
        if ((item = GetItem(TItemPos(BOOK_INVENTORY, i))))
        {
            item->SetSkipSave(true);
            ITEM_MANAGER::instance().FlushDelayedSave(item);
            item->RemoveFromCharacter();
            M2_DESTROY_ITEM(item);
        }
    }
    for (i = 0; i < SPECIAL_INVENTORY_MAX_NUM; ++i)
    {
        if ((item = GetItem(TItemPos(STONE_INVENTORY, i))))
        {
            item->SetSkipSave(true);
            ITEM_MANAGER::instance().FlushDelayedSave(item);
            item->RemoveFromCharacter();
            M2_DESTROY_ITEM(item);
        }
    }
    
    for (i = 0; i < SPECIAL_INVENTORY_MAX_NUM; ++i)
    {
        if ((item = GetItem(TItemPos(CHEST_INVENTORY, i))))
        {
            item->SetSkipSave(true);
            ITEM_MANAGER::instance().FlushDelayedSave(item);
            item->RemoveFromCharacter();
            M2_DESTROY_ITEM(item);
        }
    }
#endif
#ifdef ENABLE_SWITCHBOT
    for (i = 0; i < SWITCHBOT_SLOT_COUNT; ++i)
    {
        if ((item = GetItem(TItemPos(SWITCHBOT, i))))
        {
            item->SetSkipSave(true);
            ITEM_MANAGER::instance().FlushDelayedSave(item);
            item->RemoveFromCharacter();
            M2_DESTROY_ITEM(item);
        }
    }
#endif
}
 

Kök sebep genelde şunlardan biri olur​

  • Karakter silinirken (disconnect/map change) üzerindeki item’ların owner’ı düzgün temizlenmiyor (item-&gt;SetOwner(NULL) / item detach eksik).
  • DestroyItem bazı edge-case’lerde iki kez çağrılıyor (özellikle remove + destroy akışlarında).
  • Item char’dan düşerken/taşınırken owner/sectree geçişleri tutarsız.
İstersen şu soruyu da hızlıca çözebiliriz: Log’da gördüğün “Invalid item owner” anında item’in window’u (inventory/equip/safebox) ve “RemoveFromCharacter” çağrı zinciri nereden geliyor? O callstack’i veya ilgili log satırlarını atarsan, owner’ın neden dangling kaldığını nokta atışı buluruz.
 

Kök sebep genelde şunlardan biri olur​

  • Karakter silinirken (disconnect/map change) üzerindeki item’ların owner’ı düzgün temizlenmiyor (item-&gt;SetOwner(NULL) / item detach eksik).
  • DestroyItem bazı edge-case’lerde iki kez çağrılıyor (özellikle remove + destroy akışlarında).
  • Item char’dan düşerken/taşınırken owner/sectree geçişleri tutarsız.
İstersen şu soruyu da hızlıca çözebiliriz: Log’da gördüğün “Invalid item owner” anında item’in window’u (inventory/equip/safebox) ve “RemoveFromCharacter” çağrı zinciri nereden geliyor? O callstack’i veya ilgili log satırlarını atarsan, owner’ın neden dangling kaldığını nokta atışı buluruz.

Yanıtınız için teşekkür ederim incelemem sonucu "Invalid item owner" logu düşmemiş. Kendim core yedirmeye çalışıyorum özellikle takılan süreli itemlerin bitiş anında (oyun onu sildirdiğinde vs) ışınlanma, oyundan çıkış gibi ama kendim yediremedim.
 
Yanıtınız için teşekkür ederim incelemem sonucu "Invalid item owner" logu düşmemiş. Kendim core yedirmeye çalışıyorum özellikle takılan süreli itemlerin bitiş anında (oyun onu sildirdiğinde vs) ışınlanma, oyundan çıkış gibi ama kendim yediremedim.
Item olduğundan eminsen, şöyle bir örnek vereyim.
Oyuncu çevrimdışıyken itemin süresi bittiğinde, oyuncu tekrar giriş yaptığında core atıyor. sen oyunda iken o anı yakalama ihtimalin çok düşük.


Bunu bi Denermisin ?

item.cpp:
Genişlet Daralt Kopyala
bool CItem::OnAfterCreatedItem()
{
    // 아이템을 한 번이라도 사용했다면, 그 이후엔 사용 중이지 않아도 시간이 차감되는 방식
    if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex)
    {
        // Socket1에 아이템의 사용 횟수가 기록되어 있으니, 한 번이라도 사용한 아이템은 타이머를 시작한다.
        if (0 != GetSocket(1))
        {
            // Check if item has already expired before starting the event
            const time_t current = get_global_time();
            if (current > GetSocket(0))
            {
                // Item has already expired while player was offline
                // Remove it immediately to prevent crash during login
                ITEM_MANAGER::instance().RemoveItem(this, "REAL_TIME_EXPIRE (expired offline)");
                return false;
            }

            StartRealTimeExpireEvent();
        }
    }

    return true;
}
 
RemoveFromCharacter() sadece DestroyItem() içinde çağrılmalı

sebep olan kod satırları ; ClearItem() + DestroyItem() içinde x2 RemoveFromCharacter()

- ek olarak paylaştığın kodda Find(owner) gibi kontroller bence çok riskli ve destroy sorumluluğu tek bir yerde olmalı
- M2_DESTROY_ITEM macrosu sadece ITEM_MANAGER::DestroyItem çağırmalı



@Sys arkadaşın yaklaşımı doğru fakat yine başka yerden core yedirtir bence şu kod satırı hatalı ;
ITEM_MANAGER::instance().RemoveItem(this, "REAL_TIME_EXPIRE (expired offline)");
 
Son düzenleme:
Item olduğundan eminsen, şöyle bir örnek vereyim.
Oyuncu çevrimdışıyken itemin süresi bittiğinde, oyuncu tekrar giriş yaptığında core atıyor. sen oyunda iken o anı yakalama ihtimalin çok düşük.


Bunu bi Denermisin ?

item.cpp:
Genişlet Daralt Kopyala
bool CItem::OnAfterCreatedItem()
{
    // 아이템을 한 번이라도 사용했다면, 그 이후엔 사용 중이지 않아도 시간이 차감되는 방식
    if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex)
    {
        // Socket1에 아이템의 사용 횟수가 기록되어 있으니, 한 번이라도 사용한 아이템은 타이머를 시작한다.
        if (0 != GetSocket(1))
        {
            // Check if item has already expired before starting the event
            const time_t current = get_global_time();
            if (current > GetSocket(0))
            {
                // Item has already expired while player was offline
                // Remove it immediately to prevent crash during login
                ITEM_MANAGER::instance().RemoveItem(this, "REAL_TIME_EXPIRE (expired offline)");
                return false;
            }

            StartRealTimeExpireEvent();
        }
    }

    return true;
}

item süresini 1 dakika yaparak denedim oyundan çıkıp fakat manuel core vermedi. OnAfterCreatedItem fonksiyonunu birçok kaynak kodunda kontrol ettim hepsi benimkiyle aynı orjinal haldeler.

RemoveFromCharacter() sadece DestroyItem() içinde çağrılmalı

sebep olan kod satırları ; ClearItem() + DestroyItem() içinde x2 RemoveFromCharacter()

- ek olarak paylaştığın kodda Find(owner) gibi kontroller bence çok riskli ve destroy sorumluluğu tek bir yerde olmalı
- M2_DESTROY_ITEM macrosu sadece ITEM_MANAGER::DestroyItem çağırmalı



@Sys arkadaşın yaklaşımı doğru fakat yine başka yerden core yedirtir bence şu kod satırı hatalı ;
ITEM_MANAGER::instance().RemoveItem(this, "REAL_TIME_EXPIRE (expired offline)");

Aynı şekilde birçok kaynak kodunda clearitem ve destroyitem içinde RemoveFromCharacter bulunuyor. O kaynak kodlarında bu bir soruna neden olmuyorken bende neden oluyor olabilir
 
item süresini 1 dakika yaparak denedim oyundan çıkıp fakat manuel core vermedi. OnAfterCreatedItem fonksiyonunu birçok kaynak kodunda kontrol ettim hepsi benimkiyle aynı orjinal haldeler.



Aynı şekilde birçok kaynak kodunda clearitem ve destroyitem içinde RemoveFromCharacter bulunuyor. O kaynak kodlarında bu bir soruna neden olmuyorken bende neden oluyor olabilir

Walla böyle bir soruna sen nasıl denk geldin bilmiyorum ama bu güzel bir sorun :D tek tek bildiğim tecrübeleri anlatayım ;

bazı kaynak kodlarda RemoveFromCharacter çağrıları güvenli bir işleyişle işleniyor item önceden inventorye eklenmiş ve ownerler doğru set edilmiş , DestroyItem() çağrısı geldiğinde item->GetOwner() null değil özetle RemoveFromCharacter iki kez var her za,man patlamaz sadece UB oluştuğunda görünür

yani sorun sadece x2 çağrılması değil işleyiş sırasıyla alakalı o yüzden zaten destroy tek bir merkezde olmalı tek bir merkezde olursa daha güvenilir olur

sana denk gelmesinin sebebi zamanlama ile alakalı , ama söylediğim gibi şundan kesin eminim destroy u tek bir merkeze toplarsan gelecek açısından daha iyi olur , yapmazsan eğer ileride yine farklı yerlerden patlayacak


araştıracak arkadaşlar olursa ; Undefined Behavior c++ standartlarında bu kavramı araştırabilir
 
RemoveFromCharacter() sadece DestroyItem() içinde çağrılmalı

sebep olan kod satırları ; ClearItem() + DestroyItem() içinde x2 RemoveFromCharacter()

- ek olarak paylaştığın kodda Find(owner) gibi kontroller bence çok riskli ve destroy sorumluluğu tek bir yerde olmalı
- M2_DESTROY_ITEM macrosu sadece ITEM_MANAGER::DestroyItem çağırmalı



@Sys arkadaşın yaklaşımı doğru fakat yine başka yerden core yedirtir bence şu kod satırı hatalı ;
ITEM_MANAGER::instance().RemoveItem(this, "REAL_TIME_EXPIRE (expired offline)");
Büyük ihtimalle sorununu çözecektir RemoveItem item için tam kod bloğunu okumadınız galiba :D oldu ki çözmedi farklı bir yerde problem var address sanitizer ile bulunur :You_Rock_Emoticon:
 
Büyük ihtimalle sorununu çözecektir RemoveItem item için tam kod bloğunu okumadınız galiba :D oldu ki çözmedi farklı bir yerde problem var address sanitizer ile bulunur :You_Rock_Emoticon:

Yok yok okudum doğru yaklaşım fakat ilerleyen vakitlerde farklı satırlardan patlatacak bir satır riskli yani benim görüşüm öyle.

ITEM_MANAGER::instance().RemoveItem(this, "REAL_TIME_EXPIRE (expired offline)");

bu satır sorunlu ve riskli çünkü ; envanter içine item tam yerleşmemiş olabilir , item in silinmesi , ticaretten verilmesi vs vs başka kodlarda da bu item ile işlem yapılıyor olabilir gibi düşünebilirsin. Tam bu sırada işleyiş sırası mantığı devereye girer ve UB tekrardan oluşur ve saçma sapan yerlerden core yer.

O yüzden o kod ile sorunu çözsede ilerleyen vakitlerde destroyu tek bir merkeze almadığı sürece farklı yerlerden core yiyecek.


Edit : ClearItem'a bu sefer 187. slot olarak gelmiş hata bazen 201 geldiğide oluyor. demiş bu yukarıdaki dediğimi özetliyor yani oyunu az daha oynayacak olursa farklı satırlara farklı itemlere denk geldiğinde yine bummm :(
 
Son düzenleme:
Yok yok okudum doğru yaklaşım fakat ilerleyen vakitlerde farklı satırlardan patlatacak bir satır riskli yani benim görüşüm öyle.

ITEM_MANAGER::instance().RemoveItem(this, "REAL_TIME_EXPIRE (expired offline)");

bu satır sorunlu ve riskli çünkü ; envanter içine item tam yerleşmemiş olabilir , item in silinmesi , ticaretten verilmesi vs vs başka kodlarda da bu item ile işlem yapılıyor olabilir gibi düşünebilirsin. Tam bu sırada işleyiş sırası mantığı devereye girer ve UB tekrardan oluşur ve saçma sapan yerlerden core yer.

O yüzden o kod ile sorunu çözsede ilerleyen vakitlerde destroyu tek bir merkeze almadığı sürece farklı yerlerden core yiyecek.


Edit : ClearItem'a bu sefer 187. slot olarak gelmiş hata bazen 201 geldiğide oluyor. demiş bu yukarıdaki dediğimi özetliyor yani oyunu az daha oynayacak olursa farklı satırlara farklı itemlere denk geldiğinde yine bummm :(

Merkezileştirmekten kastınız nedir tam olarak onu anlamadım ama sadece clearitem'ın ve sadece destroyitem'ın çağırıldığı yer var bunları tek yerden çağırmaktan mı bahsediyorsunuz?
 
Merkezileştirmekten kastınız nedir tam olarak onu anlamadım ama sadece clearitem'ın ve sadece destroyitem'ın çağırıldığı yer var bunları tek yerden çağırmaktan mı bahsediyorsunuz?

evet onu yapabilirsin ve diğer fonksiyonlarda sadece referanslar temizlenmeli , tek bir fonksiyon içinde toplayabilirsin bu tarz UB sorunlarını genelde mutex ile çözmeye çalışıyorlar fakat bu bence çok yanlış sadece örnek ;

Kullanıcı itemi sürükler , item locklanır fakat kullanıcı 2. envanter veya pencere değişikliği sırasında lock u kaldırır(manipüle eder)

mutex güçlü bir araç fakat sadece bu yeterli değil (Kişisel görüşüm benim böyle, bu konuda çok tartışma var , yumurtamı tavuktan , tavukmu yumurtadan çıkar gibi, eşzamanlılık sorunu) ( eğer geleceği düşünüyorsan sağlam ve özenli kodlar istiyorsan, UB ve Mutex gibi kavramları araştırırsan işleyişi daha iyi kavrayabilirsin.)

yukarıdaki mevzuları araştırırsan çok faydasını görürsün , bir çok dupenin nasıl yapıldığına dair kafanda birşeyler şekillenir.

Bu sorun ufak bir kod değişikliği ile çözülebilecek bir şey değil örneğin bir çok sonitex offshop kullananlar offsohp açıldığında inventory deki itemler locklanıyor fakat 2. envantere geçiş yaptığınızda veya farklı pencere ile çok kolay manipüle edip lock u kaldırıp işleyiş mantığını bozabiliyorsun.

Kafanı karıştırmayayım, senin yapman gereken şey şu ;
RemoveFromCharacter() sadece DestroyItem() içinde çağrılmalı

sebep olan kod satırları ; ClearItem() + DestroyItem() içinde x2 RemoveFromCharacter()

- ek olarak paylaştığın kodda Find(owner) gibi kontroller bence çok riskli ve destroy sorumluluğu tek bir yerde olmalı
- M2_DESTROY_ITEM macrosu sadece ITEM_MANAGER::DestroyItem çağırmalı


Aşağısı senin sorunun için kafa karıştırmasın sadece benzerlik açısından kafanda birşey şekillenmesi açısından örnek olarak düşün.

Edit : lockun manipüle edildiğini ve daha sonra bu item ile herşey yapabildiğini düşün.

Benzer senaryo şu olurdu ;
 
Son düzenleme:
Daha önce başıma gelmişti . Biyolog sistemi varsa + k envanteri varsa +toplu sil sat varsa sorun bunlardan kaynaklı olabilir . Kullandığın bu sistemlerin kodlarını kontrol etmeni öneririm çünkü birini fixlesende bu sefer ilerleyen zamanda diğer sistemden patlatıcak
 
Geri
Üst