Çözüldü mob takip ve reload regen sistemlerinin çakışması

  • Konuyu açan Konuyu açan TheAdmin33
  • Açılış Tarihi Açılış Tarihi
  • Yanıt Yanıt 10
  • Gösterim Gösterim 203
Bu konu çözüme ulaştırılmıştır. Çözüm için konuya yazılan tüm yorumları okumayı unutmayın. Eğer konudaki yorumlar sorununuzu çözmediyse yeni bir konu açabilirsiniz.
Durum
İçerik kilitlendiği için mesaj gönderimine kapatıldı.

TheAdmin33

Ah, bu şarkıların gözü kör olsun
Geliştirici
Yardımsever Üye
Usta Üye
Editör
Mesaj
1.408
Çözümler
76
Beğeni
5.637
Puan
2.859
Ticaret Puanı
0
@pasha37 nin paylaştığı ni ekledim bir de valian2 deki reload regen sistemini ekledim bu iki sistem çakışıyor ve core yememe sebep oluyor bu durumu nasıl düzeltebilirim?

hataya sebep olan kısım NotifyEnemyNPCs kısmı

C++:
Genişlet Daralt Kopyala
(gdb) bt
#0  0x0081e453 in std::__1::__tree_is_left_child[abi:se190107]<std::__1::__tree_node_base<void*>*>(std::__1::__tree_node_base<void*>*) (__x=0x2e50c950)
    at /usr/include/c++/v1/__tree:110
#1  std::__1::__tree_next_iter[abi:se190107]<std::__1::__tree_end_node<std::__1::__tree_node_base<void*>*>*, std::__1::__tree_node_base<void*>*>(std::__1::__tree_node_base<void*>*) (__x=0x2e50c950) at /usr/include/c++/v1/__tree:198
#2  std::__1::__tree_const_iterator<unsigned int, std::__1::__tree_node<unsigned int, void*>*, int>::operator++[abi:se190107]() (this=<optimized out>)
    at /usr/include/c++/v1/__tree:828
#3  CHARACTER::NotifyEnemyNPCs (this=0x2e50be00) at char.cpp:7498
#4  0x008afaa9 in CInputMain::Move (this=<optimized out>, ch=0x2e50be00,
    data=0x21d23b50 "\a") at input_main.cpp:1618
#5  0x008b2ac9 in CInputMain::Analyze (this=0x21cbcb78, d=0x21cbcb00,
    bHeader=7 '\a', c_pData=0x21d23b50 "\a") at input_main.cpp:3088
#6  0x008a39b9 in CInputProcessor::Process (this=0x21cbcb78, lpDesc=0x21cbcb00,
    c_pvOrig=0x21d23b40, iBytes=48, r_iBytesProceed=@0xffbfc2fc: 16)
    at input.cpp:94
#7  0x0087d685 in DESC::ProcessInput (this=0x21cbcb00) at desc.cpp:358
#8  0x009835e1 in io_loop (fdw=0x212c8ac0) at main.cpp:757
#9  0x009832e9 in idle () at main.cpp:675
#10 0x00982385 in main (argc=1, argv=0xffbfec04) at main.cpp:376
 
Son düzenleme:
Çözüm
C++:
Genişlet Daralt Kopyala
void CHARACTER::NotifyEnemyNPCs()
{
    if (m_set_dwEnemyNPCVID.empty())
        return;

    for (const auto& dwNPCVID : m_set_dwEnemyNPCVID)
    {
        LPCHARACTER pkNPC = CHARACTER_MANAGER::Instance().Find(dwNPCVID);
        if (pkNPC)
        {
            extern bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim);
            __CHARACTER_GotoNearTarget(pkNPC, this);
        }
        else // NPC looks like no more exists, remove it from cache list
        {
            RemoveEnemyNPC(dwNPCVID);
        }
    }
}
Hata şundan kaynaklı oluyor. container üzerinde silme sırasında iterator çakışması sonucu aynı anda npcyi bulamıyor ya da elamanları düzgün takip edemiyor.
Şu şekilde değiştirip...
Merhaba,
char.cpp:7498 satırı ve CHARACTER::NotifyEnemyNPCs() bu fonksiyonu paylaşırmısın.
 
Reload regen dediğin dracarysin new regen sistemi mi bossların sunucu saatine göre sabit sürelerde çıkması? Eğer oysa bu sistem olmasa da CORE veriyor o her türlü.
 
Merhaba,
char.cpp:7498 satırı ve CHARACTER::NotifyEnemyNPCs() bu fonksiyonu paylaşırmısın.
C++:
Genişlet Daralt Kopyala
void CHARACTER::NotifyEnemyNPCs()
{
    if (m_set_dwEnemyNPCVID.empty())
        return;

    for (const auto& dwNPCVID : m_set_dwEnemyNPCVID)
    {
        LPCHARACTER pkNPC = CHARACTER_MANAGER::Instance().Find(dwNPCVID);
        if (pkNPC)
        {
            extern bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim);
            __CHARACTER_GotoNearTarget(pkNPC, this);
        }
        else // NPC looks like no more exists, remove it from cache list
        {
            RemoveEnemyNPC(dwNPCVID);
        }
    }
}
 
C++:
Genişlet Daralt Kopyala
void CHARACTER::NotifyEnemyNPCs()
{
    if (m_set_dwEnemyNPCVID.empty())
        return;

    for (const auto& dwNPCVID : m_set_dwEnemyNPCVID)
    {
        LPCHARACTER pkNPC = CHARACTER_MANAGER::Instance().Find(dwNPCVID);
        if (pkNPC)
        {
            extern bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim);
            __CHARACTER_GotoNearTarget(pkNPC, this);
        }
        else // NPC looks like no more exists, remove it from cache list
        {
            RemoveEnemyNPC(dwNPCVID);
        }
    }
}
Hata şundan kaynaklı oluyor. container üzerinde silme sırasında iterator çakışması sonucu aynı anda npcyi bulamıyor ya da elamanları düzgün takip edemiyor.
Şu şekilde değiştirip denermisin.

C++:
Genişlet Daralt Kopyala
void CHARACTER::NotifyEnemyNPCs()
{
    if (m_set_dwEnemyNPCVID.empty())
        return;

    for (auto it = m_set_dwEnemyNPCVID.begin(); it != m_set_dwEnemyNPCVID.end();)
    {
        DWORD dwNPCVID = *it;
        LPCHARACTER pkNPC = CHARACTER_MANAGER::Instance().Find(dwNPCVID);

        if (pkNPC)
        {
            extern bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim);
            __CHARACTER_GotoNearTarget(pkNPC, this);
            ++it; // devam et
        }
        else
        {
            // NPC artık yoksa güvenli şekilde sil
            it = m_set_dwEnemyNPCVID.erase(it);
        }
    }
}
 
Çözüm
core içeriğinde bir sorun gözükmüyor, muhtemelen memory kaynaklı bir sorundan dolayı crash alıyorsun ve alakasız bir yeri gösteriyor. asan ile denersen asıl sorunu bulabilirsin.
 
Asan ile hata içeriğini nasıl bakarız acaba webde Metin2 için kurulum hakkında bilgi bulamadım

How to use ASAN with FreeBSD (Server):

If you can't link it successfully, because strlcpy is already linked from libmysqlclient.a, pick the libmysqlclient.a from mariadb instead of mysql8.If you use this setting, you are able to access the logs from /var/log/asan/. Each log will end with the .{process_id} so it's very convenient. You can enable ASAN on the VM as well. db + 1 channel will allocate less than 3GB of ram.


You can use ASAN on live server too. Nobody reported any lag because of ASAN.

How to install it:

1. Open Server/db/Makefile and add:

ENABLE_ASAN = 1


ifeq ($(ENABLE_ASAN), 1)


CFLAGS += -DENABLE_ASAN


CFLAGS += -fsanitize=address -fno-omit-frame-pointer CFLAGS += -fsanitize-recover=address


endif

2. Open Server/db/Main.cpp and add:
Kod:
Genişlet Daralt Kopyala
#if !defined(__WIN32__) && defined(ENABLE_ASAN)
const char* kAsanDefaultOptions = "external_symbolizer_path=\"/usr/bin/llvm-symbolizer\""
":verbosity=1"
":help=false"
":symbolize=true"
":detect_stack_use_after_return=true"
":log_path=\"/var/log/asan/asan.log.db\""
":debug=true"
":alloc_dealloc_mismatch=true"
":new_delete_type_mismatch=true"
":detect_invalid_pointer_pairs=3"
":detect_container_overflow=true"
":allocator_may_return_null=false"
":halt_on_error=false";
extern "C" __attribute__((no_sanitize_address)) const char *__asan_default_options()
{
return kAsanDefaultOptions;
}
#endif
3. Open Server/game/Makefile and add:

ENABLE_ASAN = 1


ifeq ($(ENABLE_ASAN), 1)


CFLAGS += -DENABLE_ASAN


CFLAGS += -fsanitize=address -fno-omit-frame-pointer CFLAGS += -fsanitize-recover=address


endif

4. Open Server/game/main.cpp and add:
Kod:
Genişlet Daralt Kopyala
#if !defined(__WIN32__) && defined(ENABLE_ASAN)
const char* kAsanDefaultOptions = "external_symbolizer_path=\"/usr/bin/llvm-symbolizer\""
":verbosity=1"
":help=false"
":symbolize=true"
":detect_stack_use_after_return=true"
":log_path=\"/var/log/asan/asan.log.game\""
":debug=true"
":alloc_dealloc_mismatch=true"
":new_delete_type_mismatch=true"
":detect_invalid_pointer_pairs=3"
":detect_container_overflow=true"
":allocator_may_return_null=false"
":halt_on_error=false";
extern "C" __attribute__((no_sanitize_address)) const char *__asan_default_options()
{
return kAsanDefaultOptions;
}
#endif
How to read the logs:

For each reported error, you have 3 sections


1. "AddressSanitizer: heap-use-after-free on address" This is where the dangling pointer has been used.


2. "freed by thread T0 here:" This is where the pointed memory has been previously deleted with delete/free.


3. "previously allocated by thread T0 here:" This is where the pointed memory has been allocated with new/malloc
 
Hata şundan kaynaklı oluyor. container üzerinde silme sırasında iterator çakışması sonucu aynı anda npcyi bulamıyor ya da elamanları düzgün takip edemiyor.
Şu şekilde değiştirip denermisin.

C++:
Genişlet Daralt Kopyala
void CHARACTER::NotifyEnemyNPCs()
{
    if (m_set_dwEnemyNPCVID.empty())
        return;

    for (auto it = m_set_dwEnemyNPCVID.begin(); it != m_set_dwEnemyNPCVID.end();)
    {
        DWORD dwNPCVID = *it;
        LPCHARACTER pkNPC = CHARACTER_MANAGER::Instance().Find(dwNPCVID);

        if (pkNPC)
        {
            extern bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim);
            __CHARACTER_GotoNearTarget(pkNPC, this);
            ++it; // devam et
        }
        else
        {
            // NPC artık yoksa güvenli şekilde sil
            it = m_set_dwEnemyNPCVID.erase(it);
        }
    }
}
Bu şekilde daha güvenli gibi duruyor diğer türlü listeyi gezerken siliyordu şuan eğer yoksa npc öyle siliyor en sonda yani doğru mu hocam
Hata şundan kaynaklı oluyor. container üzerinde silme sırasında iterator çakışması sonucu aynı anda npcyi bulamıyor ya da elamanları düzgün takip edemiyor.
Şu şekilde değiştirip denermisin.

C++:
Genişlet Daralt Kopyala
void CHARACTER::NotifyEnemyNPCs()
{
    if (m_set_dwEnemyNPCVID.empty())
        return;

    for (auto it = m_set_dwEnemyNPCVID.begin(); it != m_set_dwEnemyNPCVID.end();)
    {
        DWORD dwNPCVID = *it;
        LPCHARACTER pkNPC = CHARACTER_MANAGER::Instance().Find(dwNPCVID);

        if (pkNPC)
        {
            extern bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim);
            __CHARACTER_GotoNearTarget(pkNPC, this);
            ++it; // devam et
        }
        else
        {
            // NPC artık yoksa güvenli şekilde sil
            it = m_set_dwEnemyNPCVID.erase(it);
        }
    }
}
Bu şekilde daha güvenli gibi duruyor diğer türlü listeyi üzerindeyken siliyordu şuan eğer yoksa npc öyle siliyor en sonda yani doğru mu hocam
 
Bu şekilde daha güvenli gibi duruyor diğer türlü listeyi gezerken siliyordu şuan eğer yoksa npc öyle siliyor en sonda yani doğru mu hocam

Bu şekilde daha güvenli gibi duruyor diğer türlü listeyi üzerindeyken siliyordu şuan eğer yoksa npc öyle siliyor en sonda yani doğru mu hocam
Kesinlikle eleman silmeyi daha güvenli hale getirdik.

Kod:
Genişlet Daralt Kopyala
for (const auto& dwNPCVID : m_set_dwEnemyNPCVID)
{
    ...
    else
    {
        RemoveEnemyNPC(dwNPCVID); // ❌ Bu sırada döngü yapılan container değiştiriliyor
    }
}

Gdb çıktısına göre hatanın tam kaynağı burası.
for (const auto& … : m_set_dwEnemyNPCVID)
yani range-based for loop, içeride m_set_dwEnemyNPCVID’den eleman silindiği anda iterator invalidation oluşturuyor.
 
Hata şundan kaynaklı oluyor. container üzerinde silme sırasında iterator çakışması sonucu aynı anda npcyi bulamıyor ya da elamanları düzgün takip edemiyor.
Şu şekilde değiştirip denermisin.

C++:
Genişlet Daralt Kopyala
void CHARACTER::NotifyEnemyNPCs()
{
    if (m_set_dwEnemyNPCVID.empty())
        return;

    for (auto it = m_set_dwEnemyNPCVID.begin(); it != m_set_dwEnemyNPCVID.end();)
    {
        DWORD dwNPCVID = *it;
        LPCHARACTER pkNPC = CHARACTER_MANAGER::Instance().Find(dwNPCVID);

        if (pkNPC)
        {
            extern bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim);
            __CHARACTER_GotoNearTarget(pkNPC, this);
            ++it; // devam et
        }
        else
        {
            // NPC artık yoksa güvenli şekilde sil
            it = m_set_dwEnemyNPCVID.erase(it);
        }
    }
}
chatcpt ye sorduğumda bu cevabı almıştım ve evet çalışıyor core vermez oluyor ama yinede @pasha37 ya sormak istemiştim, teşekkürler (y)
 
Durum
İçerik kilitlendiği için mesaj gönderimine kapatıldı.
Geri
Üst